MAYBE BREAKING CHANGE; Polymorphic structure types are no longer known immediately
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Thu, 3 Jun 2021 19:02:03 +0000 (14:02 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Thu, 3 Jun 2021 19:02:03 +0000 (14:02 -0500)
bin/onyx
core/stdio.onyx
include/onyxastnodes.h
src/onyxchecker.c
src/onyxtypes.c
src/onyxutils.c

index 8c7dc83053608610e844951eb4596635c3013ee9..201a94b120d9f13b7f02ce27549187fb0ee85dc5 100755 (executable)
Binary files a/bin/onyx and b/bin/onyx differ
index 7488a5a4b04ba9fe8b4a60344da2edd2a20c7ae6..a81f1a4f69c2c6b8b3dcd46c681f81d08f4332f3 100644 (file)
@@ -66,7 +66,7 @@ byte_dump :: (ptr: rawptr, byte_count: u32, bytes_per_line := 8) {
         temp[1] = map_to_ascii(val & 15);
         temp[2] = #char " ";
 
-        runtime.__output_string(.{ ~~temp, 3 }); 
+        runtime.__output_string(~~temp);
 
         if i % bytes_per_line == (bytes_per_line - 1) do runtime.__output_string("\n");
     }
index 9dc4062f5f0e1f2b91c8af63ca30b7f83bbd7a2b..ab98b6069ec6f293ec51291f3e87bb8975a2f410 100644 (file)
@@ -701,6 +701,8 @@ struct AstStructType {
 
     struct Entity* entity_type;
     struct Entity* entity_defaults;
+
+    b32 stcache_is_valid : 1;
 };
 struct AstStructMember {
     AstTyped_base;
@@ -988,8 +990,8 @@ typedef struct Entity {
     EntityState state;
 
     // TODO: Document this!
-    u16 macro_attempts;
-    u16 micro_attempts;
+    u32 macro_attempts;
+    u32 micro_attempts;
 
     b32 entered_in_queue : 1;
 
index c78dc33d78445e9b0c724ce682e6d8c48dfc45a9..2637ec5a664f9e6515a705ea2644458d3f141848 100644 (file)
@@ -972,6 +972,8 @@ CheckStatus check_unaryop(AstUnaryOp** punop) {
 
     if (unaryop->operation == Unary_Op_Cast) {
         char* err;
+        if (unaryop->type == NULL) return Check_Yield_Macro;
+
         if (!cast_is_legal(unaryop->expr->type, unaryop->type, &err)) {
             onyx_report_error(unaryop->token->pos, "Cast Error: %s", err);
             return Check_Error;
@@ -1021,7 +1023,7 @@ CheckStatus check_struct_literal(AstStructLiteral* sl) {
         }
 
         fill_in_type((AstTyped *) sl);
-        if (sl->type == NULL) return Check_Error;
+        if (sl->type == NULL) return Check_Yield_Macro;
     }
 
     if (!type_is_structlike_strict(sl->type)) {
@@ -1034,25 +1036,29 @@ CheckStatus check_struct_literal(AstStructLiteral* sl) {
     i32 mem_count = type_structlike_mem_count(sl->type);
     arguments_ensure_length(&sl->args, mem_count);
 
-    char* err_msg = NULL;
-    if (!fill_in_arguments(&sl->args, (AstNode *) sl, &err_msg)) {
-        onyx_report_error(sl->token->pos, err_msg);
-        
-        bh_arr_each(AstTyped *, value, sl->args.values) {
-            if (*value == NULL) {
-                i32 member_idx = value - sl->args.values; // Pointer subtraction hack
-                StructMember smem;
-                type_lookup_member_by_idx(sl->type, member_idx, &smem);
-
-                onyx_report_error(sl->token->pos,
-                    "Value not given for %d%s member, '%s', for type '%s'.",
-                    member_idx + 1, bh_num_suffix(member_idx + 1),
-                    smem.name, type_get_name(sl->type));
+    // :Idempotency
+    if ((sl->flags & Ast_Flag_Has_Been_Checked) == 0) {
+        char* err_msg = NULL;
+        if (!fill_in_arguments(&sl->args, (AstNode *) sl, &err_msg)) {
+            onyx_report_error(sl->token->pos, err_msg);
+            
+            bh_arr_each(AstTyped *, value, sl->args.values) {
+                if (*value == NULL) {
+                    i32 member_idx = value - sl->args.values; // Pointer subtraction hack
+                    StructMember smem;
+                    type_lookup_member_by_idx(sl->type, member_idx, &smem);
+
+                    onyx_report_error(sl->token->pos,
+                        "Value not given for %d%s member, '%s', for type '%s'.",
+                        member_idx + 1, bh_num_suffix(member_idx + 1),
+                        smem.name, type_get_name(sl->type));
+                }
             }
-        }
 
-        return Check_Error;
+            return Check_Error;
+        }
     }
+    sl->flags |= Ast_Flag_Has_Been_Checked;
 
     AstTyped** actual = sl->args.values;
     StructMember smem;
@@ -1096,6 +1102,7 @@ CheckStatus check_struct_literal(AstStructLiteral* sl) {
 }
 
 CheckStatus check_array_literal(AstArrayLiteral* al) {
+    // :Idempotency
     if ((al->flags & Ast_Flag_Array_Literal_Typed) == 0) {
         if (al->atnode == NULL) return Check_Success;
 
@@ -1105,7 +1112,7 @@ CheckStatus check_array_literal(AstArrayLiteral* al) {
         }
 
         fill_in_type((AstTyped *) al);
-        if (al->type == NULL) return Check_Error;
+        if (al->type == NULL) return Check_Yield_Macro;
 
         al->type = type_make_array(context.ast_alloc, al->type, bh_arr_length(al->values));
         if (al->type == NULL || al->type->kind != Type_Kind_Array) {
@@ -1128,6 +1135,13 @@ CheckStatus check_array_literal(AstArrayLiteral* al) {
     bh_arr_each(AstTyped *, expr, al->values) {
         CHECK(expression, expr);
 
+        // HACK HACK HACK
+        if ((*expr)->type == NULL &&
+            (*expr)->entity != NULL &&
+            (*expr)->entity->state <= Entity_State_Check_Types) {
+            return Check_Yield_Macro;
+        }
+
         al->flags &= ((*expr)->flags & Ast_Flag_Comptime) | (al->flags &~ Ast_Flag_Comptime);
 
         if (!type_check_or_auto_cast(expr, elem_type)) {
@@ -1353,21 +1367,25 @@ CheckStatus check_method_call(AstBinaryOp** mcall) {
     CHECK(expression, &(*mcall)->left);
 
     AstTyped* implicit_argument = (*mcall)->left;
-    
-    // Implicitly take the address of the value if it is not already a pointer type.
-    // This could be weird to think about semantically so some testing with real code
-    // would be good.                                      - brendanfh 2020/02/05
-    if (implicit_argument->type->kind != Type_Kind_Pointer)
-        implicit_argument = (AstTyped *) make_address_of(context.ast_alloc, implicit_argument);
-    
-    implicit_argument = (AstTyped *) make_argument(context.ast_alloc, implicit_argument);
 
     // Symbol resolution should have ensured that this is call node.
     AstCall* call_node = (AstCall *) (*mcall)->right;
     assert(call_node->kind == Ast_Kind_Call);
 
-    bh_arr_insertn(call_node->args.values, 0, 1);
-    call_node->args.values[0] = implicit_argument;
+    // :Idempotency
+    if (((*mcall)->flags & Ast_Flag_Has_Been_Checked) == 0) {
+        // Implicitly take the address of the value if it is not already a pointer type.
+        // This could be weird to think about semantically so some testing with real code
+        // would be good.                                      - brendanfh 2020/02/05
+        if (implicit_argument->type->kind != Type_Kind_Pointer)
+            implicit_argument = (AstTyped *) make_address_of(context.ast_alloc, implicit_argument);
+        
+        implicit_argument = (AstTyped *) make_argument(context.ast_alloc, implicit_argument);
+
+        bh_arr_insertn(call_node->args.values, 0, 1);
+        call_node->args.values[0] = implicit_argument;
+    }    
+    (*mcall)->flags |= Ast_Flag_Has_Been_Checked;
 
     CHECK(call, call_node);
     call_node->next = (*mcall)->next;
@@ -1380,10 +1398,8 @@ CheckStatus check_size_of(AstSizeOf* so) {
     fill_in_array_count(so->so_ast_type);
 
     so->so_type = type_build_from_ast(context.ast_alloc, so->so_ast_type);
-    if (so->so_type == NULL) {
-        onyx_report_error(so->token->pos, "Error with type used here.");
-        return Check_Error;
-    }
+    if (so->so_type == NULL) return Check_Yield_Macro;
+
     so->size = type_size_of(so->so_type);
 
     return Check_Success;
@@ -1393,10 +1409,8 @@ CheckStatus check_align_of(AstAlignOf* ao) {
     fill_in_array_count(ao->ao_ast_type);
 
     ao->ao_type = type_build_from_ast(context.ast_alloc, ao->ao_ast_type);
-    if (ao->ao_type == NULL) {
-        onyx_report_error(ao->token->pos, "Error with type used here.");
-        return Check_Error;
-    }
+    if (ao->ao_type == NULL) return Check_Yield_Macro;
+
     ao->alignment = type_alignment_of(ao->ao_type);
 
     return Check_Success;
@@ -1555,9 +1569,12 @@ CheckStatus check_statement(AstNode** pstmt) {
         // in a block in order to efficiently allocate enough space and registers
         // for them all. Now with LocalAllocator, this is no longer necessary.
         // Therefore, locals stay in the tree and need to be passed along.
-        case Ast_Kind_Local:
-            fill_in_type((AstTyped *) stmt);
+        case Ast_Kind_Local: {
+            AstTyped* typed_stmt = (AstTyped *) stmt;
+            fill_in_type(typed_stmt);
+            if (typed_stmt->type_node != NULL && typed_stmt->type == NULL) return Check_Yield_Macro;
             return Check_Success;
+        }
 
         default:
             CHECK(expression, (AstTyped **) pstmt);
@@ -1610,7 +1627,7 @@ CheckStatus check_function(AstFunction* func) {
     expected_return_type = func->type->Function.return_type;
     if (func->body) {
         CheckStatus status = check_block(func->body);
-        if (status != Check_Success && func->generated_from)
+        if (status == Check_Error && func->generated_from)
             onyx_report_error(func->generated_from->pos, "Error in polymorphic procedure generated from this location.");
 
         return status;
@@ -1658,7 +1675,10 @@ CheckStatus check_struct(AstStructType* s_node) {
     bh_arr_each(AstStructMember *, smem, s_node->members) {
         if ((*smem)->type_node == NULL && (*smem)->initial_value != NULL) {
             CHECK(expression, &(*smem)->initial_value);
+
             fill_in_type((*smem)->initial_value);
+            if ((*smem)->initial_value->type == NULL) return Check_Yield_Macro;
+
             (*smem)->type = resolve_expression_type((*smem)->initial_value);
 
             if ((*smem)->type == NULL) {
@@ -1757,13 +1777,12 @@ CheckStatus check_function_header(AstFunction* func) {
         if (local->type_node != NULL) CHECK(type, local->type_node);
 
         fill_in_type((AstTyped *) local);
-
         if (local->type == NULL) {
-            onyx_report_error(param->local->token->pos,
-                    "Unable to resolve type for parameter, '%b'",
-                    local->token->text,
-                    local->token->length);
-            return Check_Error;
+            // onyx_report_error(param->local->token->pos,
+            //         "Unable to resolve type for parameter, '%b'",
+            //         local->token->text,
+            //         local->token->length);
+            return Check_Yield_Macro;
         }
 
         if (local->type->kind == Type_Kind_Compound) {
@@ -1797,12 +1816,14 @@ CheckStatus check_function_header(AstFunction* func) {
     if (func->return_type != NULL) CHECK(type, func->return_type);
 
     func->type = type_build_function_type(context.ast_alloc, func);
+    if (func->type == NULL) return Check_Yield_Macro;
 
     return Check_Success;
 }
 
 CheckStatus check_memres_type(AstMemRes* memres) {
     fill_in_type((AstTyped *) memres);
+    if (memres->type_node && !memres->type) return Check_Yield_Macro;
     return Check_Success;
 }
 
index bfb7b0712a87a531cd3b6c1b171f0327a64711d8..800ff5381d2eb27b09062ae52ac7b22f409d05b3 100644 (file)
@@ -227,17 +227,23 @@ Type* type_build_from_ast(bh_allocator alloc, AstType* type_node) {
             AstFunctionType* ftype_node = (AstFunctionType *) type_node;
             u64 param_count = ftype_node->param_count;
 
+            Type* return_type = type_build_from_ast(alloc, ftype_node->return_type);
+            if (return_type == NULL) return NULL;
+
             Type* func_type = bh_alloc(alloc, sizeof(Type) + sizeof(Type *) * param_count);
 
             func_type->kind = Type_Kind_Function;
             func_type->ast_type = type_node;
             func_type->Function.param_count = param_count;
             func_type->Function.needed_param_count = param_count;
-            func_type->Function.return_type = type_build_from_ast(alloc, ftype_node->return_type);
+            func_type->Function.return_type = return_type;
 
             if (param_count > 0)
                 fori (i, 0, (i64) param_count) {
                     func_type->Function.params[i] = type_build_from_ast(alloc, ftype_node->params[i]);
+
+                    // LEAK LEAK LEAK
+                    if (func_type->Function.params[i] == NULL) return NULL;
                 }
 
             return func_type;
@@ -281,22 +287,31 @@ Type* type_build_from_ast(bh_allocator alloc, AstType* type_node) {
 
         case Ast_Kind_Struct_Type: {
             AstStructType* s_node = (AstStructType *) type_node;
-            if (s_node->stcache != NULL) return s_node->stcache;
+            if (s_node->stcache != NULL && s_node->stcache_is_valid) return s_node->stcache;
+
+            Type* s_type;
+            if (s_node->stcache == NULL) {
+                s_type = bh_alloc(alloc, sizeof(Type));
+                s_node->stcache = s_type;
 
-            Type* s_type = bh_alloc(alloc, sizeof(Type));
-            s_node->stcache = s_type;
-            s_type->kind = Type_Kind_Struct;
-            s_type->ast_type = type_node;
+                s_type->kind = Type_Kind_Struct;
+                s_type->ast_type = type_node;
+                s_type->Struct.name = s_node->name;
+                s_type->Struct.unique_id = next_unique_id++;
+                s_type->Struct.mem_count = bh_arr_length(s_node->members);
+
+            } else {
+                s_type = s_node->stcache;
+            }
 
-            s_type->Struct.unique_id = next_unique_id++;
-            s_type->Struct.name = s_node->name;
-            s_type->Struct.mem_count = bh_arr_length(s_node->members);
             s_type->Struct.memarr = NULL;
             s_type->Struct.poly_sln = NULL;
 
             bh_table_init(global_heap_allocator, s_type->Struct.members, s_type->Struct.mem_count + 1);
             bh_arr_new(global_heap_allocator, s_type->Struct.memarr, s_type->Struct.mem_count);
 
+            s_node->stcache_is_valid = 1;
+
             b32 is_union = (s_node->flags & Ast_Flag_Struct_Is_Union) != 0;
             u32 size = 0;
             u32 offset = 0;
@@ -307,16 +322,15 @@ Type* type_build_from_ast(bh_allocator alloc, AstType* type_node) {
                     (*member)->type = type_build_from_ast(alloc, (*member)->type_node);
 
                 if ((*member)->type == NULL) {
-                    // :ExplicitTyping
-                    // onyx_report_error((*member)->token->pos, "Unable to resolve member type. Try adding it explicitly."); 
-                    s_node->stcache = NULL;
+                    // LEAK LEAK LEAK
+                    s_node->stcache_is_valid = 0;
                     return NULL;
                 }
 
                 mem_alignment = type_alignment_of((*member)->type);
                 if (mem_alignment <= 0) {
                     onyx_report_error((*member)->token->pos, "Invalid member type: %s", type_get_name((*member)->type)); 
-                    return s_type;
+                    return NULL;
                 }
 
                 if (mem_alignment > alignment) alignment = mem_alignment;
@@ -455,9 +469,14 @@ Type* type_build_from_ast(bh_allocator alloc, AstType* type_node) {
             bh_arr_new(global_heap_allocator, slns, bh_arr_length(pc_type->params));
             bh_arr_each(AstNode *, given, pc_type->params) {
                 if (node_is_type(*given)) {
+                    Type* param_type = type_build_from_ast(alloc, (AstType *) *given);
+
+                    // LEAK LEAK LEAK
+                    if (param_type == NULL) return NULL;
+
                     bh_arr_push(slns, ((AstPolySolution) {
                         .kind     = PSK_Type,
-                        .type     = type_build_from_ast(alloc, (AstType *) *given),
+                        .type     = param_type,
                     }));
                 } else {
                     bh_arr_push(slns, ((AstPolySolution) {
@@ -492,6 +511,10 @@ Type* type_build_from_ast(bh_allocator alloc, AstType* type_node) {
             fori (i, 0, type_count) {
                 assert(ctype->types[i] != NULL);
                 comp_type->Compound.types[i] = type_build_from_ast(alloc, ctype->types[i]);
+
+                // LEAK LEAK LEAK
+                if (comp_type->Compound.types[i] == NULL) return NULL;
+
                 comp_type->Compound.size += bh_max(type_size_of(comp_type->Compound.types[i]), 4);
             }
 
@@ -512,15 +535,19 @@ Type* type_build_from_ast(bh_allocator alloc, AstType* type_node) {
     return NULL;
 }
 
+// CLEANUP: This needs to be merged with the very similar code from up above.
 Type* type_build_function_type(bh_allocator alloc, AstFunction* func) {
     u64 param_count = bh_arr_length(func->params);
 
+    Type* return_type = type_build_from_ast(alloc, func->return_type);
+    if (return_type == NULL) return NULL;
+
     Type* func_type = bh_alloc(alloc, sizeof(Type) + sizeof(Type *) * param_count);
 
     func_type->kind = Type_Kind_Function;
     func_type->Function.param_count = param_count;
     func_type->Function.needed_param_count = 0;
-    func_type->Function.return_type = type_build_from_ast(alloc, func->return_type);
+    func_type->Function.return_type = return_type;
 
     if (param_count > 0) {
         i32 i = 0;
index 6717d882bb2decd643a3409675b5e8e8cde88235..b67a66f1f39f847f4373d92569815cd4d67207d0 100644 (file)
@@ -1225,50 +1225,29 @@ AstStructType* polymorphic_struct_lookup(AstPolyStructType* ps_type, bh_arr(AstP
 
     char* unique_key = build_poly_slns_unique_key(slns);
     if (bh_table_has(AstStructType *, ps_type->concrete_structs, unique_key)) {
-        return bh_table_get(AstStructType *, ps_type->concrete_structs, unique_key);
-    }
+        AstStructType* concrete_struct = bh_table_get(AstStructType *, ps_type->concrete_structs, unique_key);
 
-    scope_clear(ps_type->scope);
-    insert_poly_slns_into_scope(ps_type->scope, slns);
+        if (concrete_struct->entity_type->state < Entity_State_Check_Types) {
+            return NULL;
+        }
 
-    AstStructType* concrete_struct = (AstStructType *) ast_clone(context.ast_alloc, ps_type->base_struct);
-    bh_table_put(AstStructType *, ps_type->concrete_structs, unique_key, concrete_struct);
+        Type* cs_type = type_build_from_ast(context.ast_alloc, (AstType *) concrete_struct);
+        if (!cs_type) return NULL;
 
-    Entity struct_entity = {
-        .state = Entity_State_Resolve_Symbols,
-        .type = Entity_Type_Type_Alias,
-        .type_alias = (AstType *) concrete_struct,
-        .package = NULL,
-        .scope = ps_type->scope,
-    };
-    Entity struct_default_entity = {
-        .state = Entity_State_Resolve_Symbols,
-        .type = Entity_Type_Struct_Member_Default,
-        .type_alias = (AstType *) concrete_struct,
-        .package = NULL,
-        .scope = ps_type->scope,
-    };
+        if (cs_type->Struct.poly_sln == NULL) cs_type->Struct.poly_sln = bh_arr_copy(global_heap_allocator, slns);
+        if (cs_type->Struct.name == NULL)     cs_type->Struct.name = build_poly_struct_name(ps_type, cs_type);
 
-    entity_bring_to_state(&struct_entity, Entity_State_Check_Types);
-    entity_bring_to_state(&struct_default_entity, Entity_State_Check_Types);
-    entity_bring_to_state(&struct_entity, Entity_State_Code_Gen);
-    entity_bring_to_state(&struct_default_entity, Entity_State_Code_Gen);
-    if (onyx_has_errors()) {
-        onyx_report_error(pos, "Error in creating polymorphic struct instantiation here.");
-        bh_table_put(AstStructType *, ps_type->concrete_structs, unique_key, NULL);
-        return NULL;
+        return concrete_struct;
     }
 
-    Type* cs_type = type_build_from_ast(context.ast_alloc, (AstType *) concrete_struct);
+    Scope* sln_scope = scope_create(context.ast_alloc, ps_type->scope, ps_type->token->pos);
+    insert_poly_slns_into_scope(sln_scope, slns);
 
-    // CLEANUP: This should not be necessary since the only place this function can be
-    // called from is type_build_from_ast in the Ast_Kind_Poly_Call_Type case, which
-    // allocates the 'slns' array on the heap. So, duplicating it should not be necessary.
-    cs_type->Struct.poly_sln = bh_arr_copy(global_heap_allocator, slns);
+    AstStructType* concrete_struct = (AstStructType *) ast_clone(context.ast_alloc, ps_type->base_struct);
+    bh_table_put(AstStructType *, ps_type->concrete_structs, unique_key, concrete_struct);
 
-    cs_type->Struct.name = build_poly_struct_name(ps_type, cs_type);
-    return concrete_struct;
+    add_entities_for_node(NULL, (AstNode *) concrete_struct, sln_scope, NULL);
+    return NULL;
 }
 
 void entity_bring_to_state(Entity* ent, EntityState state) {