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