@@ -5682,6 +5682,19 @@ static bool isForKeyPathSubscript(ConstraintSystem &cs,
5682
5682
return false ;
5683
5683
}
5684
5684
5685
+ static bool isForKeyPathSubscriptWithoutLabel (ConstraintSystem &cs,
5686
+ ConstraintLocator *locator) {
5687
+ if (!locator || !locator->getAnchor ())
5688
+ return false ;
5689
+
5690
+ if (auto *SE = dyn_cast<SubscriptExpr>(locator->getAnchor ())) {
5691
+ auto *indexExpr = SE->getIndex ();
5692
+ return isa<ParenExpr>(indexExpr) &&
5693
+ isa<KeyPathExpr>(indexExpr->getSemanticsProvidingExpr ());
5694
+ }
5695
+ return false ;
5696
+ }
5697
+
5685
5698
// / Determine whether all of the given candidate overloads
5686
5699
// / found through conditional conformances of a given base type.
5687
5700
// / This is useful to figure out whether it makes sense to
@@ -5809,7 +5822,13 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName,
5809
5822
MemberLookupResult result;
5810
5823
result.OverallResult = MemberLookupResult::HasResults;
5811
5824
5812
- if (isForKeyPathSubscript (*this , memberLocator)) {
5825
+ // Add key path result.
5826
+ // If we are including inaccessible members, check for the use of a keypath
5827
+ // subscript without a `keyPath:` label. Add it to the result so that it
5828
+ // can be caught by the missing argument label checking later.
5829
+ if (isForKeyPathSubscript (*this , memberLocator) ||
5830
+ (isForKeyPathSubscriptWithoutLabel (*this , memberLocator)
5831
+ && includeInaccessibleMembers)) {
5813
5832
if (baseTy->isAnyObject ()) {
5814
5833
result.addUnviable (
5815
5834
OverloadChoice (baseTy, OverloadChoiceKind::KeyPathApplication),
@@ -9694,14 +9713,21 @@ ConstraintSystem::addKeyPathApplicationRootConstraint(Type root, ConstraintLocat
9694
9713
path[0 ].getKind () == ConstraintLocator::SubscriptMember) ||
9695
9714
(path.size () == 2 &&
9696
9715
path[1 ].getKind () == ConstraintLocator::KeyPathDynamicMember));
9716
+
9697
9717
auto indexTuple = dyn_cast<TupleExpr>(subscript->getIndex ());
9698
- if (!indexTuple || indexTuple->getNumElements () != 1 )
9699
- return ;
9700
-
9701
- auto keyPathExpr = dyn_cast<KeyPathExpr>(indexTuple->getElement (0 ));
9718
+ auto indexParen = dyn_cast<ParenExpr>(subscript->getIndex ());
9719
+ // If a keypath subscript is used without the expected `keyPath:` label,
9720
+ // continue with type-checking when attempting fixes so that it gets caught
9721
+ // by the argument label checking. In such cases, the KeyPathExpr is contained
9722
+ // in a ParenExpr, instead of a TupleExpr.
9723
+ assert (((indexTuple && indexTuple->getNumElements () == 1 ) || indexParen) &&
9724
+ " Expected KeyPathExpr to be in either TupleExpr or ParenExpr" );
9725
+
9726
+ auto keyPathExpr = dyn_cast<KeyPathExpr>(
9727
+ indexTuple ? indexTuple->getElement (0 ) : indexParen->getSubExpr ());
9702
9728
if (!keyPathExpr)
9703
9729
return ;
9704
-
9730
+
9705
9731
auto typeVar = getType (keyPathExpr)->getAs <TypeVariableType>();
9706
9732
if (!typeVar)
9707
9733
return ;
0 commit comments