@@ -11608,19 +11608,52 @@ bool ConstraintSystem::resolveKeyPath(TypeVariableType *typeVar,
1160811608 ConstraintLocatorBuilder locator) {
1160911609 auto *keyPathLocator = typeVar->getImpl().getLocator();
1161011610 auto *keyPath = castToExpr<KeyPathExpr>(keyPathLocator->getAnchor());
11611+
1161111612 if (keyPath->hasSingleInvalidComponent()) {
1161211613 assignFixedType(typeVar, contextualType);
1161311614 return true;
1161411615 }
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];
1161911616
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+ }
1162411657 }
1162511658 }
1162611659
0 commit comments