@@ -12193,17 +12193,15 @@ ConstraintSystem::simplifyKeyPathConstraint(
12193
12193
ConstraintLocatorBuilder locator) {
12194
12194
auto subflags = getDefaultDecompositionOptions(flags);
12195
12195
// The constraint ought to have been anchored on a KeyPathExpr.
12196
- auto keyPath = castToExpr<KeyPathExpr>(locator.getBaseLocator()-> getAnchor());
12196
+ auto keyPath = castToExpr<KeyPathExpr>(locator.getAnchor());
12197
12197
keyPathTy = getFixedTypeRecursive(keyPathTy, /*want rvalue*/ true);
12198
- bool definitelyFunctionType = false;
12199
- bool definitelyKeyPathType = false;
12200
12198
bool resolveAsMultiArgFuncFix = false;
12201
12199
12202
12200
auto formUnsolved = [&]() -> SolutionKind {
12203
12201
if (flags.contains(TMF_GenerateConstraints)) {
12204
12202
addUnsolvedConstraint(Constraint::create(
12205
12203
*this, ConstraintKind::KeyPath, keyPathTy, rootTy, valueTy,
12206
- locator.getBaseLocator( ), componentTypeVars));
12204
+ getConstraintLocator(locator ), componentTypeVars));
12207
12205
return SolutionKind::Solved;
12208
12206
}
12209
12207
return SolutionKind::Unsolved;
@@ -12212,25 +12210,18 @@ ConstraintSystem::simplifyKeyPathConstraint(
12212
12210
if (keyPathTy->isTypeVariableOrMember())
12213
12211
return formUnsolved();
12214
12212
12215
- auto tryMatchRootAndValueFromType = [&](Type type,
12216
- bool allowPartial = true) -> bool {
12213
+ auto tryMatchRootAndValueFromType = [&](Type type) -> bool {
12217
12214
Type boundRoot = Type(), boundValue = Type();
12218
12215
12219
12216
if (auto bgt = type->getAs<BoundGenericType>()) {
12220
- definitelyKeyPathType = true;
12221
-
12222
12217
// We can get root and value from a concrete key path type.
12223
12218
if (bgt->isKeyPath() ||
12224
12219
bgt->isWritableKeyPath() ||
12225
12220
bgt->isReferenceWritableKeyPath()) {
12226
12221
boundRoot = bgt->getGenericArgs()[0];
12227
12222
boundValue = bgt->getGenericArgs()[1];
12228
- } else if (bgt->isPartialKeyPath()) {
12229
- if (!allowPartial)
12230
- return false;
12231
-
12232
- // We can still get the root from a PartialKeyPath.
12233
- boundRoot = bgt->getGenericArgs()[0];
12223
+ } else {
12224
+ return false;
12234
12225
}
12235
12226
}
12236
12227
@@ -12241,13 +12232,11 @@ ConstraintSystem::simplifyKeyPathConstraint(
12241
12232
12242
12233
resolveAsMultiArgFuncFix = true;
12243
12234
auto *fix = AllowMultiArgFuncKeyPathMismatch::create(
12244
- *this, fnTy, locator.getBaseLocator( ));
12235
+ *this, fnTy, getConstraintLocator(locator ));
12245
12236
// Pretend the keypath type got resolved and move on.
12246
12237
return !recordFix(fix);
12247
12238
}
12248
12239
12249
- definitelyFunctionType = true;
12250
-
12251
12240
// Match up the root and value types to the function's param and return
12252
12241
// types. Note that we're using the type of the parameter as referenced
12253
12242
// from inside the function body as we'll be transforming the code into:
@@ -12284,192 +12273,66 @@ ConstraintSystem::simplifyKeyPathConstraint(
12284
12273
// If the root type has been bound to a hole, we cannot infer it.
12285
12274
if (getFixedTypeRecursive(rootTy, /*wantRValue*/ true)->isPlaceholder())
12286
12275
return SolutionKind::Solved;
12287
-
12288
- // If we have e.g a missing member somewhere, a component type variable
12289
- // would either be marked as a potential hole or would have a fix.
12290
- if (llvm::any_of(componentTypeVars, [&](TypeVariableType *tv) {
12291
- auto *locator = tv->getImpl().getLocator();
12292
-
12293
- // Result type of a component could be bound to a contextual
12294
- // (concrete) type if it's the last component in the chain,
12295
- // so the only way to detect errors is to check for fixes.
12296
- if (locator->isForKeyPathComponentResult()) {
12297
- auto path = locator->getPath();
12298
- auto *componentLoc =
12299
- getConstraintLocator(locator->getAnchor(), path.drop_back());
12300
-
12301
- if (hasFixFor(componentLoc, FixKind::DefineMemberBasedOnUse) ||
12302
- hasFixFor(componentLoc, FixKind::UnwrapOptionalBase) ||
12303
- hasFixFor(componentLoc,
12304
- FixKind::UnwrapOptionalBaseWithOptionalResult))
12305
- return true;
12306
- }
12307
-
12308
- // If something inside of a component is marked as a hole,
12309
- // let's consider while component to be invalid.
12310
- return locator->isInKeyPathComponent() &&
12311
- tv->getImpl().canBindToHole();
12312
- })) {
12313
- (void)tryMatchRootAndValueFromType(keyPathTy);
12314
- return SolutionKind::Solved;
12315
- }
12316
12276
}
12317
12277
12318
12278
// If we're fixed to a bound generic type, trying harvesting context from it.
12319
12279
// However, we don't want a solution that fixes the expression type to
12320
12280
// PartialKeyPath; we'd rather that be represented using an upcast conversion.
12321
- if (!tryMatchRootAndValueFromType(keyPathTy, /*allowPartial=*/false ))
12281
+ if (!tryMatchRootAndValueFromType(keyPathTy))
12322
12282
return SolutionKind::Error;
12323
12283
12324
12284
// If we fix this keypath as `AllowMultiArgFuncKeyPathMismatch`, just proceed
12325
12285
if (resolveAsMultiArgFuncFix)
12326
12286
return SolutionKind::Solved;
12327
12287
12328
- // See if we resolved overloads for all the components involved.
12329
- enum {
12330
- ReadOnly,
12331
- Writable,
12332
- ReferenceWritable
12333
- } capability = Writable;
12288
+ bool isValid;
12289
+ llvm::Optional<KeyPathCapability> capability;
12334
12290
12335
- bool anyComponentsUnresolved = false;
12336
- bool didOptionalChain = false;
12291
+ std::tie(isValid, capability) = inferKeyPathLiteralCapability(keyPath);
12337
12292
12338
- for (unsigned i : indices(keyPath->getComponents())) {
12339
- auto &component = keyPath->getComponents()[i];
12340
-
12341
- switch (component.getKind()) {
12342
- case KeyPathExpr::Component::Kind::Invalid:
12343
- case KeyPathExpr::Component::Kind::Identity:
12344
- break;
12293
+ // If key path is invalid, let's not don't attempt match capabilities.
12294
+ if (!isValid)
12295
+ return shouldAttemptFixes() ? SolutionKind::Solved : SolutionKind::Error;
12345
12296
12346
- case KeyPathExpr::Component::Kind::CodeCompletion: {
12347
- anyComponentsUnresolved = true;
12348
- capability = ReadOnly;
12349
- break;
12350
- }
12351
- case KeyPathExpr::Component::Kind::Property:
12352
- case KeyPathExpr::Component::Kind::Subscript:
12353
- case KeyPathExpr::Component::Kind::UnresolvedProperty:
12354
- case KeyPathExpr::Component::Kind::UnresolvedSubscript: {
12355
- auto *componentLoc = getConstraintLocator(
12356
- locator.withPathElement(LocatorPathElt::KeyPathComponent(i)));
12357
- auto *calleeLoc = getCalleeLocator(componentLoc);
12358
- auto overload = findSelectedOverloadFor(calleeLoc);
12359
-
12360
- // If no choice was made, leave the constraint unsolved. But when
12361
- // generating constraints, we may already have enough information
12362
- // to determine whether the result will be a function type vs BGT KeyPath
12363
- // type, so continue through components to create new constraint at the
12364
- // end.
12365
- if (!overload) {
12366
- if (flags.contains(TMF_GenerateConstraints)) {
12367
- anyComponentsUnresolved = true;
12368
- continue;
12369
- }
12370
- return SolutionKind::Unsolved;
12371
- }
12372
-
12373
- // tuple elements do not change the capability of the key path
12374
- auto choice = overload->choice;
12375
- if (choice.getKind() == OverloadChoiceKind::TupleIndex) {
12376
- continue;
12377
- }
12378
-
12379
- // Discarded unsupported non-decl member lookups.
12380
- if (!choice.isDecl()) {
12381
- return SolutionKind::Error;
12382
- }
12383
-
12384
- auto storage = dyn_cast<AbstractStorageDecl>(choice.getDecl());
12385
-
12386
- if (hasFixFor(calleeLoc, FixKind::AllowInvalidRefInKeyPath)) {
12387
- return shouldAttemptFixes() ? SolutionKind::Solved
12388
- : SolutionKind::Error;
12389
- }
12390
-
12391
- if (!storage)
12392
- return SolutionKind::Error;
12393
-
12394
- if (isReadOnlyKeyPathComponent(storage, component.getLoc())) {
12395
- capability = ReadOnly;
12396
- continue;
12397
- }
12398
-
12399
- // A nonmutating setter indicates a reference-writable base.
12400
- if (!storage->isSetterMutating()) {
12401
- capability = ReferenceWritable;
12402
- continue;
12403
- }
12404
-
12405
- // Otherwise, the key path maintains its current capability.
12406
- break;
12407
- }
12408
-
12409
- case KeyPathExpr::Component::Kind::OptionalChain:
12410
- didOptionalChain = true;
12411
- break;
12412
-
12413
- case KeyPathExpr::Component::Kind::OptionalForce:
12414
- // Forcing an optional preserves its lvalue-ness.
12415
- break;
12416
-
12417
- case KeyPathExpr::Component::Kind::OptionalWrap:
12418
- // An optional chain should already have been recorded.
12419
- assert(didOptionalChain);
12420
- break;
12421
-
12422
- case KeyPathExpr::Component::Kind::TupleElement:
12423
- llvm_unreachable("not implemented");
12424
- break;
12425
- case KeyPathExpr::Component::Kind::DictionaryKey:
12426
- llvm_unreachable("DictionaryKey only valid in #keyPath");
12427
- break;
12428
- }
12429
- }
12430
-
12431
- // Optional chains force the entire key path to be read-only.
12432
- if (didOptionalChain)
12433
- capability = ReadOnly;
12297
+ // If key path is valid but not yet sufficiently resolved, let's delay
12298
+ // capability checking.
12299
+ if (!capability)
12300
+ return formUnsolved();
12434
12301
12435
12302
// Resolve the type.
12436
12303
NominalTypeDecl *kpDecl;
12437
- switch (capability) {
12438
- case ReadOnly:
12304
+ switch (* capability) {
12305
+ case KeyPathCapability:: ReadOnly:
12439
12306
kpDecl = getASTContext().getKeyPathDecl();
12440
12307
break;
12441
12308
12442
- case Writable:
12309
+ case KeyPathCapability:: Writable:
12443
12310
kpDecl = getASTContext().getWritableKeyPathDecl();
12444
12311
break;
12445
12312
12446
- case ReferenceWritable:
12313
+ case KeyPathCapability:: ReferenceWritable:
12447
12314
kpDecl = getASTContext().getReferenceWritableKeyPathDecl();
12448
12315
break;
12449
12316
}
12450
-
12317
+
12451
12318
// FIXME: Allow the type to be upcast if the type system has a concrete
12452
12319
// KeyPath type assigned to the expression already.
12453
12320
if (auto keyPathBGT = keyPathTy->getAs<BoundGenericType>()) {
12454
12321
if (keyPathBGT->isKeyPath())
12455
12322
kpDecl = getASTContext().getKeyPathDecl();
12456
- else if (keyPathBGT->isWritableKeyPath() && capability >= Writable)
12323
+ else if (keyPathBGT->isWritableKeyPath() &&
12324
+ *capability >= KeyPathCapability::Writable)
12457
12325
kpDecl = getASTContext().getWritableKeyPathDecl();
12458
12326
}
12459
12327
12460
- auto loc = locator.getBaseLocator();
12461
- if (definitelyFunctionType) {
12328
+ if (keyPathTy->is<FunctionType>()) {
12462
12329
increaseScore(SK_FunctionConversion, locator);
12463
12330
return SolutionKind::Solved;
12464
- } else if (!anyComponentsUnresolved ||
12465
- (definitelyKeyPathType && capability == ReadOnly)) {
12466
- auto resolvedKPTy =
12467
- BoundGenericType::get(kpDecl, nullptr, {rootTy, valueTy});
12468
- return matchTypes(resolvedKPTy, keyPathTy, ConstraintKind::Bind, subflags,
12469
- loc);
12470
12331
}
12471
12332
12472
- return formUnsolved();
12333
+ auto resolvedKPTy = BoundGenericType::get(kpDecl, nullptr, {rootTy, valueTy});
12334
+ return matchTypes(resolvedKPTy, keyPathTy, ConstraintKind::Bind, subflags,
12335
+ locator);
12473
12336
}
12474
12337
12475
12338
ConstraintSystem::SolutionKind
0 commit comments