Skip to content

Commit ff8ea2d

Browse files
xedinrudkx
authored andcommitted
[Diagnostics] SR-2242: Fix diagnostic when argument label is omitted
(cherry picked from commit 054e3e4)
1 parent ca0cc2f commit ff8ea2d

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
}
@@ -4667,7 +4670,7 @@ static bool diagnoseSingleCandidateFailures(CalleeCandidateInfo &CCI,
46674670

46684671
CalleeCandidateInfo CandidateInfo;
46694672

4670-
// Indicates if problem was been found and diagnostic was emitted.
4673+
// Indicates if problem has been found and diagnostic was emitted.
46714674
bool Diagnosed = false;
46724675
// Indicates if functions we are trying to call is a subscript.
46734676
bool IsSubscript;
@@ -4726,6 +4729,15 @@ static bool diagnoseSingleCandidateFailures(CalleeCandidateInfo &CCI,
47264729
Diagnosed = true;
47274730
}
47284731

4732+
void missingLabel(unsigned paramIdx) override {
4733+
auto tuple = cast<TupleExpr>(ArgExpr);
4734+
TC.diagnose(tuple->getElement(paramIdx)->getStartLoc(),
4735+
diag::missing_argument_labels, false,
4736+
Parameters[paramIdx].Label.str(), IsSubscript);
4737+
4738+
Diagnosed = true;
4739+
}
4740+
47294741
void outOfOrderArgument(unsigned argIdx, unsigned prevArgIdx) override {
47304742
auto tuple = cast<TupleExpr>(ArgExpr);
47314743
Identifier first = tuple->getElementName(argIdx);
@@ -4754,6 +4766,7 @@ static bool diagnoseSingleCandidateFailures(CalleeCandidateInfo &CCI,
47544766
auto secondRange = argRange(prevArgIdx, second);
47554767

47564768
SourceLoc diagLoc = firstRange.Start;
4769+
47574770
if (first.empty() && second.empty()) {
47584771
TC.diagnose(diagLoc, diag::argument_out_of_order_unnamed_unnamed,
47594772
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
@@ -2249,6 +2249,11 @@ class MatchCallArgumentListener {
22492249
/// \param paramIdx The index of the parameter that is missing an argument.
22502250
virtual void missingArgument(unsigned paramIdx);
22512251

2252+
/// Indicate that there was no label given when one was expected by parameter.
2253+
///
2254+
/// \param paramIndex The index of the parameter that is missing a label.
2255+
virtual void missingLabel(unsigned paramIndex);
2256+
22522257
/// Indicates that an argument is out-of-order with respect to a previously-
22532258
/// seen argument.
22542259
///

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)