@@ -5674,6 +5674,19 @@ static bool isForKeyPathSubscript(ConstraintSystem &cs,
5674
5674
return false ;
5675
5675
}
5676
5676
5677
+ static bool isForKeyPathSubscriptWithoutLabel (ConstraintSystem &cs,
5678
+ ConstraintLocator *locator) {
5679
+ if (!locator || !locator->getAnchor ())
5680
+ return false ;
5681
+
5682
+ if (auto *SE = getAsExpr<SubscriptExpr>(locator->getAnchor ())) {
5683
+ auto *indexExpr = SE->getIndex ();
5684
+ return isa<ParenExpr>(indexExpr) &&
5685
+ isa<KeyPathExpr>(indexExpr->getSemanticsProvidingExpr ());
5686
+ }
5687
+ return false ;
5688
+ }
5689
+
5677
5690
// / Determine whether all of the given candidate overloads
5678
5691
// / found through conditional conformances of a given base type.
5679
5692
// / This is useful to figure out whether it makes sense to
@@ -5801,7 +5814,13 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName,
5801
5814
MemberLookupResult result;
5802
5815
result.OverallResult = MemberLookupResult::HasResults;
5803
5816
5804
- if (isForKeyPathSubscript (*this , memberLocator)) {
5817
+ // Add key path result.
5818
+ // If we are including inaccessible members, check for the use of a keypath
5819
+ // subscript without a `keyPath:` label. Add it to the result so that it
5820
+ // can be caught by the missing argument label checking later.
5821
+ if (isForKeyPathSubscript (*this , memberLocator) ||
5822
+ (isForKeyPathSubscriptWithoutLabel (*this , memberLocator)
5823
+ && includeInaccessibleMembers)) {
5805
5824
if (baseTy->isAnyObject ()) {
5806
5825
result.addUnviable (
5807
5826
OverloadChoice (baseTy, OverloadChoiceKind::KeyPathApplication),
@@ -9700,14 +9719,21 @@ ConstraintSystem::addKeyPathApplicationRootConstraint(Type root, ConstraintLocat
9700
9719
path[0 ].getKind () == ConstraintLocator::SubscriptMember) ||
9701
9720
(path.size () == 2 &&
9702
9721
path[1 ].getKind () == ConstraintLocator::KeyPathDynamicMember));
9722
+
9703
9723
auto indexTuple = dyn_cast<TupleExpr>(subscript->getIndex ());
9704
- if (!indexTuple || indexTuple->getNumElements () != 1 )
9705
- return ;
9706
-
9707
- auto keyPathExpr = dyn_cast<KeyPathExpr>(indexTuple->getElement (0 ));
9724
+ auto indexParen = dyn_cast<ParenExpr>(subscript->getIndex ());
9725
+ // If a keypath subscript is used without the expected `keyPath:` label,
9726
+ // continue with type-checking when attempting fixes so that it gets caught
9727
+ // by the argument label checking. In such cases, the KeyPathExpr is contained
9728
+ // in a ParenExpr, instead of a TupleExpr.
9729
+ assert (((indexTuple && indexTuple->getNumElements () == 1 ) || indexParen) &&
9730
+ " Expected KeyPathExpr to be in either TupleExpr or ParenExpr" );
9731
+
9732
+ auto keyPathExpr = dyn_cast<KeyPathExpr>(
9733
+ indexTuple ? indexTuple->getElement (0 ) : indexParen->getSubExpr ());
9708
9734
if (!keyPathExpr)
9709
9735
return ;
9710
-
9736
+
9711
9737
auto typeVar = getType (keyPathExpr)->getAs <TypeVariableType>();
9712
9738
if (!typeVar)
9713
9739
return ;
0 commit comments