@@ -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),
@@ -9693,14 +9712,21 @@ ConstraintSystem::addKeyPathApplicationRootConstraint(Type root, ConstraintLocat
9693
9712
path[0 ].getKind () == ConstraintLocator::SubscriptMember) ||
9694
9713
(path.size () == 2 &&
9695
9714
path[1 ].getKind () == ConstraintLocator::KeyPathDynamicMember));
9715
+
9696
9716
auto indexTuple = dyn_cast<TupleExpr>(subscript->getIndex ());
9697
- if (!indexTuple || indexTuple->getNumElements () != 1 )
9698
- return ;
9699
-
9700
- auto keyPathExpr = dyn_cast<KeyPathExpr>(indexTuple->getElement (0 ));
9717
+ auto indexParen = dyn_cast<ParenExpr>(subscript->getIndex ());
9718
+ // If a keypath subscript is used without the expected `keyPath:` label,
9719
+ // continue with type-checking when attempting fixes so that it gets caught
9720
+ // by the argument label checking. In such cases, the KeyPathExpr is contained
9721
+ // in a ParenExpr, instead of a TupleExpr.
9722
+ assert (((indexTuple && indexTuple->getNumElements () == 1 ) || indexParen) &&
9723
+ " Expected KeyPathExpr to be in either TupleExpr or ParenExpr" );
9724
+
9725
+ auto keyPathExpr = dyn_cast<KeyPathExpr>(
9726
+ indexTuple ? indexTuple->getElement (0 ) : indexParen->getSubExpr ());
9701
9727
if (!keyPathExpr)
9702
9728
return ;
9703
-
9729
+
9704
9730
auto typeVar = getType (keyPathExpr)->getAs <TypeVariableType>();
9705
9731
if (!typeVar)
9706
9732
return ;
0 commit comments