[CSRanking] Always rank key path dynamic member choices lower than non-dynamic ones

This only comes into play when all other choices are coming from
constrained extensions, because there is no way to determine upfront
whether any are going to match it's better to be safe and add
key path dynamic member choice to the set too.

Resolves: [SR-11465](https://bugs.swift.org/browse/SR-11465)
Resolves: rdar://problem/55314724
This commit is contained in:
Pavel Yaskevich
2019-09-12 13:55:56 -07:00
parent a407b1309f
commit 868afc6fc9
2 changed files with 41 additions and 8 deletions

View File

@@ -822,17 +822,27 @@ SolutionCompareResult ConstraintSystem::compareSolutions(
continue;
}
// Dynamic member lookup through a keypath is better than one using string
// because it carries more type information.
if (choice1.getKind() == OverloadChoiceKind::KeyPathDynamicMemberLookup &&
choice2.getKind() == OverloadChoiceKind::DynamicMemberLookup) {
score1 += weight;
if (choice1.getKind() == OverloadChoiceKind::KeyPathDynamicMemberLookup) {
if (choice2.getKind() == OverloadChoiceKind::DynamicMemberLookup)
// Dynamic member lookup through a keypath is better than one using
// string because it carries more type information.
score1 += weight;
else
// Otherwise let's prefer non-dynamic declaration.
score2 += weight;
continue;
}
if (choice1.getKind() == OverloadChoiceKind::DynamicMemberLookup &&
choice2.getKind() == OverloadChoiceKind::KeyPathDynamicMemberLookup) {
score2 += weight;
if (choice2.getKind() == OverloadChoiceKind::KeyPathDynamicMemberLookup) {
if (choice1.getKind() == OverloadChoiceKind::DynamicMemberLookup)
// Dynamic member lookup through a keypath is better than one using
// string because it carries more type information.
score2 += weight;
else
// Otherwise let's prefer non-dynamic declaration.
score1 += weight;
continue;
}

View File

@@ -367,3 +367,26 @@ func make_sure_delayed_keypath_dynamic_member_works() {
}
}
}
// SR-11465 - Ambiguity in expression which matches both dynamic member lookup and declaration from constrained extension
@dynamicMemberLookup
struct SR_11465<RawValue> {
var rawValue: RawValue
subscript<Subject>(dynamicMember keyPath: KeyPath<RawValue, Subject>) -> Subject {
rawValue[keyPath: keyPath]
}
}
extension SR_11465: Hashable, Equatable where RawValue: Hashable {
func hash(into hasher: inout Hasher) {
hasher.combine(self.rawValue)
}
}
func test_constrained_ext_vs_dynamic_member() {
// CHECK: function_ref @$s29keypath_dynamic_member_lookup8SR_11465VAASHRzlE9hashValueSivg
_ = SR_11465<Int>(rawValue: 1).hashValue // Ok, keep choice from constrained extension
}