mirror of
https://github.com/odin-lang/Odin.git
synced 2026-08-14 09:44:26 +00:00
incorp specialized-vs-generic poly
This commit is contained in:
@@ -7603,24 +7603,37 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c,
|
||||
array_add(&proc_entities, data.gen_entity);
|
||||
index = proc_entities.count-1;
|
||||
|
||||
// Order candidates: value-polymorphic > concrete > type-polymorphic
|
||||
// Order candidates:
|
||||
// value-polymorphic > concrete > specialized generic > unconstrained generic
|
||||
//
|
||||
// `proc($S: string)` specialises on a compile-time *value*
|
||||
// `proc(x: $T)` specialises on a *type* and is a fallback, so it should
|
||||
// lose to an exact concrete overload
|
||||
// `proc(x: $T)` specialises on a *type* and is a fallback, so it should lose
|
||||
// to an exact concrete overload
|
||||
// `proc(x: $T/[]$E)` constrains that type, so it is the closer of the two
|
||||
//
|
||||
// Both are small tie-breaks on purpose: assign_score_function(1) is
|
||||
// These are small tie-breaks on purpose: assign_score_function(1) is
|
||||
// ~a full perfect-match unit and would swamp argument match quality.
|
||||
bool has_polymorphic_constant = false;
|
||||
bool has_specialized_generic = false;
|
||||
if (pt->Proc.params != nullptr) {
|
||||
for (Entity *param : pt->Proc.params->Tuple.variables) {
|
||||
if (param != nullptr && param->kind == Entity_Constant) {
|
||||
if (param == nullptr) {
|
||||
continue;
|
||||
}
|
||||
if (param->kind == Entity_Constant) {
|
||||
has_polymorphic_constant = true;
|
||||
break;
|
||||
}
|
||||
Type *bt = base_type(param->type);
|
||||
if (bt != nullptr && bt->kind == Type_Generic && bt->Generic.specialized != nullptr) {
|
||||
has_specialized_generic = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
item.score += has_polymorphic_constant ? +1 : -1;
|
||||
if (has_polymorphic_constant) {
|
||||
item.score += 2;
|
||||
} else {
|
||||
item.score += has_specialized_generic ? -1 : -2;
|
||||
}
|
||||
}
|
||||
|
||||
max_matched_features = gb_max(max_matched_features, matched_target_features(&pt->Proc));
|
||||
|
||||
@@ -179,32 +179,26 @@ test_proc_group_polymorphic_precedence :: proc(t: ^testing.T) {
|
||||
}
|
||||
|
||||
// a specialised generic beats an unconstrained one
|
||||
// polymorphic instantiation machinery rather than in candidate scoring, and are
|
||||
// expected to be resolved by https://github.com/odin-lang/Odin/pull/7208
|
||||
//
|
||||
// A more specialised generic should beat a less specialised one:
|
||||
//
|
||||
// {
|
||||
// proc_slice :: proc(x: $T/[]$E) -> int { return 1 }
|
||||
// proc_generic :: proc(x: $T) -> int { return 2 }
|
||||
// group :: proc{proc_slice, proc_generic}
|
||||
//
|
||||
// s := []int{1}
|
||||
// testing.expect_value(t, group(s), 1)
|
||||
// }
|
||||
//
|
||||
// Passing a polymorphic procedure to a group whose members take procedure-typed
|
||||
// parameters: only foo_concrete can accept f_poly once instantiated.
|
||||
//
|
||||
// {
|
||||
// f_poly :: proc(x: $T) -> T { return x }
|
||||
// foo_concrete :: proc(x: int, g: proc(int) -> int) -> int { return 1 }
|
||||
// foo_impossible :: proc(x: int, g: proc(int, int) -> string) -> int { return 2 }
|
||||
// group :: proc{foo_concrete, foo_impossible}
|
||||
//
|
||||
// testing.expect_value(t, group(1, f_poly), 1)
|
||||
// }
|
||||
}
|
||||
{
|
||||
proc_slice :: proc(x: $T/[]$E) -> int { return 1 }
|
||||
proc_generic :: proc(x: $T) -> int { return 2 }
|
||||
group :: proc{proc_slice, proc_generic}
|
||||
|
||||
s := []int{1}
|
||||
testing.expect_value(t, group(s), 1)
|
||||
}
|
||||
|
||||
// passing a polymorphic procedure to a group whose members take procedure-typed
|
||||
// parameters: only foo_concrete can accept f_poly once instantiated
|
||||
{
|
||||
f_poly :: proc(x: $T) -> T { return x }
|
||||
foo_concrete :: proc(x: int, g: proc(int) -> int) -> int { return 1 }
|
||||
foo_impossible :: proc(x: int, g: proc(int, int) -> string) -> int { return 2 }
|
||||
group :: proc{foo_concrete, foo_impossible}
|
||||
|
||||
testing.expect_value(t, group(1, f_poly), 1)
|
||||
}
|
||||
}
|
||||
|
||||
@test
|
||||
test_type_inference_on_literals_for_various_types :: proc(t: ^testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user