@@ -7379,6 +7379,111 @@ ConstraintSystem::lookupConformance(Type type, ProtocolDecl *protocol) {
7379
7379
return conformance;
7380
7380
}
7381
7381
7382
+ llvm::Optional<KeyPathCapability>
7383
+ ConstraintSystem::inferKeyPathLiteralCapability (TypeVariableType *keyPathType) {
7384
+ auto *typeLocator = keyPathType->getImpl ().getLocator ();
7385
+ assert (typeLocator->isLastElement <LocatorPathElt::KeyPathType>());
7386
+
7387
+ auto *keyPath = castToExpr<KeyPathExpr>(typeLocator->getAnchor ());
7388
+
7389
+ auto capability = KeyPathCapability::Writable;
7390
+
7391
+ bool didOptionalChain = false ;
7392
+
7393
+ for (unsigned i : indices (keyPath->getComponents ())) {
7394
+ auto &component = keyPath->getComponents ()[i];
7395
+
7396
+ switch (component.getKind ()) {
7397
+ case KeyPathExpr::Component::Kind::Invalid:
7398
+ case KeyPathExpr::Component::Kind::Identity:
7399
+ break ;
7400
+
7401
+ case KeyPathExpr::Component::Kind::CodeCompletion: {
7402
+ capability = KeyPathCapability::ReadOnly;
7403
+ break ;
7404
+ }
7405
+ case KeyPathExpr::Component::Kind::Property:
7406
+ case KeyPathExpr::Component::Kind::Subscript:
7407
+ case KeyPathExpr::Component::Kind::UnresolvedProperty:
7408
+ case KeyPathExpr::Component::Kind::UnresolvedSubscript: {
7409
+ auto *componentLoc =
7410
+ getConstraintLocator (keyPath, LocatorPathElt::KeyPathComponent (i));
7411
+ auto *calleeLoc = getCalleeLocator (componentLoc);
7412
+ auto overload = findSelectedOverloadFor (calleeLoc);
7413
+ if (!overload)
7414
+ return llvm::None;
7415
+
7416
+ // tuple elements do not change the capability of the key path
7417
+ auto choice = overload->choice ;
7418
+ if (choice.getKind () == OverloadChoiceKind::TupleIndex) {
7419
+ continue ;
7420
+ }
7421
+
7422
+ // Discarded unsupported non-decl member lookups.
7423
+ if (!choice.isDecl ())
7424
+ return llvm::None;
7425
+
7426
+ auto storage = dyn_cast<AbstractStorageDecl>(choice.getDecl ());
7427
+
7428
+ if (hasFixFor (calleeLoc, FixKind::AllowInvalidRefInKeyPath)) {
7429
+ if (!shouldAttemptFixes ())
7430
+ return llvm::None;
7431
+
7432
+ // If this was a method reference let's mark it as read-only.
7433
+ if (!storage) {
7434
+ capability = KeyPathCapability::ReadOnly;
7435
+ continue ;
7436
+ }
7437
+ }
7438
+
7439
+ if (!storage)
7440
+ return llvm::None;
7441
+
7442
+ if (isReadOnlyKeyPathComponent (storage, component.getLoc ())) {
7443
+ capability = KeyPathCapability::ReadOnly;
7444
+ continue ;
7445
+ }
7446
+
7447
+ // A nonmutating setter indicates a reference-writable base.
7448
+ if (!storage->isSetterMutating ()) {
7449
+ capability = KeyPathCapability::ReferenceWritable;
7450
+ continue ;
7451
+ }
7452
+
7453
+ // Otherwise, the key path maintains its current capability.
7454
+ break ;
7455
+ }
7456
+
7457
+ case KeyPathExpr::Component::Kind::OptionalChain:
7458
+ didOptionalChain = true ;
7459
+ break ;
7460
+
7461
+ case KeyPathExpr::Component::Kind::OptionalForce:
7462
+ // Forcing an optional preserves its lvalue-ness.
7463
+ break ;
7464
+
7465
+ case KeyPathExpr::Component::Kind::OptionalWrap:
7466
+ // An optional chain should already have been recorded.
7467
+ assert (didOptionalChain);
7468
+ break ;
7469
+
7470
+ case KeyPathExpr::Component::Kind::TupleElement:
7471
+ llvm_unreachable (" not implemented" );
7472
+ break ;
7473
+
7474
+ case KeyPathExpr::Component::Kind::DictionaryKey:
7475
+ llvm_unreachable (" DictionaryKey only valid in #keyPath" );
7476
+ break ;
7477
+ }
7478
+ }
7479
+
7480
+ // Optional chains force the entire key path to be read-only.
7481
+ if (didOptionalChain)
7482
+ capability = KeyPathCapability::ReadOnly;
7483
+
7484
+ return capability;
7485
+ }
7486
+
7382
7487
TypeVarBindingProducer::TypeVarBindingProducer (BindingSet &bindings)
7383
7488
: BindingProducer(bindings.getConstraintSystem(),
7384
7489
bindings.getTypeVariable()->getImpl().getLocator()),
0 commit comments