polymorphic structures are very powerful now
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Thu, 28 Apr 2022 21:37:13 +0000 (16:37 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Thu, 28 Apr 2022 21:37:13 +0000 (16:37 -0500)
include/astnodes.h
src/checker.c
src/polymorph.h
src/symres.c
src/types.c
src/wasm_type_table.h
tests/aoc-2020/day7.onyx

index d5433347f8c5171eca4d75335003d61482df38d6..f7cb27409cb119ce768642b2d737138c169bb3c8 100644 (file)
@@ -912,9 +912,13 @@ struct AstStructType {
     OnyxFilePos polymorphic_error_loc;
     ConstraintContext constraints;
 
+    bh_arr(AstType *)       polymorphic_argument_types;
+    bh_arr(AstPolySolution) polymorphic_arguments;
+
     b32 pending_type_is_valid : 1;
     b32 is_union              : 1;
     b32 is_packed             : 1;
+    b32 ready_to_build_type   : 1;
 };
 struct AstStructMember {
     AstTyped_base;
index f788ddd691811b1f63ae554ac6d2cc60ff4f32b1..5c4be2e1dad0e4868df46b58efd9a0ab49fe1515 100644 (file)
@@ -1350,6 +1350,9 @@ CheckStatus check_range_literal(AstRangeLiteral** prange) {
     CHECK(expression, &range->low);
     CHECK(expression, &range->high);
 
+    builtin_range_type_type = type_build_from_ast(context.ast_alloc, builtin_range_type);
+    if (builtin_range_type_type == NULL) YIELD(range->token->pos, "Waiting for 'range' structure to be built.");
+
     Type* expected_range_type = builtin_range_type_type;
     StructMember smem;
 
@@ -2151,6 +2154,24 @@ CheckStatus check_struct(AstStructType* s_node) {
     if (s_node->entity_defaults && s_node->entity_defaults->state < Entity_State_Check_Types)
         YIELD(s_node->token->pos, "Waiting for struct member defaults to pass symbol resolution.");
 
+    if (s_node->polymorphic_argument_types) {
+        assert(s_node->polymorphic_arguments);
+
+        fori (i, 0, (i64) bh_arr_length(s_node->polymorphic_argument_types)) {
+            Type *arg_type = type_build_from_ast(context.ast_alloc, s_node->polymorphic_argument_types[i]);
+            if (arg_type == NULL) YIELD(s_node->polymorphic_argument_types[i]->token->pos, "Waiting to build type for polymorph argument.");
+
+            // nocheckin this is wrong...
+            if (s_node->polymorphic_arguments[i].value) {
+                TYPE_CHECK(&s_node->polymorphic_arguments[i].value, arg_type) {
+                    ERROR_(s_node->polymorphic_arguments[i].value->token->pos, "Expected value of type %s, got %s.",
+                        type_get_name(arg_type),
+                        type_get_name(s_node->polymorphic_arguments[i].value->type));
+                }
+            }
+        }
+    }
+
     if (s_node->constraints.constraints) {
         s_node->constraints.produce_errors = (s_node->flags & Ast_Flag_Header_Check_No_Error) == 0;
 
@@ -2192,6 +2213,7 @@ CheckStatus check_struct(AstStructType* s_node) {
     }
 
     // NOTE: fills in the pending_type.
+    s_node->ready_to_build_type = 1;
     type_build_from_ast(context.ast_alloc, (AstType *) s_node);
     if (s_node->pending_type == NULL || !s_node->pending_type_is_valid)
         YIELD(s_node->token->pos, "Waiting for type to be constructed.");
index d7974ada7ab69e2fbdf0795a5226534ec5881c70..0185b8f3a02bbf15e8b74fe2ce704ad1ba3bf85c 100644 (file)
@@ -1043,45 +1043,6 @@ Type* polymorphic_struct_lookup(AstPolyStructType* ps_type, bh_arr(AstPolySoluti
     i32 i = 0;
     bh_arr_each(AstPolySolution, sln, slns) {
         sln->poly_sym = (AstNode *) &ps_type->poly_params[i];
-
-        PolySolutionKind expected_kind = PSK_Undefined;
-        if ((AstNode *) ps_type->poly_params[i].type_node == (AstNode *) &basic_type_type_expr) {
-            expected_kind = PSK_Type;
-        } else {
-            expected_kind = PSK_Value;
-        }
-
-        if (sln->kind != expected_kind) {
-            if (expected_kind == PSK_Type) 
-                onyx_report_error(pos, Error_Critical, "Expected type expression for %d%s argument.", i + 1, bh_num_suffix(i + 1));
-
-            if (expected_kind == PSK_Value)
-                onyx_report_error(pos, Error_Critical, "Expected value expression of type '%s' for %d%s argument.",
-                    type_get_name(ps_type->poly_params[i].type),
-                    i + 1, bh_num_suffix(i + 1));
-
-            return NULL;
-        }
-
-        if (sln->kind == PSK_Value) {
-            resolve_expression_type(sln->value);
-
-            if ((sln->value->flags & Ast_Flag_Comptime) == 0) {
-                onyx_report_error(pos, Error_Critical,
-                    "Expected compile-time known argument for '%b'.",
-                    sln->poly_sym->token->text,
-                    sln->poly_sym->token->length);
-                return NULL;
-            }
-
-            if (!types_are_compatible(sln->value->type, ps_type->poly_params[i].type)) {
-                onyx_report_error(pos, Error_Critical, "Expected compile-time argument of type '%s', got '%s'.",
-                    type_get_name(ps_type->poly_params[i].type),
-                    type_get_name(sln->value->type));
-                return NULL;
-            }
-        }
-
         i++;
     }
 
@@ -1113,8 +1074,18 @@ Type* polymorphic_struct_lookup(AstPolyStructType* ps_type, bh_arr(AstPolySoluti
     AstStructType* concrete_struct = (AstStructType *) ast_clone(context.ast_alloc, ps_type->base_struct);
     concrete_struct->polymorphic_error_loc = pos;
     BH_MASK_SET(concrete_struct->flags, !error_if_failed, Ast_Flag_Header_Check_No_Error);
-    shput(ps_type->concrete_structs, unique_key, concrete_struct);
 
+
+    i64 arg_count = bh_arr_length(ps_type->poly_params);
+    bh_arr_new(global_heap_allocator, concrete_struct->polymorphic_argument_types, arg_count);
+    bh_arr_set_length(concrete_struct->polymorphic_argument_types, arg_count);
+    concrete_struct->polymorphic_arguments = bh_arr_copy(global_heap_allocator, slns);
+
+    fori (i, 0, (i64) bh_arr_length(ps_type->poly_params)) {
+        concrete_struct->polymorphic_argument_types[i] = (AstType *) ast_clone(context.ast_alloc, ps_type->poly_params[i].type_node);
+    }
+
+    shput(ps_type->concrete_structs, unique_key, concrete_struct);
     add_entities_for_node(NULL, (AstNode *) concrete_struct, sln_scope, NULL);
     return NULL;
 }
index 503073a98a92bb11bdfe393410fa90ce2ba5abec..169636113f5c059cc8b74036398b7e6ce281b573 100644 (file)
@@ -119,6 +119,21 @@ static SymresStatus symres_struct_type(AstStructType* s_node) {
         scope_enter(s_node->scope);
     }
 
+    if (s_node->polymorphic_argument_types) {
+        assert(s_node->polymorphic_arguments);
+
+        SymresStatus ss = Symres_Success, result;
+        fori (i, 0, (i64) bh_arr_length(s_node->polymorphic_argument_types)) {
+            result = symres_type(&s_node->polymorphic_argument_types[i]);
+            if (result > ss) ss = result;
+
+            if (s_node->polymorphic_arguments[i].value) {
+                result = symres_expression(&s_node->polymorphic_arguments[i].value);
+                if (result > ss) ss = result;
+            }
+        }
+    }
+
     if (s_node->constraints.constraints) {
         bh_arr_each(AstConstraint *, constraint, s_node->constraints.constraints) {
             SYMRES(constraint, *constraint);
@@ -190,19 +205,6 @@ static SymresStatus symres_type(AstType** type) {
             if (pst_node->scope == NULL) {
                 pst_node->scope = scope_create(context.ast_alloc, pst_node->entity->scope, pst_node->token->pos);
             }
-
-            bh_arr_each(AstPolyStructParam, param, pst_node->poly_params) {
-                SYMRES(type, &param->type_node);
-                param->type = type_build_from_ast(context.ast_alloc, param->type_node);
-                if (param->type == NULL) {
-                    if (context.cycle_detected) {
-                        onyx_report_error(param->token->pos, Error_Waiting_On, "Waiting for parameter type to be known.");
-                        return Symres_Error;
-                    } else {
-                        return Symres_Yield_Macro;
-                    }
-                }
-            }
             break;
         }
 
@@ -494,10 +496,6 @@ static SymresStatus symres_expression(AstTyped** expr) {
             // :EliminatingSymres
             SYMRES(type, &builtin_range_type);
             (*expr)->type_node = builtin_range_type;
-
-            // NOTE: This is a weird place to put this so maybe put it somewhere else eventually
-            //                                                  - brendanfh   2020/09/04
-            builtin_range_type_type = type_build_from_ast(context.ast_alloc, builtin_range_type);
             break;
 
         case Ast_Kind_Function:
index 9665af33472d0f5e317421834368e43532a738b4..ec750c46058b8a96de0bbeb34958b085ed74d979 100644 (file)
@@ -337,6 +337,7 @@ Type* type_build_from_ast(bh_allocator alloc, AstType* type_node) {
             AstStructType* s_node = (AstStructType *) type_node;
             if (s_node->stcache != NULL) return s_node->stcache;
             if (s_node->pending_type != NULL && s_node->pending_type_is_valid) return s_node->pending_type;
+            if (!s_node->ready_to_build_type) return NULL;
 
             Type* s_type;
             if (s_node->pending_type == NULL) {
index 2751428409bc118484ff84235deadfc71ef690cd..b080855c161744da4a2a5bceb3bea644d393b08a 100644 (file)
@@ -222,9 +222,12 @@ u64 build_type_table(OnyxWasmModule* module) {
 
                             bh_buffer_grow(&table_buffer, table_buffer.length + size);
                             u8* buffer = table_buffer.data + table_buffer.length;
-                            emit_raw_data(module, buffer, sln->value);
-                            table_buffer.length += size;
-                            break;
+                            if (emit_raw_data_(module, buffer, sln->value)) {
+                                table_buffer.length += size;
+                                break;
+                            }
+
+                            // fallthrough
                         }
 
                         default: {
index c5be6ba68cdd16ce166341c493699443a56ade1a..434e70fb81abb1062f96db87599286d217d0ed49 100644 (file)
@@ -5,7 +5,7 @@ reader :: package core.string.reader
 
 BagGraph :: struct {
     nodes    : [..] ^BagNode;
-    node_map : map.Map(str, #type ^BagNode);
+    node_map : map.Map(str, ^BagNode);
 }
 
 BagNode :: struct {