Skip to content

Commit 176969d

Browse files
committed
[CS] Allow simplification of key path subscript arg locators
This allows a few fixes to properly emit diagnostics for key path subscript argument contextual failures. Resolves SR-11476.
1 parent 26dab57 commit 176969d

File tree

4 files changed

+57
-2
lines changed

4 files changed

+57
-2
lines changed

lib/Sema/CSDiagnostics.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1950,8 +1950,10 @@ bool ContextualFailure::diagnoseConversionToNil() const {
19501950
}
19511951

19521952
// `nil` is passed as an argument to a parameter which doesn't
1953-
// expect it e.g. `foo(a: nil)` or `s[x: nil]`.
1954-
if (isa<ApplyExpr>(enclosingExpr) || isa<SubscriptExpr>(enclosingExpr))
1953+
// expect it e.g. `foo(a: nil)` or `s[x: nil]` or \S.[x: nil].
1954+
// FIXME: Find a more robust way of checking this.
1955+
if (isa<ApplyExpr>(enclosingExpr) || isa<SubscriptExpr>(enclosingExpr) ||
1956+
isa<KeyPathExpr>(enclosingExpr))
19551957
CTP = CTP_CallArgument;
19561958
} else if (auto *CE = dyn_cast<CoerceExpr>(parentExpr)) {
19571959
// `nil` is passed as a left-hand side of the coercion

lib/Sema/ConstraintSystem.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2911,6 +2911,26 @@ void constraints::simplifyLocator(Expr *&anchor,
29112911
path = path.slice(1);
29122912
continue;
29132913

2914+
case ConstraintLocator::KeyPathComponent: {
2915+
auto elt = path[0].castTo<LocatorPathElt::KeyPathComponent>();
2916+
2917+
// If the next element is an ApplyArgument, we can simplify by looking
2918+
// into the index expression.
2919+
if (path.size() < 2 ||
2920+
path[1].getKind() != ConstraintLocator::ApplyArgument)
2921+
break;
2922+
2923+
if (auto *kpe = dyn_cast<KeyPathExpr>(anchor)) {
2924+
auto component = kpe->getComponents()[elt.getIndex()];
2925+
auto indexExpr = component.getIndexExpr();
2926+
assert(indexExpr && "Trying to apply a component without an index?");
2927+
anchor = indexExpr;
2928+
path = path.slice(2);
2929+
continue;
2930+
}
2931+
break;
2932+
}
2933+
29142934
default:
29152935
// FIXME: Lots of other cases to handle.
29162936
break;

test/Constraints/fixes.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,3 +321,18 @@ func test_explicit_call_with_overloads() {
321321
foo(S().foo)
322322
// expected-error@-1 {{function produces expected type 'Int'; did you mean to call it with '()'?}} {{14-14=()}}
323323
}
324+
325+
// SR-11476
326+
func testKeyPathSubscriptArgFixes(_ fn: @escaping () -> Int) {
327+
struct S {
328+
subscript(x: Int) -> Int { x }
329+
}
330+
331+
var i: Int?
332+
_ = \S.[i] // expected-error {{value of optional type 'Int?' must be unwrapped to a value of type 'Int'}}
333+
// expected-note@-1{{coalesce using '??' to provide a default when the optional value contains 'nil'}}{{12-12= ?? <#default value#>}}
334+
// expected-note@-2{{force-unwrap using '!' to abort execution if the optional value contains 'nil'}}{{12-12=!}}
335+
336+
_ = \S.[nil] // expected-error {{'nil' is not compatible with expected argument type 'Int'}}
337+
_ = \S.[fn] // expected-error {{function produces expected type 'Int'; did you mean to call it with '()'?}} {{13-13=()}}
338+
}

test/decl/var/property_wrappers.swift

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1011,6 +1011,18 @@ struct Foo<T> { // expected-note {{arguments to generic parameter 'T' ('W' and '
10111011
}
10121012
}
10131013

1014+
extension Foo : Equatable where T : Equatable {
1015+
static func == (lhs: Foo, rhs: Foo) -> Bool {
1016+
lhs.wrappedValue == rhs.wrappedValue
1017+
}
1018+
}
1019+
1020+
extension Foo : Hashable where T : Hashable {
1021+
func hash(into hasher: inout Hasher) {
1022+
hasher.combine(wrappedValue)
1023+
}
1024+
}
1025+
10141026
@propertyWrapper
10151027
struct Bar<T, V> {
10161028
var wrappedValue: T
@@ -1059,6 +1071,8 @@ struct MissingPropertyWrapperUnwrap {
10591071
func d(_: W) {}
10601072
func e(_: Foo<W>) {}
10611073

1074+
subscript<T : Hashable>(takesFoo x: Foo<T>) -> Foo<T> { x }
1075+
10621076
func baz() {
10631077
self.x.foo() // expected-error {{referencing instance method 'foo()' requires wrapper 'Foo<Int>'}}{{10-10=_}}
10641078
self.x.prop // expected-error {{referencing property 'prop' requires wrapper 'Foo<Int>'}} {{10-10=_}}
@@ -1092,6 +1106,10 @@ struct MissingPropertyWrapperUnwrap {
10921106

10931107
self.x[q: "ultimate question", 42] // expected-error {{referencing subscript 'subscript(q:_:)' requires wrapper 'Foo<Int>'}} {{10-10=_}}
10941108
self.x[q: "ultimate question", 42] = true // expected-error {{referencing subscript 'subscript(q:_:)' requires wrapper 'Foo<Int>'}} {{10-10=_}}
1109+
1110+
// SR-11476
1111+
_ = \Self.[takesFoo: self.x] // expected-error {{cannot convert value 'x' of type 'Int' to expected type 'Foo<Int>', use wrapper instead}}{{31-31=_}}
1112+
_ = \Foo<W>.[x: self._x] // expected-error {{cannot convert value '_x' of type 'Foo<Int>' to expected type 'Int', use wrapped value instead}} {{26-27=}}
10951113
}
10961114
}
10971115

0 commit comments

Comments
 (0)