@@ -5221,6 +5221,13 @@ bool ConstraintSystem::repairFailures(
52215221 });
52225222 };
52235223
5224+ auto hasAnyRestriction = [&]() {
5225+ return llvm::any_of(conversionsOrFixes,
5226+ [](const RestrictionOrFix &correction) {
5227+ return bool(correction.getRestriction());
5228+ });
5229+ };
5230+
52245231 // Check whether this is a tuple with a single unlabeled element
52255232 // i.e. `(_: Int)` and return type of that element if so. Note that
52265233 // if the element is pack expansion type the tuple is significant.
@@ -5246,6 +5253,40 @@ bool ConstraintSystem::repairFailures(
52465253 return true;
52475254 }
52485255
5256+ auto maybeRepairKeyPathResultFailure = [&](KeyPathExpr *kpExpr) {
5257+ if (lhs->isPlaceholder() || rhs->isPlaceholder())
5258+ return true;
5259+ if (lhs->isTypeVariableOrMember() || rhs->isTypeVariableOrMember())
5260+ return false;
5261+
5262+ if (hasConversionOrRestriction(ConversionRestrictionKind::DeepEquality) ||
5263+ hasConversionOrRestriction(ConversionRestrictionKind::ValueToOptional))
5264+ return false;
5265+
5266+ auto i = kpExpr->getComponents().size() - 1;
5267+ auto lastCompLoc =
5268+ getConstraintLocator(kpExpr, LocatorPathElt::KeyPathComponent(i));
5269+ if (hasFixFor(lastCompLoc, FixKind::AllowTypeOrInstanceMember))
5270+ return true;
5271+
5272+ auto *keyPathLoc = getConstraintLocator(anchor);
5273+
5274+ if (hasFixFor(keyPathLoc))
5275+ return true;
5276+
5277+ if (auto contextualInfo = getContextualTypeInfo(anchor)) {
5278+ if (hasFixFor(getConstraintLocator(
5279+ keyPathLoc,
5280+ LocatorPathElt::ContextualType(contextualInfo->purpose))))
5281+ return true;
5282+ }
5283+
5284+ conversionsOrFixes.push_back(IgnoreContextualType::create(
5285+ *this, lhs, rhs,
5286+ getConstraintLocator(keyPathLoc, ConstraintLocator::KeyPathValue)));
5287+ return true;
5288+ };
5289+
52495290 if (path.empty()) {
52505291 if (!anchor)
52515292 return false;
@@ -5265,9 +5306,9 @@ bool ConstraintSystem::repairFailures(
52655306 // instance fix recorded.
52665307 if (auto *kpExpr = getAsExpr<KeyPathExpr>(anchor)) {
52675308 if (isKnownKeyPathType(lhs) && isKnownKeyPathType(rhs)) {
5268- // If we have keypath capabilities for both sides and one of the bases
5269- // is unresolved, it is too early to record fix .
5270- if (hasConversionOrRestriction(ConversionRestrictionKind::DeepEquality ))
5309+ // If we have a conversion happening here, we should let fix happen in
5310+ // simplifyRestrictedConstraint .
5311+ if (hasAnyRestriction( ))
52715312 return false;
52725313 }
52735314
@@ -5667,10 +5708,7 @@ bool ConstraintSystem::repairFailures(
56675708
56685709 // If there are any restrictions here we need to wait and let
56695710 // `simplifyRestrictedConstraintImpl` handle them.
5670- if (llvm::any_of(conversionsOrFixes,
5671- [](const RestrictionOrFix &correction) {
5672- return bool(correction.getRestriction());
5673- }))
5711+ if (hasAnyRestriction())
56745712 break;
56755713
56765714 if (auto *fix = fixPropertyWrapperFailure(
@@ -6089,10 +6127,7 @@ bool ConstraintSystem::repairFailures(
60896127
60906128 // If there are any restrictions here we need to wait and let
60916129 // `simplifyRestrictedConstraintImpl` handle them.
6092- if (llvm::any_of(conversionsOrFixes,
6093- [](const RestrictionOrFix &correction) {
6094- return bool(correction.getRestriction());
6095- }))
6130+ if (hasAnyRestriction())
60966131 break;
60976132
60986133 // `lhs` - is an result type and `rhs` is a contextual type.
@@ -6111,6 +6146,10 @@ bool ConstraintSystem::repairFailures(
61116146 return true;
61126147 }
61136148
6149+ if (auto *kpExpr = getAsExpr<KeyPathExpr>(anchor)) {
6150+ return maybeRepairKeyPathResultFailure(kpExpr);
6151+ }
6152+
61146153 auto *loc = getConstraintLocator(anchor, {path.begin(), path.end() - 1});
61156154 // If this is a mismatch between contextual type and (trailing)
61166155 // closure with explicitly specified result type let's record it
@@ -6682,37 +6721,9 @@ bool ConstraintSystem::repairFailures(
66826721 return true;
66836722 }
66846723 case ConstraintLocator::KeyPathValue: {
6685- if (lhs->isPlaceholder() || rhs->isPlaceholder())
6686- return true;
6687- if (lhs->isTypeVariableOrMember() || rhs->isTypeVariableOrMember())
6688- break;
6689-
6690- if (hasConversionOrRestriction(ConversionRestrictionKind::DeepEquality) ||
6691- hasConversionOrRestriction(ConversionRestrictionKind::ValueToOptional))
6692- return false;
6693-
6694- auto kpExpr = castToExpr<KeyPathExpr>(anchor);
6695- auto i = kpExpr->getComponents().size() - 1;
6696- auto lastCompLoc =
6697- getConstraintLocator(kpExpr, LocatorPathElt::KeyPathComponent(i));
6698- if (hasFixFor(lastCompLoc, FixKind::AllowTypeOrInstanceMember))
6724+ if (maybeRepairKeyPathResultFailure(getAsExpr<KeyPathExpr>(anchor)))
66996725 return true;
67006726
6701- auto *keyPathLoc = getConstraintLocator(anchor);
6702-
6703- if (hasFixFor(keyPathLoc))
6704- return true;
6705-
6706- if (auto contextualInfo = getContextualTypeInfo(anchor)) {
6707- if (hasFixFor(getConstraintLocator(
6708- keyPathLoc,
6709- LocatorPathElt::ContextualType(contextualInfo->purpose))))
6710- return true;
6711- }
6712-
6713- conversionsOrFixes.push_back(IgnoreContextualType::create(
6714- *this, lhs, rhs,
6715- getConstraintLocator(keyPathLoc, ConstraintLocator::KeyPathValue)));
67166727 break;
67176728 }
67186729 default:
@@ -12246,12 +12257,26 @@ ConstraintSystem::simplifyKeyPathConstraint(
1224612257
1224712258 if (auto fnTy = contextualTy->getAs<FunctionType>()) {
1224812259 assert(fnTy->getParams().size() == 1);
12249- // Match up the root and value types to the function's param and return
12250- // types. Note that we're using the type of the parameter as referenced
12251- // from inside the function body as we'll be transforming the code into:
12252- // { root in root[keyPath: kp] }.
12253- contextualRootTy = fnTy->getParams()[0].getParameterType();
12254- contextualValueTy = fnTy->getResult();
12260+ // Key paths may be converted to a function of compatible type. We will
12261+ // later form from this key path an implicit closure of the form
12262+ // `{ root in root[keyPath: kp] }` so any conversions that are valid with
12263+ // a source type of `(Root) -> Value` should be valid here too.
12264+ auto rootParam = AnyFunctionType::Param(rootTy);
12265+ auto kpFnTy = FunctionType::get(rootParam, valueTy, fnTy->getExtInfo());
12266+
12267+ // Note: because the keypath is applied to `root` as a parameter internal
12268+ // to the closure, we use the function parameter's "parameter type" rather
12269+ // than the raw type. This enables things like:
12270+ // ```
12271+ // let countKeyPath: (String...) -> Int = \.count
12272+ // ```
12273+ auto paramTy = fnTy->getParams()[0].getParameterType();
12274+ auto paramParam = AnyFunctionType::Param(paramTy);
12275+ auto paramFnTy = FunctionType::get(paramParam, fnTy->getResult(),
12276+ fnTy->getExtInfo());
12277+
12278+ return matchTypes(kpFnTy, paramFnTy, ConstraintKind::Conversion, subflags,
12279+ locator).isSuccess();
1225512280 }
1225612281
1225712282 assert(contextualRootTy && contextualValueTy);
0 commit comments