@@ -12180,8 +12180,6 @@ ConstraintSystem::simplifyKeyPathConstraint(
12180
12180
TypeMatchOptions flags,
12181
12181
ConstraintLocatorBuilder locator) {
12182
12182
auto subflags = getDefaultDecompositionOptions(flags);
12183
- // The constraint ought to have been anchored on a KeyPathExpr.
12184
- auto keyPath = castToExpr<KeyPathExpr>(locator.getAnchor());
12185
12183
keyPathTy = getFixedTypeRecursive(keyPathTy, /*want rvalue*/ true);
12186
12184
12187
12185
auto formUnsolved = [&]() -> SolutionKind {
@@ -12197,49 +12195,48 @@ ConstraintSystem::simplifyKeyPathConstraint(
12197
12195
if (keyPathTy->isTypeVariableOrMember())
12198
12196
return formUnsolved();
12199
12197
12200
- auto tryMatchRootAndValueFromType = [&](Type type ) -> bool {
12201
- Type boundRoot = Type(), boundValue = Type();
12198
+ auto tryMatchRootAndValueFromContextualType = [&](Type contextualTy ) -> bool {
12199
+ Type contextualRootTy = Type(), contextualValueTy = Type();
12202
12200
12203
- if (auto bgt = type->getAs<BoundGenericType>()) {
12201
+ // Placeholders are only allowed in the diagnostic mode so it's
12202
+ // okay to simply return `true` here.
12203
+ if (contextualTy->isPlaceholder())
12204
+ return true;
12205
+
12206
+ // If there are no other options the solver might end up picking
12207
+ // `AnyKeyPath` or `PartialKeyPath` based on a contextual conversion.
12208
+ // This is an error during normal type-checking but okay in
12209
+ // diagnostic mode because root and value are allowed to be holes.
12210
+ if (contextualTy->isAnyKeyPath() || contextualTy->isPartialKeyPath())
12211
+ return shouldAttemptFixes();
12212
+
12213
+ if (auto bgt = contextualTy->getAs<BoundGenericType>()) {
12204
12214
// We can get root and value from a concrete key path type.
12205
- if (bgt->isKeyPath() ||
12206
- bgt->isWritableKeyPath() ||
12207
- bgt->isReferenceWritableKeyPath()) {
12208
- boundRoot = bgt->getGenericArgs()[0];
12209
- boundValue = bgt->getGenericArgs()[1];
12210
- } else {
12211
- return false;
12212
- }
12215
+ assert(bgt->isKeyPath() || bgt->isWritableKeyPath() ||
12216
+ bgt->isReferenceWritableKeyPath());
12217
+
12218
+ contextualRootTy = bgt->getGenericArgs()[0];
12219
+ contextualValueTy = bgt->getGenericArgs()[1];
12213
12220
}
12214
12221
12215
- if (auto fnTy = type ->getAs<FunctionType>()) {
12222
+ if (auto fnTy = contextualTy ->getAs<FunctionType>()) {
12216
12223
assert(fnTy->getParams().size() == 1);
12217
12224
// Match up the root and value types to the function's param and return
12218
12225
// types. Note that we're using the type of the parameter as referenced
12219
12226
// from inside the function body as we'll be transforming the code into:
12220
12227
// { root in root[keyPath: kp] }.
12221
- boundRoot = fnTy->getParams()[0].getParameterType();
12222
- boundValue = fnTy->getResult();
12223
-
12224
- // Key paths never throw, so if the function has a thrown error type
12225
- // that is a type variable, infer it to be Never.
12226
- if (auto thrownError = fnTy->getThrownError()) {
12227
- if (thrownError->isTypeVariableOrMember()) {
12228
- (void)matchTypes(
12229
- thrownError, getASTContext().getNeverType(),
12230
- ConstraintKind::Equal, TMF_GenerateConstraints, locator);
12231
- }
12232
- }
12228
+ contextualRootTy = fnTy->getParams()[0].getParameterType();
12229
+ contextualValueTy = fnTy->getResult();
12233
12230
}
12234
12231
12235
- if (boundRoot &&
12236
- matchTypes(rootTy, boundRoot, ConstraintKind::Bind, subflags,
12232
+ assert(contextualRootTy && contextualValueTy);
12233
+
12234
+ if (matchTypes(rootTy, contextualRootTy, ConstraintKind::Bind, subflags,
12237
12235
locator.withPathElement(ConstraintLocator::KeyPathRoot))
12238
12236
.isFailure())
12239
12237
return false;
12240
12238
12241
- if (boundValue &&
12242
- matchTypes(valueTy, boundValue, ConstraintKind::Bind, subflags,
12239
+ if (matchTypes(valueTy, contextualValueTy, ConstraintKind::Bind, subflags,
12243
12240
locator.withPathElement(ConstraintLocator::KeyPathValue))
12244
12241
.isFailure())
12245
12242
return false;
@@ -12252,6 +12249,16 @@ ConstraintSystem::simplifyKeyPathConstraint(
12252
12249
if (auto *fnTy = keyPathTy->getAs<FunctionType>()) {
12253
12250
increaseScore(SK_FunctionConversion, locator);
12254
12251
12252
+ // Key paths never throw, so if the function has a thrown error type
12253
+ // that is a type variable, infer it to be Never.
12254
+ if (auto thrownError = fnTy->getThrownError()) {
12255
+ if (thrownError->isTypeVariableOrMember()) {
12256
+ (void)matchTypes(thrownError, getASTContext().getNeverType(),
12257
+ ConstraintKind::Equal, TMF_GenerateConstraints,
12258
+ locator);
12259
+ }
12260
+ }
12261
+
12255
12262
if (fnTy->getParams().size() != 1) {
12256
12263
if (!shouldAttemptFixes())
12257
12264
return SolutionKind::Error;
@@ -12269,8 +12276,7 @@ ConstraintSystem::simplifyKeyPathConstraint(
12269
12276
// If we have a hole somewhere in the key path, the solver won't be able to
12270
12277
// infer the key path type. So let's just assume this is solved.
12271
12278
if (shouldAttemptFixes()) {
12272
- if (keyPathTy->isPlaceholder())
12273
- return SolutionKind::Solved;
12279
+ auto keyPath = castToExpr<KeyPathExpr>(locator.getAnchor());
12274
12280
12275
12281
if (hasFixFor(getConstraintLocator(keyPath),
12276
12282
FixKind::AllowKeyPathWithoutComponents))
@@ -12281,11 +12287,9 @@ ConstraintSystem::simplifyKeyPathConstraint(
12281
12287
return SolutionKind::Solved;
12282
12288
}
12283
12289
12284
- // If we're fixed to a bound generic type, trying harvesting context from it.
12285
- // However, we don't want a solution that fixes the expression type to
12286
- // PartialKeyPath; we'd rather that be represented using an upcast conversion.
12287
- return tryMatchRootAndValueFromType(keyPathTy) ? SolutionKind::Solved
12288
- : SolutionKind::Error;
12290
+ return tryMatchRootAndValueFromContextualType(keyPathTy)
12291
+ ? SolutionKind::Solved
12292
+ : SolutionKind::Error;
12289
12293
}
12290
12294
12291
12295
ConstraintSystem::SolutionKind
0 commit comments