@@ -11608,19 +11608,52 @@ bool ConstraintSystem::resolveKeyPath(TypeVariableType *typeVar,
11608
11608
ConstraintLocatorBuilder locator) {
11609
11609
auto *keyPathLocator = typeVar->getImpl().getLocator();
11610
11610
auto *keyPath = castToExpr<KeyPathExpr>(keyPathLocator->getAnchor());
11611
+
11611
11612
if (keyPath->hasSingleInvalidComponent()) {
11612
11613
assignFixedType(typeVar, contextualType);
11613
11614
return true;
11614
11615
}
11615
- if (auto *BGT = contextualType->getAs<BoundGenericType>()) {
11616
- auto args = BGT->getGenericArgs();
11617
- if (isKnownKeyPathType(contextualType) && args.size() >= 1) {
11618
- auto root = BGT->getGenericArgs()[0];
11619
11616
11620
- auto *keyPathValueTV = getKeyPathValueType(keyPath);
11621
- contextualType = BoundGenericType::get(
11622
- args.size() == 1 ? getASTContext().getKeyPathDecl() : BGT->getDecl(),
11623
- /*parent=*/Type(), {root, keyPathValueTV});
11617
+ auto objectTy = contextualType->lookThroughAllOptionalTypes();
11618
+ {
11619
+ auto &ctx = getASTContext();
11620
+ // `AnyKeyPath` and `PartialKeyPath` represent type-erased versions of
11621
+ // `KeyPath<T, V>`.
11622
+ //
11623
+ // In situations where `AnyKeyPath` or `PartialKeyPath` cannot be used
11624
+ // directly i.e. passing an argument to a parameter represented by a
11625
+ // `AnyKeyPath` or `PartialKeyPath`, let's attempt a `KeyPath` binding which
11626
+ // would then be converted to a `AnyKeyPath` or `PartialKeyPath` since there
11627
+ // is a subtype relationship between them.
11628
+ if (objectTy->isAnyKeyPath()) {
11629
+ auto root = getKeyPathRootType(keyPath);
11630
+ auto value = getKeyPathValueType(keyPath);
11631
+
11632
+ contextualType =
11633
+ BoundGenericType::get(ctx.getKeyPathDecl(), Type(), {root, value});
11634
+ } else if (objectTy->isPartialKeyPath()) {
11635
+ auto rootTy = objectTy->castTo<BoundGenericType>()->getGenericArgs()[0];
11636
+ // Since partial key path is an erased version of `KeyPath`, the value
11637
+ // type would never be used, which means that binding can use
11638
+ // type variable generated for a result of key path expression.
11639
+ auto valueTy = getKeyPathValueType(keyPath);
11640
+
11641
+ contextualType = BoundGenericType::get(ctx.getKeyPathDecl(), Type(),
11642
+ {rootTy, valueTy});
11643
+ } else if (isKnownKeyPathType(objectTy)) {
11644
+ auto *keyPathTy = objectTy->castTo<BoundGenericType>();
11645
+ auto args = keyPathTy->getGenericArgs();
11646
+ assert(args.size() == 2);
11647
+
11648
+ auto root = args.front();
11649
+ auto value = getKeyPathValueType(keyPath);
11650
+
11651
+ // Make sure that key path always gets a chance to infer its
11652
+ // value type from the member chain.
11653
+ if (!value->isEqual(args.back())) {
11654
+ contextualType = BoundGenericType::get(
11655
+ keyPathTy->getDecl(), keyPathTy->getParent(), {root, value});
11656
+ }
11624
11657
}
11625
11658
}
11626
11659
0 commit comments