From e27d93f9407830cecd12afd82949b1d043ea1708 Mon Sep 17 00:00:00 2001 From: Brendan Hansen Date: Tue, 4 Jan 2022 21:20:16 -0600 Subject: [PATCH] started working on auto polymorphic functions --- core/container/iter.onyx | 2 +- core/container/map.onyx | 12 +++--- include/astnodes.h | 25 ++++++++++++ src/checker.c | 3 +- src/clone.c | 31 +++------------ src/entities.c | 6 +++ src/polymorph.h | 84 ++++++++++++++++++++++++++++++++++++++++ src/symres.c | 18 +++++---- 8 files changed, 139 insertions(+), 42 deletions(-) diff --git a/core/container/iter.onyx b/core/container/iter.onyx index 6c903827..1a8c575b 100644 --- a/core/container/iter.onyx +++ b/core/container/iter.onyx @@ -593,7 +593,7 @@ parallel_for :: #match {} if thread_count != 0 { dist := distributor(iter); - t_data := Thread_Data(T, Ctx).{ + t_data := Thread_Data(iter.Iter_Type, Ctx).{ iter = ^dist, data = thread_data, }; diff --git a/core/container/map.onyx b/core/container/map.onyx index 5a2c9ade..7238bf9a 100644 --- a/core/container/map.onyx +++ b/core/container/map.onyx @@ -66,7 +66,7 @@ init :: (use map: ^Map($K, $V), default := __zero_value(V)) { array.init(^entries, allocator=allocator); } -free :: (use map: ^Map($K, $V)) { +free :: (use map: ^Map) { memory.free_slice(^hashes, allocator=allocator); array.free(^entries); } @@ -138,12 +138,12 @@ update :: macro (map: ^Map($K, $V), key: K, body: Code) { } } -clear :: (use map: ^Map($K, $V)) { +clear :: (use map: ^Map) { for i: 0 .. hashes.count do hashes.data[i] = -1; entries.count = 0; } -empty :: (use map: ^Map($K, $V)) -> bool { +empty :: (use map: ^Map) -> bool { return entries.count == 0; } @@ -185,14 +185,14 @@ format_map :: (output: ^conv.Format_Output, format: ^conv.Format, x: ^Map($K, $V return lr; } - full :: (use map: ^Map($K, $V)) => entries.count >= ~~(0.75f * ~~hashes.count); + full :: (use map: ^Map) => entries.count >= ~~(0.75f * ~~hashes.count); - grow :: (use map: ^Map($K, $V)) { + grow :: (use map: ^Map) { new_size := math.max(hashes.count << 1, 8); rehash(map, new_size); } - rehash :: (use map: ^Map($K, $V), new_size: i32) { + rehash :: (use map: ^Map, new_size: i32) { memory.free_slice(^hashes, allocator); memory.alloc_slice(^hashes, new_size, allocator); memory.fill_slice(hashes, -1); diff --git a/include/astnodes.h b/include/astnodes.h index 9bff6f58..e0761cb1 100644 --- a/include/astnodes.h +++ b/include/astnodes.h @@ -1407,6 +1407,7 @@ Entity* entity_heap_insert(EntityHeap* entities, Entity e); Entity* entity_heap_top(EntityHeap* entities); void entity_heap_change_top(EntityHeap* entities, Entity* new_top); void entity_heap_remove_top(EntityHeap* entities); +void entity_change_type(EntityHeap* entities, Entity *ent, EntityType new_type); // If target_arr is null, the entities will be placed directly in the heap. void add_entities_for_node(bh_arr(Entity *)* target_arr, AstNode* node, Scope* scope, Package* package); @@ -1633,6 +1634,7 @@ AstFunction* polymorphic_proc_solidify(AstFunction* pp, bh_arr(AstPolySolution) AstNode* polymorphic_proc_try_solidify(AstFunction* pp, bh_arr(AstPolySolution) slns, OnyxToken* tkn); AstFunction* polymorphic_proc_build_only_header(AstFunction* pp, PolyProcLookupMethod pp_lookup, ptr actual); AstFunction* polymorphic_proc_build_only_header_with_slns(AstFunction* pp, bh_arr(AstPolySolution) slns, b32 error_if_failed); +b32 potentially_convert_function_to_polyproc(AstFunction *func); void add_overload_option(bh_arr(OverloadOption)* poverloads, u64 precedence, AstTyped* overload); AstTyped* find_matching_overload_by_arguments(bh_arr(OverloadOption) overloads, Arguments* args); @@ -1711,4 +1713,27 @@ static inline AstFunction* get_function_from_node(AstNode* node) { return NULL; } +static inline void convert_polyproc_to_function(AstFunction *func) { + if (func->kind != Ast_Kind_Polymorphic_Proc) return; + + func->kind = Ast_Kind_Function; + func->parent_scope_of_poly_proc = NULL; + func->poly_params = NULL; + func->known_slns = NULL; + func->concrete_funcs = NULL; + func->active_queries.hashes = NULL; + func->active_queries.entries = NULL; + func->poly_scope = NULL; + func->entity = NULL; +} + +static inline void convert_function_to_polyproc(AstFunction *func) { + if (func->kind != Ast_Kind_Function) return; + + func->kind = Ast_Kind_Polymorphic_Proc; + func->parent_scope_of_poly_proc = func->scope->parent; + func->scope = NULL; + if (func->entity) entity_change_type(&context.entities, func->entity, Entity_Type_Polymorphic_Proc); +} + #endif // #ifndef ONYXASTNODES_H diff --git a/src/checker.c b/src/checker.c index df8e3f05..150d4609 100644 --- a/src/checker.c +++ b/src/checker.c @@ -1714,8 +1714,7 @@ CheckStatus check_expression(AstTyped** pexpr) { case Ast_Kind_Param: if (expr->type == NULL) { - onyx_report_error(expr->token->pos, Error_Critical, "Parameter with bad type."); - retval = Check_Error; + YIELD(expr->token->pos, "Waiting on parameter type."); } break; diff --git a/src/clone.c b/src/clone.c index e55a43f9..448f254d 100644 --- a/src/clone.c +++ b/src/clone.c @@ -11,14 +11,16 @@ static inline b32 should_clone(AstNode* node) { case Ast_Kind_Memres: case Ast_Kind_StrLit: case Ast_Kind_Package: - case Ast_Kind_Enum_Type: - case Ast_Kind_Enum_Value: case Ast_Kind_Overloaded_Function: case Ast_Kind_Alias: case Ast_Kind_Code_Block: case Ast_Kind_Macro: case Ast_Kind_File_Contents: case Ast_Kind_Symbol: + case Ast_Kind_Poly_Struct_Type: + case Ast_Kind_Basic_Type: + case Ast_Kind_Enum_Type: + case Ast_Kind_Enum_Value: return 0; default: return 1; @@ -404,17 +406,7 @@ AstNode* ast_clone(bh_allocator a, void* n) { AstFunction* df = (AstFunction *) nn; AstFunction* sf = (AstFunction *) node; - if (node->kind == Ast_Kind_Polymorphic_Proc) { - df->kind = Ast_Kind_Function; - df->parent_scope_of_poly_proc = NULL; - df->poly_params = NULL; - df->known_slns = NULL; - df->concrete_funcs = NULL; - df->active_queries.hashes = NULL; - df->active_queries.entries = NULL; - df->poly_scope = NULL; - df->entity = NULL; - } + convert_polyproc_to_function(df); if (sf->is_foreign) return node; assert(df->scope == NULL); @@ -541,19 +533,8 @@ AstFunction* clone_function_header(bh_allocator a, AstFunction* func) { memmove(new_func, func, sizeof(AstFunction)); assert(new_func->scope == NULL); - if (func->kind == Ast_Kind_Polymorphic_Proc) { - new_func->kind = Ast_Kind_Function; - new_func->parent_scope_of_poly_proc = NULL; - new_func->poly_params = NULL; - new_func->known_slns = NULL; - new_func->concrete_funcs = NULL; - new_func->active_queries.hashes = NULL; - new_func->active_queries.entries = NULL; - new_func->poly_scope = NULL; - new_func->entity = NULL; - } + convert_polyproc_to_function(new_func); - // new_func->body = NULL; new_func->return_type = (AstType *) ast_clone(a, func->return_type); new_func->params = NULL; diff --git a/src/entities.c b/src/entities.c index 2bf46c94..e8f39de0 100644 --- a/src/entities.c +++ b/src/entities.c @@ -137,6 +137,12 @@ void entity_heap_remove_top(EntityHeap* entities) { eh_shift_down(entities, 0); } +void entity_change_type(EntityHeap* entities, Entity *ent, EntityType new_type) { + entities->type_count[ent->type]--; + entities->type_count[new_type]++; + ent->type = new_type; +} + // NOTE(Brendan Hansen): Uses the entity heap in the context structure void add_entities_for_node(bh_arr(Entity *) *target_arr, AstNode* node, Scope* scope, Package* package) { #define ENTITY_INSERT(_ent) \ diff --git a/src/polymorph.h b/src/polymorph.h index 0a82db77..af03de6d 100644 --- a/src/polymorph.h +++ b/src/polymorph.h @@ -845,6 +845,90 @@ AstFunction* polymorphic_proc_build_only_header_with_slns(AstFunction* pp, bh_ar return (AstFunction *) &node_that_signals_a_yield; } +typedef struct AutoPolymorphVariable { + u32 idx; + u32 variable_count; + AstType *base_type; + AstType **replace; +} AutoPolymorphVariable; + +// This should be called after all the parameter types have been symresed, but before anything +// happens to the body. +b32 potentially_convert_function_to_polyproc(AstFunction *func) { + bh_arr(AutoPolymorphVariable) auto_vars = NULL; + bh_arr_new(global_heap_allocator, auto_vars, 2); + + u32 param_idx = 0; + bh_arr_each(AstParam, param, func->params) { + AstType **to_replace = ¶m->local->type_node; + AstType *param_type = param->local->type_node; + + b32 done = 0; + while (!done && param_type) { + switch (param_type->kind) { + case Ast_Kind_Pointer_Type: to_replace = &((AstPointerType *) *to_replace)->elem; param_type = ((AstPointerType *) param_type)->elem; break; + case Ast_Kind_Array_Type: to_replace = &((AstArrayType *) *to_replace)->elem; param_type = ((AstArrayType *) param_type)->elem; break; + case Ast_Kind_Slice_Type: to_replace = &((AstSliceType *) *to_replace)->elem; param_type = ((AstSliceType *) param_type)->elem; break; + case Ast_Kind_DynArr_Type: to_replace = &((AstDynArrType *) *to_replace)->elem; param_type = ((AstDynArrType *) param_type)->elem; break; + case Ast_Kind_Alias: param_type = ((AstAlias *) param_type)->alias; break; + case Ast_Kind_Type_Alias: param_type = ((AstTypeAlias *) param_type)->to; break; + case Ast_Kind_Poly_Struct_Type: { + AutoPolymorphVariable apv; + apv.idx = param_idx; + apv.base_type = param->local->type_node; + apv.variable_count = bh_arr_length(((AstPolyStructType *) param_type)->poly_params); + apv.replace = to_replace; + + bh_arr_push(auto_vars, apv); + done = 1; + break; + } + + default: done = 1; break; + } + } + + param_idx++; + } + + if (bh_arr_length(auto_vars) == 0) return 0; + + param_idx = 0; + bh_arr_each(AutoPolymorphVariable, apv, auto_vars) { + AstPolyParam pp; + pp.idx = apv->idx; + pp.kind = PPK_Poly_Type; + + AstPolyCallType* pcall = onyx_ast_node_new(context.ast_alloc, sizeof(AstPolyCallType), Ast_Kind_Poly_Call_Type); + pcall->callee = *apv->replace; + pcall->token = pcall->callee->token; + bh_arr_new(global_heap_allocator, pcall->params, apv->variable_count); + + if (apv->base_type->kind == Ast_Kind_Poly_Struct_Type) { + pp.type_expr = (AstType *) pcall; + } else { + pp.type_expr = apv->base_type; + } + *apv->replace = (AstType *) pcall; + + fori (i, 0, apv->variable_count) { + OnyxToken* name_token = bh_alloc_item(context.ast_alloc, OnyxToken); + name_token->text = bh_aprintf(context.ast_alloc, "__autopoly_var_%d\0", param_idx); + name_token->length = strlen(name_token->text); + name_token->type = Token_Type_Symbol; + name_token->pos = pcall->token->pos; + + pp.poly_sym = make_symbol(context.ast_alloc, name_token); + bh_arr_push(pcall->params, pp.poly_sym); + bh_arr_push(func->poly_params, pp); + param_idx ++; + } + } + + convert_function_to_polyproc(func); + return 1; +} + // // Polymorphic Structures // diff --git a/src/symres.c b/src/symres.c index 91f89e88..de655814 100644 --- a/src/symres.c +++ b/src/symres.c @@ -213,8 +213,10 @@ static SymresStatus symres_type(AstType** type) { case Ast_Kind_Alias: { AstAlias* alias = (AstAlias *) *type; alias->flags |= Ast_Flag_Symbol_Invisible; - SYMRES(type, (AstType **) &alias->alias); + SymresStatus ss = symres_type((AstType **) &alias->alias); alias->flags &= ~Ast_Flag_Symbol_Invisible; + if (ss > Symres_Errors_Start) return ss; + break; } @@ -457,8 +459,9 @@ static SymresStatus symres_expression(AstTyped** expr) { case Ast_Kind_Align_Of: SYMRES(align_of, (AstAlignOf *)*expr); break; case Ast_Kind_Alias: { (*expr)->flags |= Ast_Flag_Symbol_Invisible; - SYMRES(expression, &((AstAlias *) *expr)->alias); + SymresStatus ss = symres_expression((AstTyped **) &((AstAlias *) *expr)->alias); (*expr)->flags &= ~Ast_Flag_Symbol_Invisible; + if (ss > Symres_Errors_Start) return ss; break; } @@ -940,14 +943,12 @@ SymresStatus symres_function_header(AstFunction* func) { } } - SYMRES(type, &func->return_type); - if (!node_is_type((AstNode *) func->return_type)) { - AstType* return_type = (AstType *) strip_aliases((AstNode *) func->return_type); - if (return_type->kind == Ast_Kind_Symbol) return Symres_Yield_Macro; - - onyx_report_error(func->token->pos, Error_Critical, "Return type is not a type."); + if (potentially_convert_function_to_polyproc(func)) { + return Symres_Complete; } + SYMRES(type, &func->return_type); + if (func->constraints.constraints != NULL) { bh_arr_each(AstConstraint *, constraint, func->constraints.constraints) { SYMRES(constraint, *constraint); @@ -961,6 +962,7 @@ SymresStatus symres_function_header(AstFunction* func) { SymresStatus symres_function(AstFunction* func) { if (func->entity_header && func->entity_header->state < Entity_State_Check_Types) return Symres_Yield_Macro; + if (func->kind == Ast_Kind_Polymorphic_Proc) return Symres_Complete; assert(func->scope); scope_enter(func->scope); -- 2.25.1