Skip to content

Commit fc635cf

Browse files
authored
[CSDiagnostics] Find argument lists for key path subscripts (#27492)
[CSDiagnostics] Find argument lists for key path subscripts
2 parents 3ec5e76 + c108dae commit fc635cf

File tree

4 files changed

+59
-27
lines changed

4 files changed

+59
-27
lines changed

lib/Sema/CSDiagnostics.cpp

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -94,18 +94,19 @@ Expr *FailureDiagnostic::findParentExpr(Expr *subExpr) const {
9494
return E ? E->getParentMap()[subExpr] : nullptr;
9595
}
9696

97-
Expr *FailureDiagnostic::getArgumentExprFor(Expr *anchor) const {
98-
if (auto *UDE = dyn_cast<UnresolvedDotExpr>(anchor)) {
99-
if (auto *call = dyn_cast_or_null<CallExpr>(findParentExpr(UDE)))
100-
return call->getArg();
101-
} else if (auto *UME = dyn_cast<UnresolvedMemberExpr>(anchor)) {
102-
return UME->getArgument();
103-
} else if (auto *call = dyn_cast<CallExpr>(anchor)) {
104-
return call->getArg();
105-
} else if (auto *SE = dyn_cast<SubscriptExpr>(anchor)) {
106-
return SE->getIndex();
107-
}
108-
return nullptr;
97+
Expr *
98+
FailureDiagnostic::getArgumentListExprFor(ConstraintLocator *locator) const {
99+
auto path = locator->getPath();
100+
auto iter = path.begin();
101+
if (!locator->findFirst<LocatorPathElt::ApplyArgument>(iter))
102+
return nullptr;
103+
104+
// Form a new locator that ends at the ApplyArgument element, then simplify
105+
// to get the argument list.
106+
auto newPath = ArrayRef<LocatorPathElt>(path.begin(), iter + 1);
107+
auto &cs = getConstraintSystem();
108+
auto argListLoc = cs.getConstraintLocator(locator->getAnchor(), newPath);
109+
return simplifyLocatorToAnchor(argListLoc);
109110
}
110111

111112
Expr *FailureDiagnostic::getBaseExprFor(Expr *anchor) const {
@@ -836,21 +837,18 @@ bool GenericArgumentsMismatchFailure::diagnoseAsError() {
836837
}
837838

838839
bool LabelingFailure::diagnoseAsError() {
839-
auto &cs = getConstraintSystem();
840-
auto *anchor = getRawAnchor();
841-
842-
auto *argExpr = getArgumentExprFor(anchor);
840+
auto *argExpr = getArgumentListExprFor(getLocator());
843841
if (!argExpr)
844842
return false;
845843

844+
auto &cs = getConstraintSystem();
845+
auto *anchor = getRawAnchor();
846846
return diagnoseArgumentLabelError(cs.getASTContext(), argExpr, CorrectLabels,
847847
isa<SubscriptExpr>(anchor));
848848
}
849849

850850
bool LabelingFailure::diagnoseAsNote() {
851-
auto *anchor = getRawAnchor();
852-
853-
auto *argExpr = getArgumentExprFor(anchor);
851+
auto *argExpr = getArgumentListExprFor(getLocator());
854852
if (!argExpr)
855853
return false;
856854

@@ -4181,7 +4179,8 @@ bool ClosureParamDestructuringFailure::diagnoseAsError() {
41814179

41824180
bool OutOfOrderArgumentFailure::diagnoseAsError() {
41834181
auto *anchor = getRawAnchor();
4184-
auto *argExpr = isa<TupleExpr>(anchor) ? anchor : getArgumentExprFor(anchor);
4182+
auto *argExpr = isa<TupleExpr>(anchor) ? anchor
4183+
: getArgumentListExprFor(getLocator());
41854184
if (!argExpr)
41864185
return false;
41874186

@@ -4830,7 +4829,7 @@ bool InvalidTupleSplatWithSingleParameterFailure::diagnoseAsError() {
48304829

48314830
auto *choice = selectedOverload->choice.getDecl();
48324831

4833-
auto *argExpr = getArgumentExprFor(getRawAnchor());
4832+
auto *argExpr = getArgumentListExprFor(getLocator());
48344833
if (!argExpr)
48354834
return false;
48364835

lib/Sema/CSDiagnostics.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -166,9 +166,11 @@ class FailureDiagnostic {
166166
/// `x.foo` or `x[0]` extract and return its base expression.
167167
Expr *getBaseExprFor(Expr *anchor) const;
168168

169-
/// \returns An argument expression if given anchor is a call, member
170-
/// reference or subscript, nullptr otherwise.
171-
Expr *getArgumentExprFor(Expr *anchor) const;
169+
/// For a given locator describing an argument application, or a constraint
170+
/// within an argument application, returns the argument list for that
171+
/// application. If the locator is not for an argument application, or
172+
/// the argument list cannot be found, returns \c nullptr.
173+
Expr *getArgumentListExprFor(ConstraintLocator *locator) const;
172174

173175
/// \returns The overload choice made by the constraint system for the callee
174176
/// of a given locator's anchor, or \c None if no such choice can be found.

lib/Sema/CSSimplify.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -902,7 +902,7 @@ class ArgumentFailureTracker : public MatchCallArgumentListener {
902902
}
903903
}
904904

905-
auto *locator = CS.getConstraintLocator(anchor);
905+
auto *locator = CS.getConstraintLocator(Locator);
906906
auto *fix = RelabelArguments::create(CS, newLabels, locator);
907907
CS.recordFix(fix);
908908
// Re-labeling fixes with extraneous labels should take

test/expr/unary/keypath/keypath.swift

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -504,8 +504,11 @@ func testLabeledSubscript() {
504504
let k = \AA.[labeled: 0]
505505

506506
// TODO: These ought to work without errors.
507-
let _ = \AA.[keyPath: k] // expected-error{{}}
508-
let _ = \AA.[keyPath: \AA.[labeled: 0]] // expected-error{{}}
507+
let _ = \AA.[keyPath: k] // expected-error {{incorrect argument label in call (have 'keyPath:', expected 'labeled:')}}
508+
// expected-error@-1 {{cannot convert value of type 'KeyPath<AA, Int>' to expected argument type 'Int'}}
509+
510+
let _ = \AA.[keyPath: \AA.[labeled: 0]] // expected-error {{incorrect argument label in call (have 'keyPath:', expected 'labeled:')}}
511+
// expected-error@-1 {{cannot convert value of type 'KeyPath<AA, Int>' to expected argument type 'Int'}}
509512
}
510513

511514
func testInvalidKeyPathComponents() {
@@ -830,6 +833,34 @@ func test_keypath_inference_with_optionals() {
830833
}
831834
}
832835

836+
func sr11562() {
837+
struct S1 {
838+
subscript(x x: Int) -> Int { x }
839+
}
840+
841+
_ = \S1.[5] // expected-error {{missing argument label 'x:' in call}} {{12-12=x: }}
842+
843+
struct S2 {
844+
subscript(x x: Int) -> Int { x } // expected-note {{incorrect labels for candidate (have: '(_:)', expected: '(x:)')}}
845+
subscript(y y: Int) -> Int { y } // expected-note {{incorrect labels for candidate (have: '(_:)', expected: '(y:)')}}
846+
}
847+
848+
_ = \S2.[5] // expected-error {{no exact matches in call to subscript}}
849+
850+
struct S3 {
851+
subscript(x x: Int, y y: Int) -> Int { x }
852+
}
853+
854+
_ = \S3.[y: 5, x: 5] // expected-error {{argument 'x' must precede argument 'y'}}
855+
856+
struct S4 {
857+
subscript(x: (Int, Int)) -> Int { x.0 }
858+
}
859+
860+
_ = \S4.[1, 4] // expected-error {{subscript expects a single parameter of type '(Int, Int)'}} {{12-12=(}} {{16-16=)}}
861+
// expected-error@-1 {{subscript index of type '(Int, Int)' in a key path must be Hashable}}
862+
}
863+
833864
func testSyntaxErrors() { // expected-note{{}}
834865
_ = \. ; // expected-error{{expected member name following '.'}}
835866
_ = \.a ;

0 commit comments

Comments
 (0)