diff --git a/code/demo.odin b/code/demo.odin index 6a4f4b261..a7a72f4a8 100644 --- a/code/demo.odin +++ b/code/demo.odin @@ -31,6 +31,7 @@ proc general_stuff() { // By default, all variables are zeroed // This can be overridden with the "uninitialized value" + // This is similar to `nil` but applied to everything var undef_int: int = ---; @@ -41,7 +42,8 @@ proc general_stuff() { // // It does mean that a pointer is implicitly passed procedures with the default // Odin calling convention (#cc_odin) - // This can be overridden with something like #cc_contextless or #cc_c + // This can be overridden with something like #cc_contextless or #cc_c if performance + // is worried about } @@ -80,7 +82,8 @@ proc named_arguments() { // As the procedures have more and more parameters, it is very easy - // to get many of the arguments in the wrong order + // to get many of the arguments in the wrong order especialy if the + // types are the same make_character("¡Ay, caramba!", "Frank", Green, Blue); // Named arguments help to disambiguate this problem @@ -102,7 +105,8 @@ proc named_arguments() { // Named arguments can also aid with default arguments - proc numerous_things(s : string, a = 1, b = 2, c = 3.14, d = "The Best String!", e = false, f = 10.3/3.1, g = false) { + proc numerous_things(s : string, a = 1, b = 2, c = 3.14, + d = "The Best String!", e = false, f = 10.3/3.1, g = false) { var g_str = g ? "true" : "false"; fmt.printf("How many?! %s: %v\n", s, g_str); } @@ -169,9 +173,11 @@ proc default_return_values() { proc call_location() { proc amazing(n: int, using loc = #caller_location) { - fmt.printf("%s(%d:%d) just asked to do something amazing to %d.\n", + fmt.printf("%s(%d:%d) just asked to do something amazing.\n", fully_pathed_filename, line, column); + fmt.printf("Normal -> %d\n", n); fmt.printf("Amazing -> %d\n", n+1); + fmt.println(); } var loc = #location(main); @@ -232,7 +238,7 @@ proc explicit_parametric_polymorphic_procedures() { // A more complicated example using subtyping - // Something like this could be used a game + // Something like this could be used in a game type Vector2 struct {x, y: f32}; type Entity struct { diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 2f3b1630a..97bd33c88 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -1077,14 +1077,17 @@ 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_, Array *operands) { +Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_variadic_, bool *success_, Array *operands) { if (_params == NULL) { return NULL; } + + bool success = true; ast_node(field_list, FieldList, _params); Array params = field_list->list; if (params.count == 0) { + if (success_) *success_ = success; return NULL; } @@ -1120,6 +1123,8 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari ExactValue value = {}; bool default_is_nil = false; bool default_is_location = false; + bool is_type_param = false; + if (type_expr == NULL) { if (default_value->kind == AstNode_BasicDirective && @@ -1147,15 +1152,19 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari is_variadic = true; } else { error(param, "Invalid AST: Invalid variadic parameter"); + success = false; } } 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 a type parameter"); + error(o.expr, "Expected a type to assign to the type parameter"); + type = t_invalid; + success = false; } } else { type = make_type_generic(c->allocator, 0); @@ -1197,7 +1206,11 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari type = t_invalid; } if (is_type_untyped(type)) { - error(params[i], "Cannot determine parameter type from a nil"); + if (is_type_untyped_undef(type)) { + error(params[i], "Cannot determine parameter type from ---"); + } else { + error(params[i], "Cannot determine parameter type from a nil"); + } type = t_invalid; } @@ -1221,16 +1234,8 @@ 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; - bool is_generic = type->kind == Type_Generic; - Type *gen_type = type; - if (operands != NULL) { - Operand o = (*operands)[variable_index]; - is_generic = o.mode == Addressing_Type && o.type == type; - if (is_generic) gen_type = o.type; - } - - if (is_generic) { - param = make_entity_type_name(c->allocator, scope, name->Ident, gen_type); + if (is_type_param) { + param = make_entity_type_name(c->allocator, scope, name->Ident, type); param->TypeName.is_type_alias = true; } else { param = make_entity_param(c->allocator, scope, name->Ident, type, @@ -1267,6 +1272,7 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari tuple->Tuple.variables = variables; tuple->Tuple.variable_count = variable_count; + if (success_) *success_ = success; if (is_variadic_) *is_variadic_ = is_variadic; return tuple; @@ -1574,11 +1580,12 @@ bool abi_compat_return_by_value(gbAllocator a, ProcCallingConvention cc, Type *a } // 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) { +bool 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, operands); + bool success = true; + Type *params = check_get_params(c, c->context.scope, pt->params, &variadic, &success, operands); Type *results = check_get_results(c, c->context.scope, pt->results); isize param_count = 0; @@ -1637,6 +1644,8 @@ void check_procedure_type(Checker *c, Type *type, AstNode *proc_type_node, Array // NOTE(bill): The types are the same type->Proc.abi_compat_result_type = type_to_abi_compat_result_type(c->allocator, type->Proc.results); type->Proc.return_by_pointer = abi_compat_return_by_value(c->allocator, pt->calling_convention, type->Proc.abi_compat_result_type); + + return success; } @@ -5002,15 +5011,18 @@ Entity *find_or_generate_polymorphic_procedure(Checker *c, Entity *base_entity, // NOTE(bill): This is slightly memory leaking if the type already exists // Maybe it's better to check with the previous types first? Type *final_proc_type = make_type_proc(c->allocator, c->context.scope, NULL, 0, NULL, 0, false, pt->calling_convention); - check_procedure_type(c, final_proc_type, pt->node, operands); + bool success = check_procedure_type(c, final_proc_type, pt->node, operands); + // if (!success) { + // return NULL; + // } auto *found_gen_procs = map_get(&c->info.gen_procs, hash_pointer(base_entity->identifier)); if (found_gen_procs) { for_array(i, *found_gen_procs) { Entity *other = (*found_gen_procs)[i]; if (are_types_identical(other->type, final_proc_type)) { - // NOTE(bill): This scope is not needed any more, destroy it - destroy_scope(scope); + // NOTE(bill): This scope is not needed any more, destroy it + // destroy_scope(scope); return other; } } @@ -5039,12 +5051,14 @@ Entity *find_or_generate_polymorphic_procedure(Checker *c, Entity *base_entity, entity->scope = base_entity->scope; ProcedureInfo proc_info = {}; - proc_info.file = c->curr_ast_file; - proc_info.token = token; - proc_info.decl = d; - proc_info.type = final_proc_type; - proc_info.body = pd->body; - proc_info.tags = tags; + if (success) { + proc_info.file = c->curr_ast_file; + proc_info.token = token; + proc_info.decl = d; + proc_info.type = final_proc_type; + proc_info.body = pd->body; + proc_info.tags = tags; + } if (found_gen_procs) { array_add(found_gen_procs, entity); diff --git a/src/checker.cpp b/src/checker.cpp index 051020ae6..f490a2a23 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1448,19 +1448,10 @@ void check_procedure_overloading(Checker *c, Entity *e) { TokenPos pos = q->token.pos; - if (q->type == NULL) { + if (q->type == NULL || q->type == t_invalid) { continue; } - if (is_type_proc(q->type)) { - TypeProc *ptq = &base_type(q->type)->Proc; - if (ptq->is_generic) { - q->type = t_invalid; - error(q->token, "Polymorphic procedure `%.*s` cannot be overloaded", LIT(name)); - continue; - } - } - ProcTypeOverloadKind kind = are_proc_types_overload_safe(p->type, q->type); switch (kind) { case ProcOverload_Identical: @@ -1480,6 +1471,10 @@ void check_procedure_overloading(Checker *c, Entity *e) { error(p->token, "Overloaded procedure `%.*s` as the same parameters but different results in this scope", LIT(name)); is_invalid = true; break; + case ProcOverload_Polymorphic: + error(p->token, "Overloaded procedure `%.*s` has a polymorphic counterpart in this scope which is not allowed", LIT(name)); + is_invalid = true; + break; case ProcOverload_ParamCount: case ProcOverload_ParamTypes: // This is okay :) diff --git a/src/types.cpp b/src/types.cpp index 465f69048..ab6408b12 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -1083,6 +1083,12 @@ bool are_types_identical(Type *x, Type *y) { } switch (x->kind) { + case Type_Generic: + if (y->kind == Type_Generic) { + return true; // TODO(bill): Is this correct? + } + break; + case Type_Basic: if (y->kind == Type_Basic) { return x->Basic.kind == y->Basic.kind; @@ -1321,6 +1327,7 @@ enum ProcTypeOverloadKind { ProcOverload_ParamTypes, ProcOverload_ResultCount, ProcOverload_ResultTypes, + ProcOverload_Polymorphic, ProcOverload_NotProcedure, @@ -1340,6 +1347,10 @@ ProcTypeOverloadKind are_proc_types_overload_safe(Type *x, Type *y) { // return ProcOverload_CallingConvention; // } + if (px.is_generic != py.is_generic) { + return ProcOverload_Polymorphic; + } + if (px.param_count != py.param_count) { return ProcOverload_ParamCount; }