diff --git a/code/demo.odin b/code/demo.odin index a2d888a09..962b25db1 100644 --- a/code/demo.odin +++ b/code/demo.odin @@ -2,7 +2,15 @@ import ( "fmt.odin"; ) +proc new_type(T: type) -> ^T { + return ^T(alloc_align(size_of(T), align_of(T))); +} + proc main() { + var ptr = new_type(int); +} + +/* let program = "+ + * - /"; var accumulator = 0; @@ -18,4 +26,5 @@ proc main() { fmt.printf("The program \"%s\" calculates the value %d\n", program, accumulator); +*/ } diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 4e2dc2e36..6696af6a4 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -1030,7 +1030,7 @@ void check_bit_field_type(Checker *c, Type *bit_field_type, Type *named_type, As -Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_variadic_) { +Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_variadic_, Array *operands) { if (_params == NULL) { return NULL; } @@ -1041,6 +1041,11 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari return NULL; } + if (operands != NULL) { + GB_ASSERT(operands->count == params.count); + } + + isize variable_count = 0; for_array(i, params) { AstNode *field = params[i]; @@ -1096,32 +1101,45 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari } } if (type_expr->kind == AstNode_HelperType) { - type = make_type_generic(c->allocator, 0); + if (operands != NULL) { + Operand o = (*operands)[i]; + if (o.mode == Addressing_Type) { + type = o.type; + } else { + error(o.expr, "Expected a type to assign to a type parameter"); + } + } else { + type = make_type_generic(c->allocator, 0); + } } else { type = check_type(c, type_expr); } if (default_value != NULL) { - Operand o = {}; - if (default_value->kind == AstNode_BasicDirective && - default_value->BasicDirective.name == "caller_location") { - init_preload(c); - default_is_location = true; - o.type = t_source_code_location; - o.mode = Addressing_Value; + if (type_expr->kind == AstNode_HelperType) { + error(default_value, "A type parameter may not have a default value"); } else { - check_expr_with_type_hint(c, &o, default_value, type); - - if (is_operand_nil(o)) { - default_is_nil = true; - } else if (o.mode != Addressing_Constant) { - error(default_value, "Default parameter must be a constant"); + Operand o = {}; + if (default_value->kind == AstNode_BasicDirective && + default_value->BasicDirective.name == "caller_location") { + init_preload(c); + default_is_location = true; + o.type = t_source_code_location; + o.mode = Addressing_Value; } else { - value = o.value; - } - } + check_expr_with_type_hint(c, &o, default_value, type); - check_is_assignable_to(c, &o, type); + if (is_operand_nil(o)) { + default_is_nil = true; + } else if (o.mode != Addressing_Constant) { + error(default_value, "Default parameter must be a constant"); + } else { + value = o.value; + } + } + + check_is_assignable_to(c, &o, type); + } } } @@ -1154,7 +1172,13 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari AstNode *name = p->names[j]; if (ast_node_expect(name, AstNode_Ident)) { Entity *param = NULL; - if (type->kind == Type_Generic) { + bool is_generic = type->kind == Type_Generic; + if (operands != NULL) { + Operand o = (*operands)[j]; + is_generic = o.mode == Addressing_Type && o.type == type; + } + + if (is_generic) { param = make_entity_type_name(c->allocator, scope, name->Ident, type); } else { param = make_entity_param(c->allocator, scope, name->Ident, type, @@ -1497,11 +1521,12 @@ bool abi_compat_return_by_value(gbAllocator a, ProcCallingConvention cc, Type *a return false; } -void check_procedure_type(Checker *c, Type *type, AstNode *proc_type_node) { +// NOTE(bill): `operands` is for generating non generic procedure type +void check_procedure_type(Checker *c, Type *type, AstNode *proc_type_node, Array *operands = NULL) { ast_node(pt, ProcType, proc_type_node); bool variadic = false; - Type *params = check_get_params(c, c->context.scope, pt->params, &variadic); + Type *params = check_get_params(c, c->context.scope, pt->params, &variadic, operands); Type *results = check_get_results(c, c->context.scope, pt->results); isize param_count = 0; @@ -1509,6 +1534,7 @@ void check_procedure_type(Checker *c, Type *type, AstNode *proc_type_node) { if (params) param_count = params ->Tuple.variable_count; if (results) result_count = results->Tuple.variable_count; + type->Proc.node = proc_type_node; type->Proc.scope = c->context.scope; type->Proc.params = params; type->Proc.param_count = param_count; @@ -1541,14 +1567,19 @@ void check_procedure_type(Checker *c, Type *type, AstNode *proc_type_node) { is_generic = true; } } - GB_ASSERT(type->Proc.is_generic == is_generic); + if (operands == NULL) { + GB_ASSERT(type->Proc.is_generic == is_generic); + } type->Proc.abi_compat_params = gb_alloc_array(c->allocator, Type *, param_count); for (isize i = 0; i < param_count; i++) { - Type *original_type = type->Proc.params->Tuple.variables[i]->type; - Type *new_type = type_to_abi_compat_param_type(c->allocator, original_type); - type->Proc.abi_compat_params[i] = new_type; + Entity *e = type->Proc.params->Tuple.variables[i]; + if (e->kind == Entity_Variable) { + Type *original_type = e->type; + Type *new_type = type_to_abi_compat_param_type(c->allocator, original_type); + type->Proc.abi_compat_params[i] = new_type; + } } // NOTE(bill): The types are the same @@ -4829,6 +4860,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id enum CallArgumentError { CallArgumentError_None, + CallArgumentError_NoneProcedureType, CallArgumentError_WrongTypes, CallArgumentError_NonVariadicExpand, CallArgumentError_VariadicTuple, @@ -4902,23 +4934,28 @@ bool check_unpack_arguments(Checker *c, isize lhs_count, Array *operand return optional_ok; } -#define CALL_ARGUMENT_CHECKER(name) CallArgumentError name(Checker *c, AstNode *call, Type *proc_type, Array operands, CallArgumentErrorMode show_error_mode, i64 *score_) +#define CALL_ARGUMENT_CHECKER(name) CallArgumentError name(Checker *c, AstNode *call, Type *proc_type, Array operands, CallArgumentErrorMode show_error_mode, i64 *score_, Type **result_type_) typedef CALL_ARGUMENT_CHECKER(CallArgumentCheckerType); CALL_ARGUMENT_CHECKER(check_call_arguments_internal) { ast_node(ce, CallExpr, call); + GB_ASSERT(is_type_proc(proc_type)); + proc_type = base_type(proc_type); + TypeProc *pt = &proc_type->Proc; + isize param_count = 0; isize param_count_excluding_defaults = 0; - bool variadic = proc_type->Proc.variadic; + bool variadic = pt->variadic; bool vari_expand = (ce->ellipsis.pos.line != 0); i64 score = 0; bool show_error = show_error_mode == CallArgumentMode_ShowErrors; + TypeTuple *param_tuple = NULL; - if (proc_type->Proc.params != NULL) { - param_tuple = &proc_type->Proc.params->Tuple; + if (pt->params != NULL) { + param_tuple = &pt->params->Tuple; param_count = param_tuple->variable_count; if (variadic) { @@ -4945,120 +4982,126 @@ CALL_ARGUMENT_CHECKER(check_call_arguments_internal) { } } + CallArgumentError err = CallArgumentError_None; + Type *final_proc_type = proc_type; + if (vari_expand && !variadic) { if (show_error) { error(ce->ellipsis, "Cannot use `..` in call to a non-variadic procedure: `%.*s`", LIT(ce->proc->Ident.string)); } - if (score_) *score_ = score; - return CallArgumentError_NonVariadicExpand; - } - if (vari_expand && proc_type->Proc.c_vararg) { + err = CallArgumentError_NonVariadicExpand; + } else if (vari_expand && pt->c_vararg) { if (show_error) { error(ce->ellipsis, "Cannot use `..` in call to a `#c_vararg` variadic procedure: `%.*s`", LIT(ce->proc->Ident.string)); } - if (score_) *score_ = score; - return CallArgumentError_NonVariadicExpand; - } - - if (operands.count == 0 && param_count_excluding_defaults == 0) { - if (score_) *score_ = score; - return CallArgumentError_None; - } - - i32 error_code = 0; - if (operands.count < param_count_excluding_defaults) { - error_code = -1; - } else if (!variadic && operands.count > param_count) { - error_code = +1; - } - if (error_code != 0) { - CallArgumentError err = CallArgumentError_TooManyArguments; - char *err_fmt = "Too many arguments for `%s`, expected %td arguments"; - if (error_code < 0) { - err = CallArgumentError_TooFewArguments; - err_fmt = "Too few arguments for `%s`, expected %td arguments"; + err = CallArgumentError_NonVariadicExpand; + } else if (operands.count == 0 && param_count_excluding_defaults == 0) { + err = CallArgumentError_None; + } else { + i32 error_code = 0; + if (operands.count < param_count_excluding_defaults) { + error_code = -1; + } else if (!variadic && operands.count > param_count) { + error_code = +1; } - - if (show_error) { - gbString proc_str = expr_to_string(ce->proc); - error(call, err_fmt, proc_str, param_count_excluding_defaults); - gb_string_free(proc_str); - } - if (score_) *score_ = score; - return err; - } - - CallArgumentError err = CallArgumentError_None; - - - GB_ASSERT(proc_type->Proc.params != NULL); - Entity **sig_params = param_tuple->variables; - isize operand_index = 0; - isize max_operand_count = gb_min(param_count, operands.count); - for (; operand_index < max_operand_count; operand_index++) { - Entity *e = sig_params[operand_index]; - Type *t = e->type; - Operand o = operands[operand_index]; - if (e->kind == Entity_TypeName) { - GB_ASSERT(proc_type->Proc.is_generic); - GB_ASSERT(!variadic); - if (o.mode == Addressing_Invalid) { - continue; - } else if (o.mode != Addressing_Type) { - error(o.expr, "Expected a type for the argument"); + if (error_code != 0) { + err = CallArgumentError_TooManyArguments; + char *err_fmt = "Too many arguments for `%s`, expected %td arguments"; + if (error_code < 0) { + err = CallArgumentError_TooFewArguments; + err_fmt = "Too few arguments for `%s`, expected %td arguments"; } - score += assign_score_function(1); - continue; - } - if (variadic) { - o = operands[operand_index]; - } - i64 s = 0; - if (!check_is_assignable_to_with_score(c, &o, t, &s)) { if (show_error) { - check_assignment(c, &o, t, str_lit("argument")); + gbString proc_str = expr_to_string(ce->proc); + error(call, err_fmt, proc_str, param_count_excluding_defaults); + gb_string_free(proc_str); } - err = CallArgumentError_WrongTypes; - } - score += s; - } + } else { + if (pt->is_generic) { + Scope *scope = make_scope(pt->scope->parent, c->allocator); + CheckerContext prev = c->context; + defer (c->context = prev); + c->context.scope = scope; - if (variadic) { - bool variadic_expand = false; - Type *slice = sig_params[param_count]->type; - GB_ASSERT(is_type_slice(slice)); - Type *elem = base_type(slice)->Slice.elem; - Type *t = elem; - for (; operand_index < operands.count; operand_index++) { - Operand o = operands[operand_index]; - if (vari_expand) { - variadic_expand = true; - t = slice; - if (operand_index != param_count) { - if (show_error) { - error(o.expr, "`..` in a variadic procedure can only have one variadic argument at the end"); + final_proc_type = alloc_type(c->allocator, Type_Proc); + check_procedure_type(c, final_proc_type, pt->node, &operands); + } + + + TypeProc *pt = &final_proc_type->Proc; + + GB_ASSERT(pt->params != NULL); + Entity **sig_params = pt->params->Tuple.variables; + isize operand_index = 0; + isize max_operand_count = gb_min(param_count, operands.count); + for (; operand_index < max_operand_count; operand_index++) { + Entity *e = sig_params[operand_index]; + Type *t = e->type; + Operand o = operands[operand_index]; + if (e->kind == Entity_TypeName) { + // GB_ASSERT(!variadic); + if (o.mode == Addressing_Invalid) { + continue; + } else if (o.mode != Addressing_Type) { + error(o.expr, "Expected a type for the argument"); } - if (score_) *score_ = score; - return CallArgumentError_MultipleVariadicExpand; + + score += assign_score_function(1); + continue; + } + if (variadic) { + o = operands[operand_index]; + } + i64 s = 0; + if (!check_is_assignable_to_with_score(c, &o, t, &s)) { + if (show_error) { + check_assignment(c, &o, t, str_lit("argument")); + } + err = CallArgumentError_WrongTypes; + } + score += s; + } + + if (variadic) { + bool variadic_expand = false; + Type *slice = sig_params[param_count]->type; + GB_ASSERT(is_type_slice(slice)); + Type *elem = base_type(slice)->Slice.elem; + Type *t = elem; + for (; operand_index < operands.count; operand_index++) { + Operand o = operands[operand_index]; + if (vari_expand) { + variadic_expand = true; + t = slice; + if (operand_index != param_count) { + if (show_error) { + error(o.expr, "`..` in a variadic procedure can only have one variadic argument at the end"); + } + if (score_) *score_ = score; + return CallArgumentError_MultipleVariadicExpand; + } + } + i64 s = 0; + if (!check_is_assignable_to_with_score(c, &o, t, &s)) { + if (show_error) { + check_assignment(c, &o, t, str_lit("argument")); + } + err = CallArgumentError_WrongTypes; + } + score += s; } } - i64 s = 0; - if (!check_is_assignable_to_with_score(c, &o, t, &s)) { - if (show_error) { - check_assignment(c, &o, t, str_lit("argument")); - } - err = CallArgumentError_WrongTypes; - } - score += s; } } if (score_) *score_ = score; + if (result_type_) *result_type_ = final_proc_type->Proc.results; + return err; } @@ -5208,6 +5251,7 @@ CALL_ARGUMENT_CHECKER(check_named_call_arguments) { } if (score_) *score_ = score; + if (result_type_) *result_type_ = pt->results; return err; } @@ -5267,7 +5311,7 @@ Type *check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNod Type *pt = base_type(p->type); if (pt != NULL && is_type_proc(pt)) { i64 score = 0; - CallArgumentError err = call_checker(c, call, pt, operands, CallArgumentMode_NoErrors, &score); + CallArgumentError err = call_checker(c, call, pt, operands, CallArgumentMode_NoErrors, &score, &result_type); if (err == CallArgumentError_None) { valids[valid_count].index = i; valids[valid_count].score = score; @@ -5312,18 +5356,11 @@ Type *check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNod add_entity_use(c, expr, e); proc_type = e->type; i64 score = 0; - CallArgumentError err = call_checker(c, call, proc_type, operands, CallArgumentMode_ShowErrors, &score); - - if (proc_type != NULL && is_type_proc(proc_type)) { - result_type = base_type(proc_type)->Proc.results; - } + CallArgumentError err = call_checker(c, call, proc_type, operands, CallArgumentMode_ShowErrors, &score, &result_type); } } else { i64 score = 0; - CallArgumentError err = call_checker(c, call, proc_type, operands, CallArgumentMode_ShowErrors, &score); - if (proc_type != NULL && is_type_proc(proc_type)) { - result_type = base_type(proc_type)->Proc.results; - } + CallArgumentError err = call_checker(c, call, proc_type, operands, CallArgumentMode_ShowErrors, &score, &result_type); } return result_type; @@ -5473,13 +5510,7 @@ ExprKind check_call_expr(Checker *c, Operand *operand, AstNode *call) { } Type *pt = base_type(proc_type); - bool results_are_generic = false; - if (is_type_proc(pt) && pt->Proc.results != NULL) { - results_are_generic = is_type_generic(pt->Proc.results); - } - if (results_are_generic) { - operand->mode = Addressing_NoValue; - } else if (result_type == NULL) { + if (result_type == NULL) { operand->mode = Addressing_NoValue; } else { GB_ASSERT(is_type_tuple(result_type)); diff --git a/src/checker.cpp b/src/checker.cpp index 66fcc1ab6..5fe030331 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -221,6 +221,7 @@ ExprInfo make_expr_info(bool is_lhs, AddressingMode mode, Type *type, ExactValue struct Scope { + AstNode * node; Scope * parent; Scope * prev, *next; Scope * first_child; @@ -241,8 +242,6 @@ gb_global Scope *universal_scope = NULL; - - struct DelayedDecl { Scope * parent; AstNode *decl; @@ -278,6 +277,7 @@ struct CheckerInfo { Map entities; // Key: Entity * Map foreigns; // Key: String Map files; // Key: String (full path) + Map type_info_map; // Key: Type * isize type_info_count; }; @@ -423,12 +423,12 @@ void destroy_scope(Scope *scope) { void add_scope(Checker *c, AstNode *node, Scope *scope) { GB_ASSERT(node != NULL); GB_ASSERT(scope != NULL); + scope->node = node; map_set(&c->info.scopes, hash_node(node), scope); } void check_open_scope(Checker *c, AstNode *node) { - GB_ASSERT(node != NULL); node = unparen_expr(node); GB_ASSERT(node->kind == AstNode_Invalid || is_ast_node_stmt(node) || diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 09eba836f..29d9fac7d 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -189,18 +189,26 @@ void ir_print_proc_type_without_pointer(irFileBuffer *f, irModule *m, Type *t) { ir_fprintf(f, ", "); } } + isize param_index = 0; for (isize i = 0; i < param_count; i++) { - if (i > 0) { + if (param_index > 0) { ir_fprintf(f, ", "); } + Entity *e = t->Proc.params->Tuple.variables[i]; + if (e->kind != Entity_Variable) { + continue; + } + if (i+1 == param_count && t->Proc.c_vararg) { ir_fprintf(f, "..."); } else { ir_print_type(f, m, t->Proc.abi_compat_params[i]); } + + param_index++; } if (t->Proc.calling_convention == ProcCC_Odin) { - if (param_count > 0) { + if (param_index > 0) { ir_fprintf(f, ", "); } ir_print_type(f, m, t_context_ptr); @@ -354,11 +362,16 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) { ir_print_type(f, m, t->Tuple.variables[0]->type); } else { ir_fprintf(f, "{"); + isize index = 0; for (isize i = 0; i < t->Tuple.variable_count; i++) { - if (i > 0) { + if (index > 0) { ir_fprintf(f, ", "); } - ir_print_type(f, m, t->Tuple.variables[i]->type); + Entity *e = t->Tuple.variables[i]; + if (e->kind == Entity_Variable) { + ir_print_type(f, m, e->type); + index++; + } } ir_fprintf(f, "}"); } @@ -1551,17 +1564,22 @@ void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) { } } + isize param_index = 0; if (param_count > 0) { TypeTuple *params = &proc_type->params->Tuple; for (isize i = 0; i < param_count; i++) { Entity *e = params->variables[i]; Type *original_type = e->type; Type *abi_type = proc_type->abi_compat_params[i]; - if (i > 0) { + if (param_index > 0) { ir_fprintf(f, ", "); } + if (e->kind != Entity_Variable) { + continue; + } + if (i+1 == params->variable_count && proc_type->c_vararg) { - ir_fprintf(f, " ..."); + ir_fprintf(f, " ..."); } else { ir_print_type(f, m, abi_type); if (e->flags&EntityFlag_NoAlias) { @@ -1577,10 +1595,12 @@ void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) { } } } + + param_index++; } } if (proc_type->calling_convention == ProcCC_Odin) { - if (param_count > 0) { + if (param_index > 0) { ir_fprintf(f, ", "); } ir_print_type(f, m, t_context_ptr); diff --git a/src/parser.cpp b/src/parser.cpp index bf1b6163e..f6345265b 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -34,6 +34,7 @@ struct AstFile { // NOTE(bill): Used to prevent type literals in control clauses isize expr_level; bool allow_range; // NOTE(bill): Ranges are only allowed in certain cases + bool allow_gen_proc_type; bool in_foreign_block; Array decls; @@ -2729,9 +2730,13 @@ AstNode *parse_proc_decl(AstFile *f) { String link_name = {}; + bool prev_allow_gen_proc_type = f->allow_gen_proc_type; + f->allow_gen_proc_type = true; AstNode *name = parse_ident(f); AstNode *type = parse_proc_type(f, token, &link_name); u64 tags = type->ProcType.tags; + f->allow_gen_proc_type = prev_allow_gen_proc_type; + if (f->curr_token.kind == Token_OpenBrace) { if ((tags & ProcTag_foreign) != 0) { @@ -3404,12 +3409,13 @@ AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, Tok isize total_name_count = 0; bool allow_ellipsis = allowed_flags&FieldFlag_ellipsis; + bool allow_type_token = f->allow_gen_proc_type && allow_default_parameters; while (f->curr_token.kind != follow && f->curr_token.kind != Token_Colon && f->curr_token.kind != Token_EOF) { u32 flags = parse_field_prefixes(f); - AstNode *param = parse_var_type(f, allow_ellipsis, allow_default_parameters); + AstNode *param = parse_var_type(f, allow_ellipsis, allow_type_token); AstNodeAndFlags naf = {param, flags}; array_add(&list, naf); if (f->curr_token.kind != Token_Comma) { @@ -3436,7 +3442,7 @@ AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, Tok if (f->curr_token.kind != Token_Eq) { expect_token_after(f, Token_Colon, "field list"); - type = parse_var_type(f, allow_ellipsis, allow_default_parameters); + type = parse_var_type(f, allow_ellipsis, allow_type_token); } if (allow_token(f, Token_Eq)) { // TODO(bill): Should this be true==lhs or false==rhs? @@ -3788,7 +3794,10 @@ AstNode *parse_type_or_ident(AstFile *f) { case Token_proc: { Token token = f->curr_token; next_token(f); + bool prev_allow_gen_proc_type = f->allow_gen_proc_type; + f->allow_gen_proc_type = false; AstNode *pt = parse_proc_type(f, token, NULL); + f->allow_gen_proc_type = prev_allow_gen_proc_type; if (pt->ProcType.tags != 0) { syntax_error(token, "A procedure type cannot have tags"); } diff --git a/src/types.cpp b/src/types.cpp index 54224373d..f6399a7a0 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -1,4 +1,5 @@ struct Scope; +struct AstNode; enum BasicKind { Basic_Invalid, @@ -135,18 +136,19 @@ struct TypeRecord { i64 * offsets; \ }) \ TYPE_KIND(Proc, struct { \ - Scope *scope; \ - Type * params; /* Type_Tuple */ \ - Type * results; /* Type_Tuple */ \ - i32 param_count; \ - i32 result_count; \ - bool return_by_pointer; \ - Type **abi_compat_params; \ - Type * abi_compat_result_type; \ - bool variadic; \ - bool require_results; \ - bool c_vararg; \ - bool is_generic; \ + AstNode *node; \ + Scope * scope; \ + Type * params; /* Type_Tuple */ \ + Type * results; /* Type_Tuple */ \ + i32 param_count; \ + i32 result_count; \ + bool return_by_pointer; \ + Type ** abi_compat_params; \ + Type * abi_compat_result_type; \ + bool variadic; \ + bool require_results; \ + bool c_vararg; \ + bool is_generic; \ ProcCallingConvention calling_convention; \ }) \ TYPE_KIND(Map, struct { \ @@ -1164,7 +1166,7 @@ bool are_types_identical(Type *x, Type *y) { for (isize i = 0; i < x->Tuple.variable_count; i++) { Entity *xe = x->Tuple.variables[i]; Entity *ye = y->Tuple.variables[i]; - if (!are_types_identical(xe->type, ye->type)) { + if (xe->kind != ye->kind || !are_types_identical(xe->type, ye->type)) { return false; } } @@ -2383,19 +2385,24 @@ gbString write_type_to_string(gbString str, Type *type) { for (isize i = 0; i < type->Tuple.variable_count; i++) { Entity *var = type->Tuple.variables[i]; if (var != NULL) { - GB_ASSERT(var->kind == Entity_Variable); if (i > 0) { str = gb_string_appendc(str, ", "); } - if (var->flags&EntityFlag_CVarArg) { - str = gb_string_appendc(str, "#c_vararg "); - } - if (var->flags&EntityFlag_Ellipsis) { - Type *slice = base_type(var->type); - str = gb_string_appendc(str, ".."); - GB_ASSERT(is_type_slice(var->type)); - str = write_type_to_string(str, slice->Slice.elem); + if (var->kind == Entity_Variable) { + if (var->flags&EntityFlag_CVarArg) { + str = gb_string_appendc(str, "#c_vararg "); + } + if (var->flags&EntityFlag_Ellipsis) { + Type *slice = base_type(var->type); + str = gb_string_appendc(str, ".."); + GB_ASSERT(is_type_slice(var->type)); + str = write_type_to_string(str, slice->Slice.elem); + } else { + str = write_type_to_string(str, var->type); + } } else { + GB_ASSERT(var->kind == Entity_TypeName); + str = gb_string_appendc(str, "type/"); str = write_type_to_string(str, var->type); } }