diff --git a/code/demo.odin b/code/demo.odin index 919b5a0a4..f96fd3cbe 100644 --- a/code/demo.odin +++ b/code/demo.odin @@ -367,7 +367,10 @@ explicit_parametric_polymorphic_procedures :: proc() { } + + main :: proc() { +/* general_stuff(); foreign_blocks(); default_arguments(); @@ -381,6 +384,7 @@ main :: proc() { program := "+ + * - /"; accumulator := 0; +*/ for token in program { match token { diff --git a/core/opengl.odin b/core/opengl.odin index 3dda9dede..4141549c5 100644 --- a/core/opengl.odin +++ b/core/opengl.odin @@ -8,6 +8,8 @@ import ( ) import_load "opengl_constants.odin"; +_ := compile_assert(ODIN_OS != "osx"); + foreign lib { Clear :: proc(mask: u32) #link_name "glClear" ---; ClearColor :: proc(r, g, b, a: f32) #link_name "glClearColor" ---; diff --git a/core/os_x.odin b/core/os_x.odin index a75353797..4ac16aaec 100644 --- a/core/os_x.odin +++ b/core/os_x.odin @@ -8,7 +8,6 @@ import "strings.odin"; Handle :: i32; FileTime :: u64; Errno :: int; -AddressSize :: int; O_RDONLY :: 0x00000; @@ -125,9 +124,9 @@ F_OK :: 0; // Test for file existance foreign libc { unix_open :: proc(path: ^u8, mode: int) -> Handle #link_name "open" ---; unix_close :: proc(handle: Handle) #link_name "close" ---; - unix_read :: proc(handle: Handle, buffer: rawptr, count: int) -> AddressSize #link_name "read" ---; - unix_write :: proc(handle: Handle, buffer: rawptr, count: int) -> AddressSize #link_name "write" ---; - unix_lseek :: proc(fs: Handle, offset: AddressSize, whence: int) -> AddressSize #link_name "lseek" ---; + unix_read :: proc(handle: Handle, buffer: rawptr, count: int) -> int #link_name "read" ---; + unix_write :: proc(handle: Handle, buffer: rawptr, count: int) -> int #link_name "write" ---; + unix_lseek :: proc(fs: Handle, offset: int, whence: int) -> int #link_name "lseek" ---; unix_gettid :: proc() -> u64 #link_name "gettid" ---; unix_stat :: proc(path: ^u8, stat: ^Stat) -> int #link_name "stat" ---; unix_access :: proc(path: ^u8, mask: int) -> int #link_name "access" ---; @@ -168,7 +167,7 @@ close :: proc(fd: Handle) { unix_close(fd); } -write :: proc(fd: Handle, data: []u8) -> (AddressSize, Errno) { +write :: proc(fd: Handle, data: []u8) -> (int, Errno) { assert(fd != -1); bytes_written := unix_write(fd, &data[0], len(data)); @@ -178,7 +177,7 @@ write :: proc(fd: Handle, data: []u8) -> (AddressSize, Errno) { return bytes_written, 0; } -read :: proc(fd: Handle, data: []u8) -> (AddressSize, Errno) { +read :: proc(fd: Handle, data: []u8) -> (int, Errno) { assert(fd != -1); bytes_read := unix_read(fd, &data[0], len(data)); @@ -188,7 +187,7 @@ read :: proc(fd: Handle, data: []u8) -> (AddressSize, Errno) { return bytes_read, 0; } -seek :: proc(fd: Handle, offset: AddressSize, whence: int) -> (AddressSize, Errno) { +seek :: proc(fd: Handle, offset: int, whence: int) -> (int, Errno) { assert(fd != -1); final_offset := unix_lseek(fd, offset, whence); diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 47d7364d8..b27c40148 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -266,12 +266,12 @@ String get_fullpath_core(gbAllocator a, String path) { } - +String const ODIN_VERSION = str_lit("0.6.0-dev"); void init_build_context(void) { BuildContext *bc = &build_context; bc->ODIN_VENDOR = str_lit("odin"); - bc->ODIN_VERSION = str_lit("0.6.0-dev"); + bc->ODIN_VERSION = ODIN_VERSION; bc->ODIN_ROOT = odin_root_dir(); #if defined(GB_SYSTEM_WINDOWS) diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 77f1c2cd7..0826f59ca 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -329,7 +329,16 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) { check_open_scope(c, pl->type); defer (check_close_scope(c)); + #if 0 + if (e->token.string == "sort") { + gb_printf_err("%.*s\n", LIT(e->token.string)); + } + #endif + + bool prev_allow_polymorphic_types = c->context.allow_polymorphic_types; + c->context.allow_polymorphic_types = true; check_procedure_type(c, proc_type, pl->type); + c->context.allow_polymorphic_types = prev_allow_polymorphic_types; bool is_foreign = (pl->tags & ProcTag_foreign) != 0; bool is_link_name = (pl->tags & ProcTag_link_name) != 0; @@ -348,11 +357,11 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) { error(e->token, "Procedure type of `main` was expected to be `proc()`, got %s", str); gb_string_free(str); } - if (proc_type->Proc.calling_convention != ProcCC_Odin && - proc_type->Proc.calling_convention != ProcCC_Contextless) { + if (pt->calling_convention != ProcCC_Odin && + pt->calling_convention != ProcCC_Contextless) { error(e->token, "Procedure `main` cannot have a custom calling convention"); } - proc_type->Proc.calling_convention = ProcCC_Contextless; + pt->calling_convention = ProcCC_Contextless; } if (is_inline && is_no_inline) { @@ -363,7 +372,6 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) { error(pl->type, "A foreign procedure cannot have an `export` tag"); } - if (pt->is_polymorphic) { if (pl->body == NULL) { error(e->token, "Polymorphic procedures must have a body"); @@ -472,9 +480,15 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count } e->flags |= EntityFlag_Visited; + String context_name = str_lit("variable declaration"); + if (type_expr != NULL) { e->type = check_type(c, type_expr); } + if (e->type != NULL && is_type_polymorphic(e->type)) { + error(e->token, "Invalid use of a polymorphic type in %.*s", LIT(context_name)); + e->type = t_invalid; + } if (e->Variable.is_foreign) { @@ -514,7 +528,7 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count GB_ASSERT(entities == NULL || entities[0] == e); Operand operand = {}; check_expr(c, &operand, init_expr); - check_init_variable(c, e, &operand, str_lit("variable declaration")); + check_init_variable(c, e, &operand, context_name); } if (type_expr != NULL) { @@ -527,7 +541,7 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count Array inits; array_init(&inits, c->allocator, 1); array_add(&inits, init_expr); - check_init_variables(c, entities, entity_count, inits, str_lit("variable declaration")); + check_init_variables(c, entities, entity_count, inits, context_name); } void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type) { diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 557b57d8c..98a0614a7 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -1073,14 +1073,105 @@ void check_bit_field_type(Checker *c, Type *bit_field_type, Type *named_type, As } } +bool is_polymorphic_type_assignable(Checker *c, Type *poly, Type *source, bool compound) { + Operand o = {Addressing_Value}; + o.type = source; + switch (poly->kind) { + case Type_Basic: + if (compound) return are_types_identical(poly, source); + return check_is_assignable_to(c, &o, poly); + case Type_Named: + if (compound) return are_types_identical(poly, source); + return check_is_assignable_to(c, &o, poly); + case Type_Generic: { + Type *ds = default_type(source); + gb_memmove(poly, ds, gb_size_of(Type)); + return true; + } + case Type_Pointer: + if (source->kind == Type_Pointer) { + return is_polymorphic_type_assignable(c, poly->Pointer.elem, source->Pointer.elem, true); + } + return false; + case Type_Atomic: + if (source->kind == Type_Atomic) { + return is_polymorphic_type_assignable(c, poly->Atomic.elem, source->Atomic.elem, true); + } + return false; + case Type_Array: + if (source->kind == Type_Array && + poly->Array.count == source->Array.count) { + return is_polymorphic_type_assignable(c, poly->Array.elem, source->Array.elem, true); + } + return false; + case Type_DynamicArray: + if (source->kind == Type_DynamicArray) { + return is_polymorphic_type_assignable(c, poly->DynamicArray.elem, source->DynamicArray.elem, true); + } + return false; + case Type_Vector: + if (source->kind == Type_Vector && + poly->Vector.count == source->Vector.count) { + return is_polymorphic_type_assignable(c, poly->Vector.elem, source->Vector.elem, true); + } + return false; + case Type_Slice: + if (source->kind == Type_Slice) { + return is_polymorphic_type_assignable(c, poly->Slice.elem, source->Slice.elem, true); + } + return false; + case Type_Record: + if (source->kind == Type_Record) { + // TODO(bill): Polymorphic type assignment + } + return false; + case Type_Tuple: + GB_PANIC("This should never happen"); + return false; + case Type_Proc: + if (source->kind == Type_Proc) { + // TODO(bill): Polymorphic type assignment + } + return false; + case Type_Map: + if (source->kind == Type_Map) { + bool key = is_polymorphic_type_assignable(c, poly->Map.key, source->Map.key, true); + bool value = is_polymorphic_type_assignable(c, poly->Map.value, source->Map.value, true); + return key || value; + } + return false; + } + return false; +} + +Type *determine_type_from_polymorphic(Checker *c, Type *poly_type, Operand operand) { + if (!is_operand_value(operand)) { + error(operand.expr, "Cannot determine polymorphic type from parameter"); + return t_invalid; + } + if (is_polymorphic_type_assignable(c, poly_type, operand.type, false)) { + return poly_type; + } + gbString pts = type_to_string(poly_type); + gbString ots = type_to_string(operand.type); + defer (gb_string_free(pts)); + defer (gb_string_free(ots)); + error(operand.expr, + "Cannot determine polymorphic type from parameter: `%s` to `%s`\n" + "\tNote: Record and procedure types are not yet supported", + ots, pts); + return t_invalid; +} Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_variadic_, bool *success_, Array *operands) { if (_params == NULL) { return NULL; } + bool allow_polymorphic_types = c->context.allow_polymorphic_types; + bool success = true; ast_node(field_list, FieldList, _params); Array params = field_list->list; @@ -1123,6 +1214,8 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari bool default_is_nil = false; bool default_is_location = false; bool is_type_param = false; + bool is_type_polymorphic_type = false; + bool detemine_type_from_operand = false; if (type_expr == NULL) { @@ -1157,24 +1250,23 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari if (type_expr->kind == AstNode_HelperType) { is_type_param = true; if (operands != NULL) { - Operand o = (*operands)[variable_index]; - if (o.mode == Addressing_Type) { - type = o.type; - } else { - error(o.expr, "Expected a type to assign to the type parameter"); - type = t_invalid; - success = false; - } + detemine_type_from_operand = true; + type = t_invalid; } else { type = make_type_generic(c->allocator, 0, str_lit("")); } } else { - type = check_type(c, type_expr); - if (p->flags&FieldFlag_dollar) { - error(type_expr, "`$` is only allowed for polymorphic type parameters at the moment"); - type = NULL; + bool prev = c->context.allow_polymorphic_types; + if (operands != NULL) { + c->context.allow_polymorphic_types = true; } + type = check_type(c, type_expr); + c->context.allow_polymorphic_types = prev; + + if (is_type_polymorphic(type)) { + is_type_polymorphic_type = true; + } } if (default_value != NULL) { @@ -1218,12 +1310,7 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari type = t_invalid; } - if (p->flags&FieldFlag_no_alias) { - if (!is_type_pointer(type)) { - error(params[i], "`#no_alias` can only be applied to fields of pointer type"); - p->flags &= ~FieldFlag_no_alias; // Remove the flag - } - } + if (p->flags&FieldFlag_c_vararg) { if (p->type == NULL || p->type->kind != AstNode_Ellipsis) { @@ -1234,19 +1321,44 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari } } + for_array(j, p->names) { AstNode *name = p->names[j]; if (ast_node_expect(name, AstNode_Ident)) { Entity *param = NULL; if (is_type_param) { + if (operands != NULL) { + Operand o = (*operands)[variable_index]; + if (o.mode == Addressing_Type) { + type = o.type; + } else { + error(o.expr, "Expected a type to assign to the type parameter"); + type = t_invalid; + } + } param = make_entity_type_name(c->allocator, scope, name->Ident.token, type); param->TypeName.is_type_alias = true; } else { + if (operands != NULL && is_type_polymorphic_type) { + type = determine_type_from_polymorphic(c, type, (*operands)[variable_index]); + if (type == t_invalid) { + success = false; + } + } + + if (p->flags&FieldFlag_no_alias) { + if (!is_type_pointer(type)) { + error(params[i], "`#no_alias` can only be applied to fields of pointer type"); + p->flags &= ~FieldFlag_no_alias; // Remove the flag + } + } + param = make_entity_param(c->allocator, scope, name->Ident.token, type, (p->flags&FieldFlag_using) != 0, false); param->Variable.default_value = value; param->Variable.default_is_nil = default_is_nil; param->Variable.default_is_location = default_is_location; + } if (p->flags&FieldFlag_no_alias) { param->flags |= EntityFlag_NoAlias; @@ -1629,11 +1741,12 @@ bool check_procedure_type(Checker *c, Type *type, AstNode *proc_type_node, Array if (e->kind != Entity_Variable) { is_polymorphic = true; break; + } else if (is_type_polymorphic(e->type)) { + is_polymorphic = true; + break; } } - if (operands == NULL) { - // GB_ASSERT(type->Proc.is_polymorphic == is_polymorphic); - } + type->Proc.is_polymorphic = is_polymorphic; type->Proc.abi_compat_params = gb_alloc_array(c->allocator, Type *, param_count); @@ -2005,6 +2118,26 @@ bool check_type_internal(Checker *c, AstNode *e, Type **type, Type *named_type) } case_end; + case_ast_node(pt, PolyType, e); + AstNode *ident = pt->type; + if (ident->kind != AstNode_Ident) { + error(ident, "Expected an identifier after the $"); + *type = t_invalid; + return false; + } + + Token token = ident->Ident.token; + Type *t = make_type_generic(c->allocator, 0, token.string); + if (c->context.allow_polymorphic_types) { + Scope *s = c->context.scope; + Entity *e = make_entity_type_name(c->allocator, s, token, t); + e->TypeName.is_type_alias = true; + add_entity(c, s, ident, e); + } + *type = t; + return true; + case_end; + case_ast_node(se, SelectorExpr, e); Operand o = {}; check_selector(c, &o, e, NULL); @@ -2224,13 +2357,14 @@ Type *check_type(Checker *c, AstNode *e, Type *named_type) { } } - // if (is_type_polymorphic(type)) { - if (is_type_poly_proc(type)) { + #if 0 + if (!c->context.allow_polymorphic_types && is_type_polymorphic(type)) { gbString str = type_to_string(type); error(e, "Invalid use of a polymorphic type `%s`", str); gb_string_free(str); type = t_invalid; } + #endif if (is_type_typed(type)) { add_type_and_value(&c->info, e, Addressing_Type, type, empty_exact_value); diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 33cfd3dfa..d197e02d5 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -1717,6 +1717,9 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { init_type = check_type(c, vd->type, NULL); if (init_type == NULL) { init_type = t_invalid; + } else if (is_type_polymorphic(init_type)) { + error(vd->type, "Invalid use of a polymorphic type in variable declaration"); + init_type = t_invalid; } } diff --git a/src/checker.cpp b/src/checker.cpp index 4ad2295f3..abb544ef6 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -261,6 +261,7 @@ struct CheckerContext { DeclInfo * decl; u32 stmt_state_flags; bool in_defer; // TODO(bill): Actually handle correctly + bool allow_polymorphic_types; String proc_name; Type * type_hint; DeclInfo * curr_proc_decl; diff --git a/src/main.cpp b/src/main.cpp index ff562d5c6..9cdf10cc7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -375,7 +375,7 @@ int main(int arg_count, char **arg_ptr) { return 1; #endif } else if (args[1] == "version") { - gb_printf("%.*s version %.*s\n", LIT(args[0]), LIT(build_context.ODIN_VERSION)); + gb_printf("%.*s version %.*s\n", LIT(args[0]), LIT(ODIN_VERSION)); return 0; } else { usage(args[0]); diff --git a/src/parser.cpp b/src/parser.cpp index 7368b81e8..69b77bf2f 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -632,6 +632,10 @@ AstNode *clone_ast_node(gbAllocator a, AstNode *node) { case AstNode_Undef: break; case AstNode_BasicLit: break; case AstNode_BasicDirective: break; + + case AstNode_PolyType: + n->PolyType.type = clone_ast_node(a, n->PolyType.type); + break; case AstNode_Ellipsis: n->Ellipsis.expr = clone_ast_node(a, n->Ellipsis.expr); break; @@ -3259,8 +3263,10 @@ u32 check_field_prefixes(AstFile *f, isize name_count, u32 allowed_flags, u32 se syntax_error(f->curr_token, "`#c_vararg` is not allowed within this field list"); set_flags &= ~FieldFlag_c_vararg; } - if ((allowed_flags&FieldFlag_dollar) == 0 && (set_flags&FieldFlag_dollar)) { - syntax_error(f->curr_token, "`$` is only allowed within procedures"); + // if ((allowed_flags&FieldFlag_dollar) == 0 && (set_flags&FieldFlag_dollar)) { + if ((set_flags&FieldFlag_dollar)) { + // syntax_error(f->curr_token, "`$` is only allowed within procedures"); + syntax_error(f->curr_token, "`$` is not yet supported"); set_flags &= ~FieldFlag_dollar; } return set_flags; diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index 6cfd3e3e5..7b478692e 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -36,27 +36,27 @@ TOKEN_KIND(Token__OperatorBegin, "_OperatorBegin"), \ TOKEN_KIND(Token_CmpAnd, "&&"), \ TOKEN_KIND(Token_CmpOr, "||"), \ \ -TOKEN_KIND(Token__AssignOpBegin, "_AssignOpBegin"), \ - TOKEN_KIND(Token_AddEq, "+="), \ - TOKEN_KIND(Token_SubEq, "-="), \ - TOKEN_KIND(Token_MulEq, "*="), \ - TOKEN_KIND(Token_QuoEq, "/="), \ - TOKEN_KIND(Token_ModEq, "%="), \ - TOKEN_KIND(Token_ModModEq, "%%="), \ - TOKEN_KIND(Token_AndEq, "&="), \ - TOKEN_KIND(Token_OrEq, "|="), \ - TOKEN_KIND(Token_XorEq, "~="), \ - TOKEN_KIND(Token_AndNotEq, "&~="), \ - TOKEN_KIND(Token_ShlEq, "<<="), \ - TOKEN_KIND(Token_ShrEq, ">>="), \ - TOKEN_KIND(Token_CmpAndEq, "&&="), \ - TOKEN_KIND(Token_CmpOrEq, "||="), \ -TOKEN_KIND(Token__AssignOpEnd, "_AssignOpEnd"), \ - TOKEN_KIND(Token_ArrowRight, "->"), \ - TOKEN_KIND(Token_ArrowLeft, "<-"), \ - TOKEN_KIND(Token_Inc, "++"), \ - TOKEN_KIND(Token_Dec, "--"), \ - TOKEN_KIND(Token_Undef, "---"), \ +TOKEN_KIND(Token__AssignOpBegin, "_AssignOpBegin"), \ + TOKEN_KIND(Token_AddEq, "+="), \ + TOKEN_KIND(Token_SubEq, "-="), \ + TOKEN_KIND(Token_MulEq, "*="), \ + TOKEN_KIND(Token_QuoEq, "/="), \ + TOKEN_KIND(Token_ModEq, "%="), \ + TOKEN_KIND(Token_ModModEq, "%%="), \ + TOKEN_KIND(Token_AndEq, "&="), \ + TOKEN_KIND(Token_OrEq, "|="), \ + TOKEN_KIND(Token_XorEq, "~="), \ + TOKEN_KIND(Token_AndNotEq, "&~="), \ + TOKEN_KIND(Token_ShlEq, "<<="), \ + TOKEN_KIND(Token_ShrEq, ">>="), \ + TOKEN_KIND(Token_CmpAndEq, "&&="), \ + TOKEN_KIND(Token_CmpOrEq, "||="), \ +TOKEN_KIND(Token__AssignOpEnd, "_AssignOpEnd"), \ + TOKEN_KIND(Token_ArrowRight, "->"), \ + TOKEN_KIND(Token_ThickArrowRight, "=>"), \ + TOKEN_KIND(Token_Inc, "++"), \ + TOKEN_KIND(Token_Dec, "--"), \ + TOKEN_KIND(Token_Undef, "---"), \ \ TOKEN_KIND(Token__ComparisonBegin, "_ComparisonBegin"), \ TOKEN_KIND(Token_CmpEq, "=="), \ @@ -910,7 +910,16 @@ Token tokenizer_get_token(Tokenizer *t) { case '%': token.kind = token_kind_dub_eq(t, '%', Token_Mod, Token_ModEq, Token_ModMod, Token_ModModEq); break; case '*': token.kind = token_kind_variant2(t, Token_Mul, Token_MulEq); break; - case '=': token.kind = token_kind_variant2(t, Token_Eq, Token_CmpEq); break; + case '=': + token.kind = Token_Eq; + if (t->curr_rune == '>') { + advance_to_next_rune(t); + token.kind = Token_ThickArrowRight; + } else if (t->curr_rune == '=') { + advance_to_next_rune(t); + token.kind = Token_CmpEq; + } + break; case '~': token.kind = token_kind_variant2(t, Token_Xor, Token_XorEq); break; case '!': token.kind = token_kind_variant2(t, Token_Not, Token_NotEq); break; case '+': token.kind = token_kind_variant3(t, Token_Add, Token_AddEq, '+', Token_Inc); break; @@ -967,11 +976,7 @@ Token tokenizer_get_token(Tokenizer *t) { } break; case '<': - if (t->curr_rune == '-') { - token.kind = Token_ArrowLeft; - } else { - token.kind = token_kind_dub_eq(t, '<', Token_Lt, Token_LtEq, Token_Shl, Token_ShlEq); - } + token.kind = token_kind_dub_eq(t, '<', Token_Lt, Token_LtEq, Token_Shl, Token_ShlEq); break; case '>': token.kind = token_kind_dub_eq(t, '>', Token_Gt, Token_GtEq, Token_Shr, Token_ShrEq); break; diff --git a/src/types.cpp b/src/types.cpp index e4c28fed9..d41843ddc 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -944,7 +944,6 @@ bool is_type_indexable(Type *t) { } bool is_type_polymorphic(Type *t) { - t = core_type(t); switch (t->kind) { case Type_Generic: return true; @@ -974,29 +973,36 @@ bool is_type_polymorphic(Type *t) { if (t->Proc.is_polymorphic) { return true; } - // if (t->Proc.param_count > 0 && - // is_type_polymorphic(t->Proc.params)) { - // return true; - // } - // if (t->Proc.result_count > 0 && - // is_type_polymorphic(t->Proc.results)) { - // return true; - // } + #if 0 + if (t->Proc.param_count > 0 && + is_type_polymorphic(t->Proc.params)) { + return true; + } + if (t->Proc.result_count > 0 && + is_type_polymorphic(t->Proc.results)) { + return true; + } + #endif break; - // case Type_Record: - // GB_ASSERT(t->Record.kind != TypeRecord_Enum); - // for (isize i = 0; i < t->Record.field_count; i++) { - // if (is_type_polymorphic(t->Record.fields[i]->type)) { - // return true; - // } - // } - // for (isize i = 1; i < t->Record.variant_count; i++) { - // if (is_type_polymorphic(t->Record.variants[i]->type)) { - // return true; - // } - // } - // break; + case Type_Record: + if (t->Record.kind == TypeRecord_Enum) { + if (t->Record.enum_base_type != NULL) { + return is_type_polymorphic(t->Record.enum_base_type); + } + return false; + } + for (isize i = 0; i < t->Record.field_count; i++) { + if (is_type_polymorphic(t->Record.fields[i]->type)) { + return true; + } + } + for (isize i = 1; i < t->Record.variant_count; i++) { + if (is_type_polymorphic(t->Record.variants[i]->type)) { + return true; + } + } + break; case Type_Map: if (is_type_polymorphic(t->Map.key)) { @@ -2263,7 +2269,13 @@ gbString write_type_to_string(gbString str, Type *type) { break; case Type_Generic: - str = gb_string_appendc(str, "type"); + if (type->Generic.name.len == 0) { + str = gb_string_appendc(str, "type"); + } else { + String name = type->Generic.name; + str = gb_string_appendc(str, "$"); + str = gb_string_append_length(str, name.text, name.len); + } break; case Type_Pointer: