diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 6f968c368..aaa6bcabf 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -728,35 +728,38 @@ gb_internal i64 check_distance_between_types(CheckerContext *c, Operand *operand if (operand->mode == Addressing_Constant) { if (check_representable_as_constant(c, operand->value, dst, nullptr)) { if (is_type_typed(dst) && src->kind == Type_Basic) { + // NOTE: prefer the untyped constant's default type (int, f64, string, bool, + // rune) over other members of the same family, so a call like g(1) picks + // `int` over `i64` instead of scoring them identically and going ambiguous. switch (src->Basic.kind) { case Basic_UntypedBool: if (is_type_boolean(dst)) { - return 1; + return are_types_identical(dst, default_type(src)) ? 1 : 2; } break; case Basic_UntypedRune: if (is_type_integer(dst) || is_type_rune(dst)) { - return 1; + return are_types_identical(dst, default_type(src)) ? 1 : 2; } break; case Basic_UntypedInteger: if (is_type_integer(dst) || is_type_rune(dst)) { - return 1; + return are_types_identical(dst, default_type(src)) ? 1 : 2; } break; case Basic_UntypedString: if (is_type_string(dst)) { - return 1; + return are_types_identical(dst, default_type(src)) ? 1 : 2; } break; case Basic_UntypedFloat: if (is_type_float(dst)) { - return 1; + return are_types_identical(dst, default_type(src)) ? 1 : 2; } break; case Basic_UntypedComplex: if (is_type_complex(dst)) { - return 1; + return are_types_identical(dst, default_type(src)) ? 1 : 2; } if (is_type_quaternion(dst)) { return 2; @@ -764,12 +767,13 @@ gb_internal i64 check_distance_between_types(CheckerContext *c, Operand *operand break; case Basic_UntypedQuaternion: if (is_type_quaternion(dst)) { - return 1; + return are_types_identical(dst, default_type(src)) ? 1 : 2; } break; } } - return 2; + // A cross-family constant conversion ranks below a same-family one. + return 3; } return -1; } @@ -7012,6 +7016,11 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A error(o->expr, "'..' in a variadic procedure can only have one variadic argument at the end"); } if (data) { + // A synthesised default argument is not evidence of a better match: it + // contributes assign_score_function(1) as a dummy bonus and is then scored + // again as a perfect-match argument. Discount both, plus 1 to break the + // resulting tie, so an exact-arity overload wins. + score -= dummy_argument_count * (assign_score_function(0) + assign_score_function(1) + 1); data->score = score; data->result_type = final_proc_type->Proc.results; data->gen_entity = gen_entity; @@ -7041,6 +7050,11 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A } if (data) { + // A synthesised default argument is not evidence of a better match: it + // contributes assign_score_function(1) as a dummy bonus and is then scored + // again as a perfect-match argument. Discount both, plus 1 to break the + // resulting tie, so an exact-arity overload wins. + score -= dummy_argument_count * (assign_score_function(0) + assign_score_function(1) + 1); data->score = score; data->result_type = final_proc_type->Proc.results; data->gen_entity = gen_entity; @@ -7593,8 +7607,10 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c, array_add(&proc_entities, data.gen_entity); index = proc_entities.count-1; - // prefer non-polymorphic procedures over polymorphic - item.score += assign_score_function(1); + // Prefer non-polymorphic procedures over polymorphic. This must be a + // small tie-break: assign_score_function(1) is ~a full perfect-match + // unit, so adding it made a generic beat an exact concrete overload. + item.score -= 1; } max_matched_features = gb_max(max_matched_features, matched_target_features(&pt->Proc));