@@ -5221,6 +5221,13 @@ bool ConstraintSystem::repairFailures(
5221
5221
});
5222
5222
};
5223
5223
5224
+ auto hasAnyRestriction = [&]() {
5225
+ return llvm::any_of(conversionsOrFixes,
5226
+ [](const RestrictionOrFix &correction) {
5227
+ return bool(correction.getRestriction());
5228
+ });
5229
+ };
5230
+
5224
5231
// Check whether this is a tuple with a single unlabeled element
5225
5232
// i.e. `(_: Int)` and return type of that element if so. Note that
5226
5233
// if the element is pack expansion type the tuple is significant.
@@ -5246,6 +5253,40 @@ bool ConstraintSystem::repairFailures(
5246
5253
return true;
5247
5254
}
5248
5255
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
+
5249
5290
if (path.empty()) {
5250
5291
if (!anchor)
5251
5292
return false;
@@ -5265,9 +5306,9 @@ bool ConstraintSystem::repairFailures(
5265
5306
// instance fix recorded.
5266
5307
if (auto *kpExpr = getAsExpr<KeyPathExpr>(anchor)) {
5267
5308
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( ))
5271
5312
return false;
5272
5313
}
5273
5314
@@ -5667,10 +5708,7 @@ bool ConstraintSystem::repairFailures(
5667
5708
5668
5709
// If there are any restrictions here we need to wait and let
5669
5710
// `simplifyRestrictedConstraintImpl` handle them.
5670
- if (llvm::any_of(conversionsOrFixes,
5671
- [](const RestrictionOrFix &correction) {
5672
- return bool(correction.getRestriction());
5673
- }))
5711
+ if (hasAnyRestriction())
5674
5712
break;
5675
5713
5676
5714
if (auto *fix = fixPropertyWrapperFailure(
@@ -6089,10 +6127,7 @@ bool ConstraintSystem::repairFailures(
6089
6127
6090
6128
// If there are any restrictions here we need to wait and let
6091
6129
// `simplifyRestrictedConstraintImpl` handle them.
6092
- if (llvm::any_of(conversionsOrFixes,
6093
- [](const RestrictionOrFix &correction) {
6094
- return bool(correction.getRestriction());
6095
- }))
6130
+ if (hasAnyRestriction())
6096
6131
break;
6097
6132
6098
6133
// `lhs` - is an result type and `rhs` is a contextual type.
@@ -6111,6 +6146,10 @@ bool ConstraintSystem::repairFailures(
6111
6146
return true;
6112
6147
}
6113
6148
6149
+ if (auto *kpExpr = getAsExpr<KeyPathExpr>(anchor)) {
6150
+ return maybeRepairKeyPathResultFailure(kpExpr);
6151
+ }
6152
+
6114
6153
auto *loc = getConstraintLocator(anchor, {path.begin(), path.end() - 1});
6115
6154
// If this is a mismatch between contextual type and (trailing)
6116
6155
// closure with explicitly specified result type let's record it
@@ -6682,37 +6721,9 @@ bool ConstraintSystem::repairFailures(
6682
6721
return true;
6683
6722
}
6684
6723
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)))
6699
6725
return true;
6700
6726
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)));
6716
6727
break;
6717
6728
}
6718
6729
default:
@@ -12246,12 +12257,26 @@ ConstraintSystem::simplifyKeyPathConstraint(
12246
12257
12247
12258
if (auto fnTy = contextualTy->getAs<FunctionType>()) {
12248
12259
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();
12255
12280
}
12256
12281
12257
12282
assert(contextualRootTy && contextualValueTy);
0 commit comments