diff options
| author | Ginger Bill <bill@gingerbill.org> | 2017-01-15 20:43:28 +0000 |
|---|---|---|
| committer | Ginger Bill <bill@gingerbill.org> | 2017-01-15 20:43:28 +0000 |
| commit | 6dc6b6f8aaa3289ae32746367089f9f77be9a623 (patch) | |
| tree | 8a5956818804b72b552e4de8cd60a6a356a378b4 /src/check_expr.c | |
| parent | ac736aa4ecf5dce7b1dbd4c5ef3758f8f2008ebc (diff) | |
Err on ambiguous overloaded calls
Diffstat (limited to 'src/check_expr.c')
| -rw-r--r-- | src/check_expr.c | 126 |
1 files changed, 55 insertions, 71 deletions
diff --git a/src/check_expr.c b/src/check_expr.c index 763fc360a..f1c2dd620 100644 --- a/src/check_expr.c +++ b/src/check_expr.c @@ -91,19 +91,24 @@ bool check_is_assignable_to_using_subtype(Type *dst, Type *src) { } -bool check_is_assignable_to(Checker *c, Operand *operand, Type *type) { + +bool check_is_assignable_to_with_score(Checker *c, Operand *operand, Type *type, i64 *score) { + // IMPORTANT TODO(bill): Determine score for assignments with use with overloaded procedures if (operand->mode == Addressing_Invalid || type == t_invalid) { + if (score) *score = 0; return true; } if (operand->mode == Addressing_Builtin) { + if (score) *score = 0; return false; } Type *s = operand->type; if (are_types_identical(s, type)) { + if (score) *score = 10; return true; } @@ -111,15 +116,13 @@ bool check_is_assignable_to(Checker *c, Operand *operand, Type *type) { Type *dst = base_type(type); if (is_type_untyped(src)) { - switch (dst->kind) { - case Type_Basic: + if (dst->kind == Type_Basic) { if (operand->mode == Addressing_Constant) { return check_value_is_expressible(c, operand->value, dst, NULL); } if (src->kind == Type_Basic && src->Basic.kind == Basic_UntypedBool) { return is_type_boolean(dst); } - break; } if (type_has_nil(dst)) { return operand->mode == Addressing_Value && operand->type == t_untyped_nil; @@ -132,7 +135,8 @@ bool check_is_assignable_to(Checker *c, Operand *operand, Type *type) { if (is_type_maybe(dst)) { Type *elem = base_type(dst)->Maybe.elem; - return are_types_identical(elem, s); + bool ok = are_types_identical(elem, s); + return ok; } if (is_type_untyped_nil(src)) { @@ -189,6 +193,12 @@ bool check_is_assignable_to(Checker *c, Operand *operand, Type *type) { } +bool check_is_assignable_to(Checker *c, Operand *operand, Type *type) { + i64 score = 0; + return check_is_assignable_to_with_score(c, operand, type, &score); +} + + // NOTE(bill): `content_name` is for debugging and error messages void check_assignment(Checker *c, Operand *operand, Type *type, String context_name) { check_not_tuple(c, operand); @@ -3407,11 +3417,13 @@ typedef enum CallArgumentError { CallArgumentError_TooManyArguments, } CallArgumentError; -CallArgumentError check_call_arguments_internal(Checker *c, AstNode *call, Type *proc_type, Operand *operands, isize operand_count, bool show_error, i64 *score) { +CallArgumentError check_call_arguments_internal(Checker *c, AstNode *call, Type *proc_type, Operand *operands, isize operand_count, + bool show_error, i64 *score_) { ast_node(ce, CallExpr, call); isize param_count = 0; bool variadic = proc_type->Proc.variadic; bool vari_expand = (ce->ellipsis.pos.line != 0); + i64 score = 0; if (proc_type->Proc.params != NULL) { param_count = proc_type->Proc.params->Tuple.variable_count; @@ -3426,10 +3438,12 @@ CallArgumentError check_call_arguments_internal(Checker *c, AstNode *call, Type "Cannot use `..` in call to a non-variadic procedure: `%.*s`", LIT(ce->proc->Ident.string)); } + if (score_) *score_ = score; return CallArgumentError_NonVariadicExpand; } if (operand_count == 0 && param_count == 0) { + if (score_) *score_ = score; return CallArgumentError_None; } @@ -3452,6 +3466,7 @@ CallArgumentError check_call_arguments_internal(Checker *c, AstNode *call, Type error_node(call, err_fmt, proc_str, param_count); gb_string_free(proc_str); } + if (score_) *score_ = score; return err; } @@ -3466,12 +3481,14 @@ CallArgumentError check_call_arguments_internal(Checker *c, AstNode *call, Type if (variadic) { o = operands[operand_index]; } - if (!check_is_assignable_to(c, &o, t)) { + 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) { @@ -3489,18 +3506,22 @@ CallArgumentError check_call_arguments_internal(Checker *c, AstNode *call, Type if (show_error) { error_node(o.expr, "`..` in a variadic procedure can only have one variadic argument at the end"); } + if (score_) *score_ = score; return CallArgumentError_MultipleVariadicExpand; } } - if (!check_is_assignable_to(c, &o, t)) { + 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; return err; } @@ -3532,10 +3553,11 @@ Type *check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNod String name = operand->initial_overload_entity->token.string; HashKey key = hash_string(name); - isize overload_count = operand->overload_count; - Entity **procs = gb_alloc_array(heap_allocator(), Entity *, overload_count); - isize *valid_procs = gb_alloc_array(heap_allocator(), isize, overload_count); - isize valid_proc_count = 0; + isize overload_count = operand->overload_count; + Entity **procs = gb_alloc_array(heap_allocator(), Entity *, overload_count); + isize * valid_procs = gb_alloc_array(heap_allocator(), isize, overload_count); + i64 * valid_scores = gb_alloc_array(heap_allocator(), i64, overload_count); + isize valid_count = 0; map_entity_multi_get_all(&s->elements, key, procs); @@ -3554,18 +3576,36 @@ Type *check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNod i64 score = 0; CallArgumentError err = check_call_arguments_internal(c, call, proc_type, operands.e, operands.count, false, &score); if (err == CallArgumentError_None) { - valid_procs[valid_proc_count++] = i; + valid_procs[valid_count] = i; + valid_scores[valid_count] = score; + valid_count++; } } } + // IMPORTANT TODO(bill): Get the best proc by its score + // i64 best_score = 0; + // isize best_index = 0; + // for (isize i = 0; i < valid_count; i++) { + // if (best_score < valid_scores[i]) { + // best_score = valid_scores[i]; + // best_index = i; + // } + // } + - if (valid_proc_count == 0) { + if (valid_count == 0) { error_node(operand->expr, "No overloads for `%.*s` that match the specified arguments", LIT(name)); proc_type = t_invalid; + } else if (valid_count > 1) { + error_node(operand->expr, "Ambiguous procedure call `%.*s`, could be:", LIT(name)); + for (isize i = 0; i < valid_count; i++) { + TokenPos pos = procs[valid_procs[i]]->token.pos; + gb_printf_err("\t`%.*s` at %.*s(%td:%td)\n", LIT(name), LIT(pos.file), pos.line, pos.column); + } + proc_type = t_invalid; } else { GB_ASSERT(operand->expr->kind == AstNode_Ident); - // IMPORTANT TODO(bill): Get the best proc by its score Entity *e = procs[valid_procs[0]]; add_entity_use(c, operand->expr, e); proc_type = e->type; @@ -3581,62 +3621,6 @@ Type *check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNod array_free(&operands); } return proc_type; - -/* - i32 error_code = 0; - if (operands.count < param_count) { - error_code = -1; - } else if (!variadic && operands.count > param_count) { - error_code = +1; - } - if (error_code != 0) { - char *err_fmt = "Too many arguments for `%s`, expected %td arguments"; - if (error_code < 0) { - err_fmt = "Too few arguments for `%s`, expected %td arguments"; - } - - gbString proc_str = expr_to_string(ce->proc); - error_node(call, err_fmt, proc_str, param_count); - gb_string_free(proc_str); - operand->mode = Addressing_Invalid; - goto end; - } - - GB_ASSERT(proc_type->Proc.params != NULL); - Entity **sig_params = proc_type->Proc.params->Tuple.variables; - isize operand_index = 0; - for (; operand_index < param_count; operand_index++) { - Type *arg_type = sig_params[operand_index]->type; - Operand o = operands.e[operand_index]; - if (variadic) { - o = operands.e[operand_index]; - } - check_assignment(c, &o, arg_type, str_lit("argument")); - } - - 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.e[operand_index]; - if (vari_expand) { - variadic_expand = true; - t = slice; - if (operand_index != param_count) { - error_node(o.expr, "`..` in a variadic procedure can only have one variadic argument at the end"); - break; - } - } - check_assignment(c, &o, t, str_lit("argument")); - } - } -end: - - return proc_type; -*/ } |