Skip to content

Commit 1516a3d

Browse files
committed
[ConstraintSystem] Type of key path expression should be a known KeyPath type
Currently `getPotentialBindingsForRelationalConstraint` doesn't respect the fact that type of key path expression has to be a form of `KeyPath`, instead it could eagerly try to bind it to `Any` or other contextual type if it's only available information. This patch aims to fix this situation by filtering potential bindings available for type variable representing type of the key path expression. Resolves: SR-10467
1 parent a42bf06 commit 1516a3d

File tree

4 files changed

+27
-6
lines changed

4 files changed

+27
-6
lines changed

lib/Sema/CSBindings.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,15 @@ ConstraintSystem::getPotentialBindingForRelationalConstraint(
276276
if (type->hasError())
277277
return None;
278278

279+
if (auto *locator = typeVar->getImpl().getLocator()) {
280+
if (locator->isKeyPathType()) {
281+
auto *BGT =
282+
type->lookThroughAllOptionalTypes()->getAs<BoundGenericType>();
283+
if (!BGT || !isKnownKeyPathDecl(getASTContext(), BGT->getDecl()))
284+
return None;
285+
}
286+
}
287+
279288
// If the source of the binding is 'OptionalObject' constraint
280289
// and type variable is on the left-hand side, that means
281290
// that it _has_ to be of optional type, since the right-hand

lib/Sema/ConstraintSystem.cpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1913,12 +1913,8 @@ void ConstraintSystem::resolveOverload(ConstraintLocator *locator,
19131913
refType = fnType->getResult();
19141914

19151915
auto *keyPathDecl = keyPathTy->getAnyNominal();
1916-
assert(
1917-
keyPathDecl &&
1918-
(keyPathDecl == getASTContext().getKeyPathDecl() ||
1919-
keyPathDecl == getASTContext().getWritableKeyPathDecl() ||
1920-
keyPathDecl == getASTContext().getReferenceWritableKeyPathDecl()) &&
1921-
"parameter is supposed to be a keypath");
1916+
assert(isKnownKeyPathDecl(getASTContext(), keyPathDecl) &&
1917+
"parameter is supposed to be a keypath");
19221918

19231919
auto *keyPathLoc = getConstraintLocator(
19241920
locator, LocatorPathElt::getKeyPathDynamicMember(keyPathDecl));
@@ -2712,3 +2708,9 @@ void ConstraintSystem::generateConstraints(
27122708
recordChoice(constraints, index, choices[index]);
27132709
}
27142710
}
2711+
2712+
bool constraints::isKnownKeyPathDecl(ASTContext &ctx, ValueDecl *decl) {
2713+
return decl == ctx.getKeyPathDecl() || decl == ctx.getWritableKeyPathDecl() ||
2714+
decl == ctx.getReferenceWritableKeyPathDecl() ||
2715+
decl == ctx.getPartialKeyPathDecl() || decl == ctx.getAnyKeyPathDecl();
2716+
}

lib/Sema/ConstraintSystem.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4010,6 +4010,10 @@ class DisjunctionChoiceProducer : public BindingProducer<DisjunctionChoice> {
40104010
IsExplicitConversion, isBeginningOfPartition);
40114011
}
40124012
};
4013+
4014+
/// Determine whether given declaration is one for a key path
4015+
/// `{Writable, ReferenceWritable}KeyPath`.
4016+
bool isKnownKeyPathDecl(ASTContext &ctx, ValueDecl *decl);
40134017
} // end namespace constraints
40144018

40154019
template<typename ...Args>

test/expr/unary/keypath/keypath.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -801,6 +801,12 @@ func test_keypath_with_method_refs() {
801801
let _ = \A.Type.faz.bar // expected-error {{key path cannot refer to static method 'faz()'}}
802802
}
803803

804+
// SR-10467 - Argument type 'KeyPath<String, Int>' does not conform to expected type 'Any'
805+
func test_keypath_in_any_context() {
806+
func foo(_: Any) {}
807+
_ = foo(\String.count) // Ok
808+
}
809+
804810
func testSyntaxErrors() { // expected-note{{}}
805811
_ = \. ; // expected-error{{expected member name following '.'}}
806812
_ = \.a ;

0 commit comments

Comments
 (0)