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