Skip to content

Commit 054e3e4

Browse files
committed
[Diagnostics] SR-2242: Fix diagnostic when argument label is omitted
1 parent 2dfc8b6 commit 054e3e4

File tree

4 files changed

+64
-3
lines changed

4 files changed

+64
-3
lines changed

lib/Sema/CSDiag.cpp

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1274,6 +1274,9 @@ CalleeCandidateInfo::evaluateCloseness(DeclContext *dc, Type candArgListType,
12741274
void missingArgument(unsigned paramIdx) override {
12751275
result = CC_ArgumentCountMismatch;
12761276
}
1277+
void missingLabel(unsigned paramIdx) override {
1278+
result = CC_ArgumentLabelMismatch;
1279+
}
12771280
void outOfOrderArgument(unsigned argIdx, unsigned prevArgIdx) override {
12781281
result = CC_ArgumentLabelMismatch;
12791282
}
@@ -4681,7 +4684,7 @@ static bool diagnoseSingleCandidateFailures(CalleeCandidateInfo &CCI,
46814684

46824685
CalleeCandidateInfo CandidateInfo;
46834686

4684-
// Indicates if problem was been found and diagnostic was emitted.
4687+
// Indicates if problem has been found and diagnostic was emitted.
46854688
bool Diagnosed = false;
46864689
// Indicates if functions we are trying to call is a subscript.
46874690
bool IsSubscript;
@@ -4740,6 +4743,15 @@ static bool diagnoseSingleCandidateFailures(CalleeCandidateInfo &CCI,
47404743
Diagnosed = true;
47414744
}
47424745

4746+
void missingLabel(unsigned paramIdx) override {
4747+
auto tuple = cast<TupleExpr>(ArgExpr);
4748+
TC.diagnose(tuple->getElement(paramIdx)->getStartLoc(),
4749+
diag::missing_argument_labels, false,
4750+
Parameters[paramIdx].Label.str(), IsSubscript);
4751+
4752+
Diagnosed = true;
4753+
}
4754+
47434755
void outOfOrderArgument(unsigned argIdx, unsigned prevArgIdx) override {
47444756
auto tuple = cast<TupleExpr>(ArgExpr);
47454757
Identifier first = tuple->getElementName(argIdx);
@@ -4768,6 +4780,7 @@ static bool diagnoseSingleCandidateFailures(CalleeCandidateInfo &CCI,
47684780
auto secondRange = argRange(prevArgIdx, second);
47694781

47704782
SourceLoc diagLoc = firstRange.Start;
4783+
47714784
if (first.empty() && second.empty()) {
47724785
TC.diagnose(diagLoc, diag::argument_out_of_order_unnamed_unnamed,
47734786
argIdx + 1, prevArgIdx + 1)

lib/Sema/CSSimplify.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ void MatchCallArgumentListener::extraArgument(unsigned argIdx) { }
2828

2929
void MatchCallArgumentListener::missingArgument(unsigned paramIdx) { }
3030

31+
void MatchCallArgumentListener::missingLabel(unsigned paramIdx) {}
32+
3133
void MatchCallArgumentListener::outOfOrderArgument(unsigned argIdx,
3234
unsigned prevArgIdx) {
3335
}
@@ -454,6 +456,27 @@ matchCallArguments(ArrayRef<CallArgParam> args,
454456
}
455457

456458
unsigned prevArgIdx = parameterBindings[prevParamIdx].front();
459+
460+
// First let's double check if out-of-order argument is nothing
461+
// more than a simple label mismatch, because in situation where
462+
// one argument requires label and another one doesn't, but caller
463+
// doesn't provide either, problem is going to be identified as
464+
// out-of-order argument instead of label mismatch.
465+
auto &parameter = params[prevArgIdx];
466+
if (parameter.hasLabel()) {
467+
auto expectedLabel = parameter.Label;
468+
auto argumentLabel = args[argIdx].Label;
469+
470+
// If there is a label but it's incorrect it can only mean
471+
// situation like this: expected (x, _ y) got (y, _ x).
472+
if (argumentLabel.empty() ||
473+
(expectedLabel.compare(argumentLabel) != 0 &&
474+
args[prevArgIdx].Label.empty())) {
475+
listener.missingLabel(prevArgIdx);
476+
return true;
477+
}
478+
}
479+
457480
listener.outOfOrderArgument(argIdx, prevArgIdx);
458481
return true;
459482
}

lib/Sema/ConstraintSystem.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2243,6 +2243,11 @@ class MatchCallArgumentListener {
22432243
/// \param paramIdx The index of the parameter that is missing an argument.
22442244
virtual void missingArgument(unsigned paramIdx);
22452245

2246+
/// Indicate that there was no label given when one was expected by parameter.
2247+
///
2248+
/// \param paramIndex The index of the parameter that is missing a label.
2249+
virtual void missingLabel(unsigned paramIndex);
2250+
22462251
/// Indicates that an argument is out-of-order with respect to a previously-
22472252
/// seen argument.
22482253
///

test/Constraints/diagnostics.swift

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -713,10 +713,9 @@ func nilComparison(i: Int, o: AnyObject) {
713713
_ = o !== nil // expected-warning {{comparing non-optional value of type 'AnyObject' to nil always returns true}}
714714
}
715715

716-
// FIXME: Bad diagnostic
717716
func secondArgumentNotLabeled(a:Int, _ b: Int) { }
718717
secondArgumentNotLabeled(10, 20)
719-
// expected-error@-1 {{unnamed argument #2 must precede unnamed argument #1}}
718+
// expected-error@-1 {{missing argument label 'a' in call}}
720719

721720
// <rdar://problem/23709100> QoI: incorrect ambiguity error due to implicit conversion
722721
func testImplConversion(a : Float?) -> Bool {}
@@ -795,3 +794,24 @@ func valueForKey<K>(_ key: K) -> CacheValue? {
795794
let cache = NSCache<K, CacheValue>()
796795
return cache.object(forKey: key)?.value // expected-error {{ambiguous reference to member 'value(x:)'}}
797796
}
797+
798+
// SR-2242: poor diagnostic when argument label is omitted
799+
800+
func r27212391(x: Int, _ y: Int) {
801+
let _: Int = x + y
802+
}
803+
804+
func r27212391(a: Int, x: Int, _ y: Int) {
805+
let _: Int = a + x + y
806+
}
807+
808+
r27212391(3, 5) // expected-error {{missing argument label 'x' in call}}
809+
r27212391(3, y: 5) // expected-error {{missing argument label 'x' in call}}
810+
r27212391(3, x: 5) // expected-error {{argument 'x' must precede unnamed argument #1}}
811+
r27212391(y: 3, x: 5) // expected-error {{argument 'x' must precede argument 'y'}}
812+
r27212391(y: 3, 5) // expected-error {{incorrect argument label in call (have 'y:_:', expected 'x:_:')}}
813+
r27212391(x: 3, x: 5) // expected-error {{extraneous argument label 'x:' in call}}
814+
r27212391(a: 1, 3, y: 5) // expected-error {{missing argument label 'x' in call}}
815+
r27212391(1, x: 3, y: 5) // expected-error {{missing argument label 'a' in call}}
816+
r27212391(a: 1, y: 3, x: 5) // expected-error {{argument 'x' must precede argument 'y'}}
817+
r27212391(a: 1, 3, x: 5) // expected-error {{argument 'x' must precede unnamed argument #2}}

0 commit comments

Comments
 (0)