@@ -5222,6 +5222,13 @@ bool ConstraintSystem::repairFailures(
52225222 });
52235223 };
52245224
5225+ auto hasAnyRestriction = [&]() {
5226+ return llvm::any_of(conversionsOrFixes,
5227+ [](const RestrictionOrFix &correction) {
5228+ return bool(correction.getRestriction());
5229+ });
5230+ };
5231+
52255232 // Check whether this is a tuple with a single unlabeled element
52265233 // i.e. `(_: Int)` and return type of that element if so. Note that
52275234 // if the element is pack expansion type the tuple is significant.
@@ -5247,6 +5254,40 @@ bool ConstraintSystem::repairFailures(
52475254 return true;
52485255 }
52495256
5257+ auto maybeRepairKeyPathResultFailure = [&](KeyPathExpr *kpExpr) {
5258+ if (lhs->isPlaceholder() || rhs->isPlaceholder())
5259+ return true;
5260+ if (lhs->isTypeVariableOrMember() || rhs->isTypeVariableOrMember())
5261+ return false;
5262+
5263+ if (hasConversionOrRestriction(ConversionRestrictionKind::DeepEquality) ||
5264+ hasConversionOrRestriction(ConversionRestrictionKind::ValueToOptional))
5265+ return false;
5266+
5267+ auto i = kpExpr->getComponents().size() - 1;
5268+ auto lastCompLoc =
5269+ getConstraintLocator(kpExpr, LocatorPathElt::KeyPathComponent(i));
5270+ if (hasFixFor(lastCompLoc, FixKind::AllowTypeOrInstanceMember))
5271+ return true;
5272+
5273+ auto *keyPathLoc = getConstraintLocator(anchor);
5274+
5275+ if (hasFixFor(keyPathLoc))
5276+ return true;
5277+
5278+ if (auto contextualInfo = getContextualTypeInfo(anchor)) {
5279+ if (hasFixFor(getConstraintLocator(
5280+ keyPathLoc,
5281+ LocatorPathElt::ContextualType(contextualInfo->purpose))))
5282+ return true;
5283+ }
5284+
5285+ conversionsOrFixes.push_back(IgnoreContextualType::create(
5286+ *this, lhs, rhs,
5287+ getConstraintLocator(keyPathLoc, ConstraintLocator::KeyPathValue)));
5288+ return true;
5289+ };
5290+
52505291 if (path.empty()) {
52515292 if (!anchor)
52525293 return false;
@@ -5266,9 +5307,9 @@ bool ConstraintSystem::repairFailures(
52665307 // instance fix recorded.
52675308 if (auto *kpExpr = getAsExpr<KeyPathExpr>(anchor)) {
52685309 if (isKnownKeyPathType(lhs) && isKnownKeyPathType(rhs)) {
5269- // If we have keypath capabilities for both sides and one of the bases
5270- // is unresolved, it is too early to record fix .
5271- if (hasConversionOrRestriction(ConversionRestrictionKind::DeepEquality ))
5310+ // If we have a conversion happening here, we should let fix happen in
5311+ // simplifyRestrictedConstraint .
5312+ if (hasAnyRestriction( ))
52725313 return false;
52735314 }
52745315
@@ -5668,10 +5709,7 @@ bool ConstraintSystem::repairFailures(
56685709
56695710 // If there are any restrictions here we need to wait and let
56705711 // `simplifyRestrictedConstraintImpl` handle them.
5671- if (llvm::any_of(conversionsOrFixes,
5672- [](const RestrictionOrFix &correction) {
5673- return bool(correction.getRestriction());
5674- }))
5712+ if (hasAnyRestriction())
56755713 break;
56765714
56775715 if (auto *fix = fixPropertyWrapperFailure(
@@ -6090,10 +6128,7 @@ bool ConstraintSystem::repairFailures(
60906128
60916129 // If there are any restrictions here we need to wait and let
60926130 // `simplifyRestrictedConstraintImpl` handle them.
6093- if (llvm::any_of(conversionsOrFixes,
6094- [](const RestrictionOrFix &correction) {
6095- return bool(correction.getRestriction());
6096- }))
6131+ if (hasAnyRestriction())
60976132 break;
60986133
60996134 // `lhs` - is an result type and `rhs` is a contextual type.
@@ -6112,6 +6147,10 @@ bool ConstraintSystem::repairFailures(
61126147 return true;
61136148 }
61146149
6150+ if (auto *kpExpr = getAsExpr<KeyPathExpr>(anchor)) {
6151+ return maybeRepairKeyPathResultFailure(kpExpr);
6152+ }
6153+
61156154 auto *loc = getConstraintLocator(anchor, {path.begin(), path.end() - 1});
61166155 // If this is a mismatch between contextual type and (trailing)
61176156 // closure with explicitly specified result type let's record it
@@ -6683,37 +6722,9 @@ bool ConstraintSystem::repairFailures(
66836722 return true;
66846723 }
66856724 case ConstraintLocator::KeyPathValue: {
6686- if (lhs->isPlaceholder() || rhs->isPlaceholder())
6687- return true;
6688- if (lhs->isTypeVariableOrMember() || rhs->isTypeVariableOrMember())
6689- break;
6690-
6691- if (hasConversionOrRestriction(ConversionRestrictionKind::DeepEquality) ||
6692- hasConversionOrRestriction(ConversionRestrictionKind::ValueToOptional))
6693- return false;
6694-
6695- auto kpExpr = castToExpr<KeyPathExpr>(anchor);
6696- auto i = kpExpr->getComponents().size() - 1;
6697- auto lastCompLoc =
6698- getConstraintLocator(kpExpr, LocatorPathElt::KeyPathComponent(i));
6699- if (hasFixFor(lastCompLoc, FixKind::AllowTypeOrInstanceMember))
6725+ if (maybeRepairKeyPathResultFailure(getAsExpr<KeyPathExpr>(anchor)))
67006726 return true;
67016727
6702- auto *keyPathLoc = getConstraintLocator(anchor);
6703-
6704- if (hasFixFor(keyPathLoc))
6705- return true;
6706-
6707- if (auto contextualInfo = getContextualTypeInfo(anchor)) {
6708- if (hasFixFor(getConstraintLocator(
6709- keyPathLoc,
6710- LocatorPathElt::ContextualType(contextualInfo->purpose))))
6711- return true;
6712- }
6713-
6714- conversionsOrFixes.push_back(IgnoreContextualType::create(
6715- *this, lhs, rhs,
6716- getConstraintLocator(keyPathLoc, ConstraintLocator::KeyPathValue)));
67176728 break;
67186729 }
67196730 default:
@@ -12257,12 +12268,26 @@ ConstraintSystem::simplifyKeyPathConstraint(
1225712268
1225812269 if (auto fnTy = contextualTy->getAs<FunctionType>()) {
1225912270 assert(fnTy->getParams().size() == 1);
12260- // Match up the root and value types to the function's param and return
12261- // types. Note that we're using the type of the parameter as referenced
12262- // from inside the function body as we'll be transforming the code into:
12263- // { root in root[keyPath: kp] }.
12264- contextualRootTy = fnTy->getParams()[0].getParameterType();
12265- contextualValueTy = fnTy->getResult();
12271+ // Key paths may be converted to a function of compatible type. We will
12272+ // later form from this key path an implicit closure of the form
12273+ // `{ root in root[keyPath: kp] }` so any conversions that are valid with
12274+ // a source type of `(Root) -> Value` should be valid here too.
12275+ auto rootParam = AnyFunctionType::Param(rootTy);
12276+ auto kpFnTy = FunctionType::get(rootParam, valueTy, fnTy->getExtInfo());
12277+
12278+ // Note: because the keypath is applied to `root` as a parameter internal
12279+ // to the closure, we use the function parameter's "parameter type" rather
12280+ // than the raw type. This enables things like:
12281+ // ```
12282+ // let countKeyPath: (String...) -> Int = \.count
12283+ // ```
12284+ auto paramTy = fnTy->getParams()[0].getParameterType();
12285+ auto paramParam = AnyFunctionType::Param(paramTy);
12286+ auto paramFnTy = FunctionType::get(paramParam, fnTy->getResult(),
12287+ fnTy->getExtInfo());
12288+
12289+ return matchTypes(kpFnTy, paramFnTy, ConstraintKind::Conversion, subflags,
12290+ locator).isSuccess();
1226612291 }
1226712292
1226812293 assert(contextualRootTy && contextualValueTy);
0 commit comments