polymorphic structures have compile time known arguments
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Fri, 8 Jan 2021 19:58:28 +0000 (13:58 -0600)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Fri, 8 Jan 2021 19:58:28 +0000 (13:58 -0600)
15 files changed:
bin/onyx
core/map.onyx
include/onyxastnodes.h
include/onyxtypes.h
onyx.exe
src/onyxbuiltins.c
src/onyxchecker.c
src/onyxclone.c
src/onyxparser.c
src/onyxsymres.c
src/onyxtypes.c
src/onyxutils.c
tests/poly_structs_with_values [new file with mode: 0644]
tests/poly_structs_with_values.onyx [new file with mode: 0644]
tests/struct_robustness.onyx

index e532435510a50cb1de385e6d4f565b1bdf2e46da..ab0104e39b578d7e8abbed2657d232d967436051 100755 (executable)
Binary files a/bin/onyx and b/bin/onyx differ
index 74fc99edcb21aed571d7a070c4499468243832ce..5d05c0da2a485dffdf967372d1d0268edad4de20 100644 (file)
@@ -4,7 +4,7 @@ use package core { printf }
 use package core.array as array
 use package core.string as string
 
-Map :: struct ($K, $V) {
+Map :: struct (K: type_expr, V: type_expr) {
     hashes  : [..] i32;
     entries : [..] MapEntry(K, V);
 
@@ -12,10 +12,10 @@ Map :: struct ($K, $V) {
     default_value : V;
 }
 
-MapEntry :: struct ($K, $T) {
+MapEntry :: struct (K: type_expr, V: type_expr) {
     next  : i32;
     key   : K;
-    value : T;
+    value : V;
 }
 
 init :: proc (use map: ^Map($K, $V), dv: V = ~~0, hash_count: i32 = 16) {
index 42485c5a4f5b2be8c52361280708463e391fc3cd..aadbb47a1cf5f0c9489197635b5fb6f37fd9ef91 100644 (file)
@@ -50,6 +50,7 @@ typedef struct AstVarArgType AstVarArgType;
 typedef struct AstStructType AstStructType;
 typedef struct AstStructMember AstStructMember;
 typedef struct AstPolyStructType AstPolyStructType;
+typedef struct AstPolyStructParam AstPolyStructParam;
 typedef struct AstPolyCallType AstPolyCallType;
 typedef struct AstEnumType AstEnumType;
 typedef struct AstEnumValue AstEnumValue;
@@ -630,11 +631,14 @@ struct AstStructMember {
     AstTyped_base;
     AstTyped* initial_value;
 };
+struct AstPolyStructParam {
+    AstTyped_base;
+};
 struct AstPolyStructType {
     AstType_base;
 
     Scope *scope;
-    bh_arr(OnyxToken *) poly_params;
+    bh_arr(AstPolyStructParam) poly_params;
     bh_table(AstStructType *) concrete_structs;
 
     AstStructType* base_struct;
@@ -643,7 +647,9 @@ struct AstPolyCallType {
     AstType_base;
 
     AstType* callee;
-    bh_arr(AstType *) params;
+
+    // NOTE: These nodes can be either AstTypes, or AstTyped expressions.
+    bh_arr(AstNode *) params;
 };
 struct AstEnumType {
     AstType_base;
@@ -745,6 +751,7 @@ struct AstPolyParam {
 };
 
 typedef enum PolySolutionKind {
+    PSK_Undefined,
     PSK_Type,
     PSK_Value,
 } PolySolutionKind;
@@ -905,6 +912,9 @@ extern AstBasicType basic_type_rawptr;
 extern AstBasicType basic_type_int_unsized;
 extern AstBasicType basic_type_float_unsized;
 
+// :TypeExprHack
+extern AstNode type_expr_symbol;
+
 extern AstNode   builtin_package_node;
 extern AstNumLit builtin_heap_start;
 extern AstGlobal builtin_stack_top;
@@ -953,7 +963,7 @@ AstFunction* polymorphic_proc_solidify(AstPolyProc* pp, bh_arr(AstPolySolution)
 AstNode* polymorphic_proc_try_solidify(AstPolyProc* pp, bh_arr(AstPolySolution) slns, OnyxFilePos pos);
 
 
-AstStructType* polymorphic_struct_lookup(AstPolyStructType* ps_type, bh_arr(Type *) params, OnyxFilePos pos);
+AstStructType* polymorphic_struct_lookup(AstPolyStructType* ps_type, bh_arr(AstPolySolution) slns, OnyxFilePos pos);
 
 // NOTE: Useful inlined functions
 static inline b32 is_lval(AstNode* node) {
index 526eddcba536582dd9d1412da67314fa12ab5909..9d95102167cfac6f7cc65a1b2bc9834c7c16d191 100644 (file)
@@ -88,7 +88,7 @@ typedef struct StructMember {
         u16 alignment, mem_count;                                 \
         bh_table(StructMember) members;                           \
         bh_arr(StructMember *) memarr;                            \
-        bh_arr(Type *)         poly_args;                         \
+        bh_arr(struct AstPolySolution) poly_sln;                  \
     })                                                            \
     TYPE_KIND(Array, struct { u32 size; u32 count; Type *elem; }) \
     TYPE_KIND(Slice, struct { Type *ptr_to_data; })               \
index 432a5a5e3ac9fea9dad314b83fdaf55ef0c07c48..4f9b9084d8d6ce6a9af49d11f9910320f30565c6 100644 (file)
Binary files a/onyx.exe and b/onyx.exe differ
index 54b2553f5387287631b2651fad2b4ff51dfb0504..2eb3edc84c4b7a2efdbda3eaac7738a3f58261f6 100644 (file)
@@ -38,6 +38,10 @@ static OnyxToken builtin_stack_top_token  = { Token_Type_Symbol, 11, "__stack_to
 AstNumLit builtin_heap_start  = { Ast_Kind_NumLit, Ast_Flag_Const, &builtin_heap_start_token, NULL, (AstType *) &basic_type_rawptr, NULL, 0 };
 AstGlobal builtin_stack_top   = { Ast_Kind_Global, Ast_Flag_Const | Ast_Flag_Global_Stack_Top,  &builtin_stack_top_token,  NULL, (AstType *) &basic_type_rawptr, NULL };
 
+// :TypeExprHack
+static OnyxToken type_expr_token = { Token_Type_Symbol, 9, "type_expr", { 0 } };
+AstNode type_expr_symbol         = { Ast_Kind_Basic_Type, 0, &type_expr_token, NULL };
+
 AstType  *builtin_string_type;
 AstType  *builtin_range_type;
 Type     *builtin_range_type_type;
@@ -59,6 +63,7 @@ const BuiltinSymbol builtin_symbols[] = {
     { NULL, "f32",        (AstNode *) &basic_type_f32 },
     { NULL, "f64",        (AstNode *) &basic_type_f64 },
     { NULL, "rawptr",     (AstNode *) &basic_type_rawptr },
+    { NULL, "type_expr",  (AstNode *) &type_expr_symbol },
 
     { "simd", "i8x16",    (AstNode *) &basic_type_i8x16 },
     { "simd", "i16x8",    (AstNode *) &basic_type_i16x8 },
index 39428feb27950c04df60bba8d7eb7f775ea7dae0..54f074b2e78736195502579551120acb55ad4edb 100644 (file)
@@ -46,6 +46,8 @@ CheckStatus check_function_header(AstFunction* func);
 CheckStatus check_memres_type(AstMemRes* memres);
 CheckStatus check_memres(AstMemRes* memres);
 
+static inline void fill_in_type(AstTyped* node);
+
 static inline void fill_in_array_count(AstType* type_node) {
     if (type_node == NULL) return;
 
@@ -61,8 +63,24 @@ static inline void fill_in_array_count(AstType* type_node) {
     }
 }
 
+static inline void fill_in_poly_call_args(AstType* type_node) {
+    if (type_node == NULL) return;
+    if (type_node->kind != Ast_Kind_Poly_Call_Type) return;
+
+    AstPolyCallType* pctype = (AstPolyCallType *) type_node;
+
+    bh_arr_each(AstNode *, param, pctype->params) {
+        if (!node_is_type(*param)) {
+            check_expression((AstTyped **) param);
+            resolve_expression_type((AstTyped *) *param);
+            fill_in_type((AstTyped *) *param);
+        }
+    }
+}
+
 static inline void fill_in_type(AstTyped* node) {
     fill_in_array_count(node->type_node);
+    fill_in_poly_call_args(node->type_node);
 
     if (node->type == NULL)
         node->type = type_build_from_ast(semstate.allocator, node->type_node);
@@ -952,7 +970,7 @@ CheckStatus check_struct_literal(AstStructLiteral* sl) {
             token_toggle_end((*smem)->token);
 
             if (s.included_through_use) {
-                onyx_report_error((*smem)->token->pos, "Cannot specify value for member '%s', whic was included through a 'use' statement.", s.name);
+                onyx_report_error((*smem)->token->pos, "Cannot specify value for member '%s', which was included through a 'use' statement.", s.name);
                 return Check_Error;
             }
 
@@ -969,7 +987,7 @@ CheckStatus check_struct_literal(AstStructLiteral* sl) {
                 u32 idx = (*smem)->idx;
 
                 if (sl->values[idx] == NULL) {
-                    if ((*smem)->initial_value == NULL) {
+                    if (*(*smem)->initial_value == NULL) {
                         onyx_report_error(sl->token->pos, "No value was given for the field '%s'.", (*smem)->name);
                         return Check_Error;
                     }
index 85d7186330efb0a39031bc8517c48ee5d5bc1000..9d04ebe611626547c83314bd6bb255e359e6e5ce 100644 (file)
@@ -335,8 +335,8 @@ AstNode* ast_clone(bh_allocator a, void* n) {
             pcd->params = NULL;
             bh_arr_new(global_heap_allocator, pcd->params, bh_arr_length(pcs->params));
 
-            bh_arr_each(AstType *, param, pcs->params) {
-                bh_arr_push(pcd->params, (AstType *) ast_clone(a, *param));
+            bh_arr_each(AstNode *, param, pcs->params) {
+                bh_arr_push(pcd->params, ast_clone(a, *param));
             }
 
             break;
index 9af7c208af2fb598f69a8e8a470ac65212541680..a35f11b33beaa000dbe8dc8d90d78d3bdf6495f1 100644 (file)
@@ -1515,13 +1515,13 @@ static AstType* parse_type(OnyxParser* parser) {
             if (parser->curr->type == '(') {
                 OnyxToken* paren_token = expect_token(parser, '(');
 
-                bh_arr(AstType *) params = NULL;
+                bh_arr(AstNode *) params = NULL;
                 bh_arr_new(global_heap_allocator, params, 2);
 
                 while (parser->curr->type != ')') {
                     if (parser->hit_unexpected_token) break;
 
-                    AstType* t = parse_type(parser);
+                    AstNode* t = (AstNode *) parse_type(parser);
                     bh_arr_push(params, t);
 
                     if (parser->curr->type != ')')
@@ -1587,15 +1587,22 @@ static AstStructType* parse_struct(OnyxParser* parser) {
     if (parser->curr->type == '(') {
         consume_token(parser);
 
-        bh_arr(OnyxToken *) poly_params = NULL;
+        bh_arr(AstPolyStructParam) poly_params = NULL;
         bh_arr_new(global_heap_allocator, poly_params, 1);
 
-        while (parser->curr->type == '$') {
-            consume_token(parser);
+        while (parser->curr->type != ')') {
             if (parser->hit_unexpected_token) return NULL;
 
             OnyxToken* sym_token = expect_token(parser, Token_Type_Symbol);
-            bh_arr_push(poly_params, sym_token);
+            expect_token(parser, ':');
+
+            AstType* param_type = parse_type(parser);
+
+            bh_arr_push(poly_params, ((AstPolyStructParam) {
+                .token = sym_token,
+                .type_node = param_type,
+                .type = NULL, 
+            }));
 
             if (parser->curr->type != ')')
                 expect_token(parser, ',');
index 4ae95bfe080cc7e643a50a4600a5ec1e5cce278b..3f9feb93240e2397d8ef4190f9ca6f9acaaf7e65 100644 (file)
@@ -192,6 +192,11 @@ AstType* symres_type(AstType* type) {
         AstPolyStructType* pst_node = (AstPolyStructType *) type;
         pst_node->scope = scope_create(semstate.node_allocator, semstate.curr_scope, pst_node->token->pos);
 
+        bh_arr_each(AstPolyStructParam, param, pst_node->poly_params) {
+            param->type_node = symres_type(param->type_node);
+            param->type      = type_build_from_ast(semstate.node_allocator, param->type_node);
+        }
+
         return type;
     }
 
@@ -200,8 +205,12 @@ AstType* symres_type(AstType* type) {
 
         pc_node->callee = symres_type(pc_node->callee);
 
-        bh_arr_each(AstType *, param, pc_node->params) {
-            *param = symres_type(*param);
+        bh_arr_each(AstNode *, param, pc_node->params) {
+            if (node_is_type(*param)) {
+                *param = (AstNode *) symres_type((AstType *) *param);
+            } else {
+                symres_expression((AstTyped **) param);
+            }
         }
 
         return type;
@@ -814,28 +823,13 @@ static void symres_memres(AstMemRes** memres) {
 }
 
 static void symres_struct_defaults(AstType* t) {
-    switch (t->kind) {
-        case Ast_Kind_Struct_Type: {
-            AstStructType* st = (AstStructType *) t;
-            bh_arr_each(AstStructMember *, smem, st->members) {
-                if ((*smem)->initial_value != NULL) {
-                    symres_expression(&(*smem)->initial_value);
-                }
-            }
-            break;
-        }
-
-        case Ast_Kind_Poly_Struct_Type: {
-            AstPolyStructType* st = (AstPolyStructType *) t;
-            bh_arr_each(AstStructMember *, smem, st->base_struct->members) {
-                if ((*smem)->initial_value != NULL) {
-                    symres_expression(&(*smem)->initial_value);
-                }
-            }
-            break;
+    if (t->kind != Ast_Kind_Struct_Type) return;
+    
+    AstStructType* st = (AstStructType *) t;
+    bh_arr_each(AstStructMember *, smem, st->members) {
+        if ((*smem)->initial_value != NULL) {
+            symres_expression(&(*smem)->initial_value);
         }
-
-        default: break;
     }
 }
 
index e23f163e0e97821bc045143aaf14bb2eb7f549a2..5eaea9259ac12e05e8d804d80b441ea26ac9435b 100644 (file)
@@ -475,15 +475,27 @@ Type* type_build_from_ast(bh_allocator alloc, AstType* type_node) {
 
             AstPolyStructType* ps_type = (AstPolyStructType *) pc_type->callee;
 
-            bh_arr(Type *) param_types = NULL;
-            bh_arr_new(global_heap_allocator, param_types, bh_arr_length(pc_type->params));
-            bh_arr_each(AstType *, ptype, pc_type->params) {
-                bh_arr_push(param_types, type_build_from_ast(alloc, *ptype));
+            bh_arr(AstPolySolution) slns = NULL;
+            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)) {
+                    bh_arr_push(slns, ((AstPolySolution) {
+                        .kind     = PSK_Type,
+                        .type     = type_build_from_ast(alloc, (AstType *) *given),
+                    }));
+                } else {
+                    bh_arr_push(slns, ((AstPolySolution) {
+                        .kind  = PSK_Value,
+                        .value = (AstTyped *) *given,
+                    }));
+                }
             }
 
-            AstStructType* concrete = polymorphic_struct_lookup(ps_type, param_types, pc_type->token->pos);
+            AstStructType* concrete = polymorphic_struct_lookup(ps_type, slns, pc_type->token->pos);
 
-            bh_arr_free(param_types);
+            // This should be copied in the previous function.
+            // CLEANUP: Maybe don't copy it and just use this one since it is allocated on the heap?
+            bh_arr_free(slns);
 
             return type_build_from_ast(alloc, (AstType *) concrete);
         }
index aa9b4f374a3076cb5a61bd52f554deae47d7365c..1813e98a45999062ec94a749abb8a5d55c3fd678 100644 (file)
@@ -450,10 +450,11 @@ static PolySolveResult solve_poly_type(AstNode* target, AstType* type_expr, Type
     bh_arr(PolySolveElem) elem_queue = NULL;
     bh_arr_new(global_heap_allocator, elem_queue, 4);
 
-    PolySolveResult result = { -1, { NULL } };
+    PolySolveResult result = { PSK_Undefined, { NULL } };
 
     bh_arr_push(elem_queue, ((PolySolveElem) {
         .type_expr = type_expr,
+        .kind = PSK_Type,
         .actual    = actual
     }));
 
@@ -463,11 +464,10 @@ static PolySolveResult solve_poly_type(AstNode* target, AstType* type_expr, Type
 
         if (elem.type_expr == (AstType *) target) {
             result.kind = elem.kind;
-            if (result.kind == PSK_Type) {
-                result.actual = elem.actual;
-            } else {
-                result.value = elem.value;
-            }
+
+            assert(elem.kind != PSK_Undefined);
+            if (result.kind == PSK_Type)  result.actual = elem.actual;
+            if (result.kind == PSK_Value) result.value = elem.value;
             break;
         }
 
@@ -556,16 +556,25 @@ static PolySolveResult solve_poly_type(AstNode* target, AstType* type_expr, Type
 
             case Ast_Kind_Poly_Call_Type: {
                 if (elem.actual->kind != Type_Kind_Struct) break;
-                if (bh_arr_length(elem.actual->Struct.poly_args) != bh_arr_length(((AstPolyCallType *) elem.type_expr)->params)) break;
+                if (bh_arr_length(elem.actual->Struct.poly_sln) != bh_arr_length(((AstPolyCallType *) elem.type_expr)->params)) break;
 
                 AstPolyCallType* pt = (AstPolyCallType *) elem.type_expr;
 
                 fori (i, 0, bh_arr_length(pt->params)) {
-                    bh_arr_push(elem_queue, ((PolySolveElem) {
-                        .type_expr = pt->params[i],
-                        .kind = PSK_Type,
-                        .actual = elem.actual->Struct.poly_args[i],
-                    }));
+                    PolySolutionKind kind = elem.actual->Struct.poly_sln[i].kind;
+                    if (kind == PSK_Type) {
+                        bh_arr_push(elem_queue, ((PolySolveElem) {
+                            .kind = kind,
+                            .type_expr = (AstType *) pt->params[i],
+                            .actual = elem.actual->Struct.poly_sln[i].type,
+                        }));
+                    } else {
+                        bh_arr_push(elem_queue, ((PolySolveElem) {
+                            .kind = kind,
+                            .type_expr = (AstType *) pt->params[i],
+                            .value = elem.actual->Struct.poly_sln[i].value,
+                        }));
+                    }
                 }
 
                 break;
@@ -630,7 +639,7 @@ AstFunction* polymorphic_proc_lookup(AstPolyProc* pp, PolyProcLookupMethod pp_lo
         PolySolveResult resolved = solve_poly_type(param->poly_sym, param->type_expr, actual_type);
 
         switch (resolved.kind) {
-            case -1:
+            case PSK_Undefined:
                 onyx_report_error(pos,
                     "Unable to solve for polymoprhic variable '%b', using the type '%s'.",
                     param->poly_sym->token->text,
@@ -691,7 +700,7 @@ static char* build_poly_solution_key(AstPolySolution* sln) {
 }
 
 // NOTE: This returns a volatile string. Do not store it without copying it.
-static char* build_polyproc_unique_key(bh_arr(AstPolySolution) slns) {
+static char* build_poly_slns_unique_key(bh_arr(AstPolySolution) slns) {
     static char key_buf[1024];
     fori (i, 0, 1024) key_buf[i] = 0;
 
@@ -715,7 +724,7 @@ AstFunction* polymorphic_proc_solidify(AstPolyProc* pp, bh_arr(AstPolySolution)
     }
 
     // NOTE: Check if a version of this polyproc has already been created.
-    char* unique_key = build_polyproc_unique_key(slns);
+    char* unique_key = build_poly_slns_unique_key(slns);
     if (bh_table_has(AstFunction *, pp->concrete_funcs, unique_key)) {
         return bh_table_get(AstFunction *, pp->concrete_funcs, unique_key);
     }
@@ -826,81 +835,160 @@ AstNode* polymorphic_proc_try_solidify(AstPolyProc* pp, bh_arr(AstPolySolution)
     }
 }
 
+char* build_poly_struct_name(AstPolyStructType* ps_type, Type* cs_type) {
+    char name_buf[256];
+    fori (i, 0, 256) name_buf[i] = 0;
+
+    strncat(name_buf, ps_type->name, 255);
+    strncat(name_buf, "(", 255);
+    bh_arr_each(AstPolySolution, ptype, cs_type->Struct.poly_sln) {
+        if (ptype != cs_type->Struct.poly_sln)
+            strncat(name_buf, ", ", 255);
+
+        // This logic will have to be other places as well.
+
+        switch (ptype->kind) {
+            case PSK_Undefined: assert(0); break;
+            case PSK_Type:      strncat(name_buf, type_get_name(ptype->type), 255); break;
+            case PSK_Value: {
+                // FIX
+                if (ptype->value->kind == Ast_Kind_NumLit) {
+                    AstNumLit* nl = (AstNumLit *) ptype->value;
+                    if (type_is_integer(nl->type)) {
+                        strncat(name_buf, bh_bprintf("%l", nl->value.l), 127);
+                    } else {
+                        strncat(name_buf, "numlit (FIX ME)", 127);
+                    }
+                } else {
+                    strncat(name_buf, "<expr>", 127);
+                }
+
+                break;
+            }
+        }
+    }
+    strncat(name_buf, ")", 255);
+
+    return bh_aprintf(global_heap_allocator, "%s", name_buf);
+}
 
-AstStructType* polymorphic_struct_lookup(AstPolyStructType* ps_type, bh_arr(Type *) params, OnyxFilePos pos) {
+AstStructType* polymorphic_struct_lookup(AstPolyStructType* ps_type, bh_arr(AstPolySolution) slns, OnyxFilePos pos) {
     // @Cleanup
-    assert(bh_arr_length(ps_type->poly_params) == bh_arr_length(params));
     assert(ps_type->scope != NULL);
 
     if (ps_type->concrete_structs == NULL) {
         bh_table_init(global_heap_allocator, ps_type->concrete_structs, 16);
     }
 
-    scope_clear(ps_type->scope);
+    if (bh_arr_length(slns) < bh_arr_length(ps_type->poly_params)) {
+        onyx_report_error(pos, "Not enough arguments for polymorphic struct creation. Expected %d, got %d",
+            bh_arr_length(ps_type->poly_params),
+            bh_arr_length(slns));
 
-    fori (i, 0, bh_arr_length(ps_type->poly_params)) {
-        if (params[i] == NULL) {
-            onyx_report_error((OnyxFilePos) { 0 }, "Type parameter is not a type.");
-            return NULL;
+        return NULL;
+    }
+
+    i32 i = 0;
+    bh_arr_each(AstPolySolution, sln, slns) {
+        PolySolutionKind expected_kind = PSK_Undefined;
+        if ((AstNode *) ps_type->poly_params[i].type_node == &type_expr_symbol) {
+            expected_kind = PSK_Type;
+        } else {
+            expected_kind = PSK_Value;
         }
 
-        AstTypeRawAlias* raw = onyx_ast_node_new(semstate.node_allocator, sizeof(AstTypeRawAlias), Ast_Kind_Type_Raw_Alias);
-        raw->to = params[i];
+        if (sln->kind != expected_kind) {
+            if (expected_kind == PSK_Type) 
+                onyx_report_error(pos, "Expected type expression for %d%s argument.", i + 1, bh_num_suffix(i + 1));
 
-        symbol_introduce(ps_type->scope, ps_type->poly_params[i], (AstNode *) raw);
-    }
+            if (expected_kind == PSK_Value)
+                onyx_report_error(pos, "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));
 
-    char key_buf[1024];
-    fori (i, 0, 1024) key_buf[i] = 0;
-    bh_table_each_start(AstNode *, ps_type->scope->symbols);
-        strncat(key_buf, key, 1023);
-        strncat(key_buf, "=", 1023);
-        strncat(key_buf, type_get_unique_name(((AstTypeRawAlias *) value)->to), 1023);
-        strncat(key_buf, ";", 1023);
-    bh_table_each_end;
+            return NULL;
+        }
+
+        if (sln->kind == PSK_Value) {
+            if ((sln->value->flags & Ast_Flag_Comptime) == 0) {
+                onyx_report_error(pos,
+                    "Expected compile-time known argument for '%b'.",
+                    sln->poly_sym->token->text,
+                    sln->poly_sym->token->length);
+                return NULL;
+            }
 
-    if (bh_table_has(AstStructType *, ps_type->concrete_structs, key_buf)) {
-        return bh_table_get(AstStructType *, ps_type->concrete_structs, key_buf);
+            if (!types_are_compatible(sln->value->type, ps_type->poly_params[i].type)) {
+                onyx_report_error(pos, "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;
+            }
+        }
+
+        sln->poly_sym = (AstNode *) &ps_type->poly_params[i];
+        i++;
     }
 
-    AstStructType* concrete_struct = (AstStructType *) ast_clone(semstate.node_allocator, ps_type->base_struct);
+    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);
+    }
 
-    Scope* old_scope = semstate.curr_scope;
-    semstate.curr_scope = ps_type->scope;
-    concrete_struct = (AstStructType *) symres_type((AstType *) concrete_struct);
-    semstate.curr_scope = old_scope;
+    scope_clear(ps_type->scope);
 
-    if (onyx_has_errors()) goto has_error;
-    goto no_errors;
+    bh_arr_each(AstPolySolution, sln, slns) {
+        AstNode *node = NULL;
+        
+        switch (sln->kind) {
+            case PSK_Type:
+                node = onyx_ast_node_new(semstate.node_allocator, sizeof(AstTypeRawAlias), Ast_Kind_Type_Raw_Alias);
+                ((AstTypeRawAlias *) node)->to = sln->type;
+                break;
 
-has_error:
-    // onyx_report_error(pos, "Error in polymorphic struct generated from this call site.");
-    return NULL;
+            case PSK_Value:
+                // CLEANUP: Maybe clone this?
+                node = (AstNode *) sln->value;
+                break;
+        }
 
-no_errors:
-    bh_table_put(AstStructType *, ps_type->concrete_structs, key_buf, concrete_struct);
+        symbol_introduce(ps_type->scope, sln->poly_sym->token, node);
+    }
 
-    Type* cs_type = type_build_from_ast(semstate.node_allocator, (AstType *) concrete_struct);
+    AstStructType* concrete_struct = (AstStructType *) ast_clone(semstate.node_allocator, ps_type->base_struct);
 
-    cs_type->Struct.poly_args = NULL;
-    bh_arr_new(global_heap_allocator, cs_type->Struct.poly_args, bh_arr_length(params));
+    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,
+    };
 
-    fori (i, 0, bh_arr_length(params)) bh_arr_push(cs_type->Struct.poly_args, params[i]);
+    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 polymoprhic struct instantiation here.");
+        return NULL;
+    }
 
-    char name_buf[256];
-    fori (i, 0, 256) name_buf[i] = 0;
+    bh_table_put(AstStructType *, ps_type->concrete_structs, unique_key, concrete_struct);
 
-    strncat(name_buf, ps_type->name, 255);
-    strncat(name_buf, "(", 255);
-    bh_arr_each(Type *, ptype, cs_type->Struct.poly_args) {
-        if (ptype != cs_type->Struct.poly_args)
-            strncat(name_buf, ", ", 255);
+    Type* cs_type = type_build_from_ast(semstate.node_allocator, (AstType *) concrete_struct);
+    cs_type->Struct.poly_sln = NULL;
+    bh_arr_new(global_heap_allocator, cs_type->Struct.poly_sln, bh_arr_length(slns));
 
-        strncat(name_buf, type_get_name(*ptype), 255);
-    }
-    strncat(name_buf, ")", 255);
-    cs_type->Struct.name = bh_aprintf(semstate.node_allocator, "%s", name_buf);
+    fori (i, 0, bh_arr_length(slns)) bh_arr_push(cs_type->Struct.poly_sln, slns[i]);
 
+    cs_type->Struct.name = build_poly_struct_name(ps_type, cs_type);
     return concrete_struct;
 }
 
diff --git a/tests/poly_structs_with_values b/tests/poly_structs_with_values
new file mode 100644 (file)
index 0000000..3d8fae7
--- /dev/null
@@ -0,0 +1,6 @@
+12345
+12345
+12345
+12345
+1234
+Hello World!
diff --git a/tests/poly_structs_with_values.onyx b/tests/poly_structs_with_values.onyx
new file mode 100644 (file)
index 0000000..38eb53e
--- /dev/null
@@ -0,0 +1,27 @@
+#load "core/std/js"
+
+use package core
+
+main :: proc (args: [] cstr) {
+
+    NewPolyStruct :: struct (T: type_expr, N: i32) {
+        x : [N] T; 
+        y : [N] f32;
+    }
+
+    nps : NewPolyStruct(i32, #value 4);
+
+    for ^x: nps.x do *x = 12345;
+    for ^y: nps.y do *y = 67890;
+
+    for x: nps.x do println(x);
+
+    SimpleWithDefault :: struct (T: type_expr, default: str) {
+        x : T;
+        str_member : str = default; 
+    }
+
+    swd := <SimpleWithDefault(i32, #value "Hello World!")>.{ x = 1234 };
+    println(swd.x);
+    println(swd.str_member);
+}
\ No newline at end of file
index 2e3872a05b1bad8369b0cb50b690978ca5900a0f..4e75fb46de95d739aaca2e260eb948852a7cf631 100644 (file)
@@ -105,7 +105,7 @@ main :: proc (args: [] cstr) {
     test_polymorphic :: proc () {
         println("\n\nTesting a polymorphic struct.");
 
-        PolyStruct :: struct ($T, $R) {
+        PolyStruct :: struct (T: type_expr, R: type_expr) {
             t_data : T;
             r_data : R;
         }
@@ -124,7 +124,7 @@ main :: proc (args: [] cstr) {
     test_polymorphic_with_defaults :: proc () {
         println("\n\nTesting a polymorphic struct with default values.");
 
-        PolyStruct :: struct ($T, $R) {
+        PolyStruct :: struct (T: type_expr, R: type_expr) {
             t_data : T = 1234;
             r_data : R = 5678;
         }
@@ -138,7 +138,7 @@ main :: proc (args: [] cstr) {
     test_polymorphic_union_with_use :: proc () {
         println("\n\nTesting a polymorphic union with use.");
 
-        PolyStruct :: struct ($T, $R) {
+        PolyStruct :: struct (T: type_expr, R: type_expr) {
             use container : struct #union {
                 t_data : T;
                 r_data : R;
@@ -178,7 +178,7 @@ main :: proc (args: [] cstr) {
     test_polymorphic_union :: proc () {
         println("\n\nTesting a polymorphic union.");
 
-        PolyUnion :: struct ($T, $R) #union {
+        PolyUnion :: struct (T: type_expr, R: type_expr) #union {
             t_data : T;
             r_data : R;
         }