started working on auto polymorphic functions
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Wed, 5 Jan 2022 03:20:16 +0000 (21:20 -0600)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Wed, 5 Jan 2022 03:20:16 +0000 (21:20 -0600)
core/container/iter.onyx
core/container/map.onyx
include/astnodes.h
src/checker.c
src/clone.c
src/entities.c
src/polymorph.h
src/symres.c

index 6c90382747e890558c914ee30521a2d4bba8a0ba..1a8c575bb26b59113dec5f37ef6148cfeceec8c5 100644 (file)
@@ -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,
         };
index 5a2c9ade528f5ddda2e6de7035cd62b0a6c29149..7238bf9a2a2d689c79623a50ac3a3f1e3b22f655 100644 (file)
@@ -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);
index 9bff6f58bbf2673c49d31e1773149344e79f2bb9..e0761cb1b8eb8084bc7474d256c52f342bb67729 100644 (file)
@@ -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
index df8e3f054d37e04a8dcb912641c5cef205bb9d9d..150d46094594e9e72c1e885c75c1659bd618f668 100644 (file)
@@ -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;
 
index e55a43f9d8c92a7a741fac4f92e11be731fe80ce..448f254da4f95b600c681d6b98c48b26d6d954f4 100644 (file)
@@ -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;
index 2bf46c94b0270d6fdf2a59bc3abb920306bd606c..e8f39de047ed43d6d8cbb4888aea4716586835bb 100644 (file)
@@ -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)                                     \
index 0a82db77851878f8546d4c9f08a54e9e907d4df0..af03de6da3bb053fccb3be23700e2c873998f526 100644 (file)
@@ -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 = &param->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
 //
index 91f89e880f9945d3f9c804aae439b493ae979525..de655814677226d9e43d1fd19f5091a4a281d03b 100644 (file)
@@ -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);