Improve printing of "too few" or "too many" arguments in generic or

overloaded argument list mismatches.  We printed them in simple cases
due to "Failure" detecting them in trivial situations.  Instead of
doing that, let CSDiags do it, which allows us to pick things out of
overload sets and handle the more complex cases well.

This is a progression across the board except for a couple of cases
where we now produce "cannot convert value of type 'whatever' to
expected argument type '(arglist)'", this is a known issue that I'll
fix in a subsequent commit.
This commit is contained in:
Chris Lattner
2015-12-07 23:06:55 -08:00
parent b53ff3b580
commit 96a1e96dea
9 changed files with 69 additions and 62 deletions

View File

@@ -643,45 +643,12 @@ static bool diagnoseFailure(ConstraintSystem &cs, Failure &failure,
// FIXME: diagnose other cases // FIXME: diagnose other cases
return false; return false;
case Failure::MissingArgument: { case Failure::MissingArgument:
Identifier name;
unsigned idx = failure.getValue();
if (auto tupleTy = failure.getFirstType()->getAs<TupleType>()) {
name = tupleTy->getElement(idx).getName();
} else {
// Scalar.
assert(idx == 0);
}
if (name.empty())
tc.diagnose(loc, diag::missing_argument_positional, idx+1);
else
tc.diagnose(loc, diag::missing_argument_named, name);
return true;
}
case Failure::ExtraArgument: {
if (auto tuple = dyn_cast_or_null<TupleExpr>(anchor)) {
unsigned firstIdx = failure.getValue();
auto name = tuple->getElementName(firstIdx);
Expr *arg = tuple->getElement(firstIdx);
if (firstIdx == tuple->getNumElements()-1 &&
tuple->hasTrailingClosure())
tc.diagnose(arg->getLoc(), diag::extra_trailing_closure_in_call)
.highlight(arg->getSourceRange());
else if (name.empty())
tc.diagnose(loc, diag::extra_argument_positional)
.highlight(arg->getSourceRange());
else
tc.diagnose(loc, diag::extra_argument_named, name)
.highlight(arg->getSourceRange());
return true;
}
return false; return false;
}
case Failure::ExtraArgument:
return false;
case Failure::NoPublicInitializers: { case Failure::NoPublicInitializers: {
tc.diagnose(loc, diag::no_accessible_initializers, failure.getFirstType()) tc.diagnose(loc, diag::no_accessible_initializers, failure.getFirstType())
.highlight(range); .highlight(range);
@@ -3580,24 +3547,33 @@ bool FailureDiagnosis::visitApplyExpr(ApplyExpr *callExpr) {
// If we filtered this down to exactly one candidate, see if we can produce // If we filtered this down to exactly one candidate, see if we can produce
// an extremely specific error about it. // an extremely specific error about it.
if (calleeInfo.size() == 1) { if (calleeInfo.size() == 1) {
if (calleeInfo.closeness == CC_ArgumentLabelMismatch) { if (calleeInfo.closeness == CC_ArgumentLabelMismatch ||
calleeInfo.closeness == CC_ArgumentCountMismatch) {
auto args = decomposeArgParamType(argExpr->getType()); auto args = decomposeArgParamType(argExpr->getType());
SmallVector<Identifier, 4> correctNames; SmallVector<Identifier, 4> correctNames;
unsigned OOOArgIdx = ~0U, OOOPrevArgIdx = ~0U; unsigned OOOArgIdx = ~0U, OOOPrevArgIdx = ~0U;
unsigned extraArgIdx = ~0U, missingParamIdx = ~0U;
// If we have a single candidate that failed to match the argument list, // If we have a single candidate that failed to match the argument list,
// attempt to use matchCallArguments to diagnose the problem. // attempt to use matchCallArguments to diagnose the problem.
struct OurListener : public MatchCallArgumentListener { struct OurListener : public MatchCallArgumentListener {
SmallVectorImpl<Identifier> &correctNames; SmallVectorImpl<Identifier> &correctNames;
unsigned &OOOArgIdx, &OOOPrevArgIdx; unsigned &OOOArgIdx, &OOOPrevArgIdx;
unsigned &extraArgIdx, &missingParamIdx;
public: public:
OurListener(SmallVectorImpl<Identifier> &correctNames, OurListener(SmallVectorImpl<Identifier> &correctNames,
unsigned &OOOArgIdx, unsigned &OOOPrevArgIdx) unsigned &OOOArgIdx, unsigned &OOOPrevArgIdx,
unsigned &extraArgIdx, unsigned &missingParamIdx)
: correctNames(correctNames), : correctNames(correctNames),
OOOArgIdx(OOOArgIdx), OOOPrevArgIdx(OOOPrevArgIdx) {} OOOArgIdx(OOOArgIdx), OOOPrevArgIdx(OOOPrevArgIdx),
void extraArgument(unsigned argIdx) override {} extraArgIdx(extraArgIdx), missingParamIdx(missingParamIdx) {}
void missingArgument(unsigned paramIdx) override {} void extraArgument(unsigned argIdx) override {
extraArgIdx = argIdx;
}
void missingArgument(unsigned paramIdx) override {
missingParamIdx = paramIdx;
}
void outOfOrderArgument(unsigned argIdx, unsigned prevArgIdx) override{ void outOfOrderArgument(unsigned argIdx, unsigned prevArgIdx) override{
OOOArgIdx = argIdx; OOOArgIdx = argIdx;
OOOPrevArgIdx = prevArgIdx; OOOPrevArgIdx = prevArgIdx;
@@ -3606,7 +3582,8 @@ bool FailureDiagnosis::visitApplyExpr(ApplyExpr *callExpr) {
correctNames.append(newNames.begin(), newNames.end()); correctNames.append(newNames.begin(), newNames.end());
return true; return true;
} }
} listener(correctNames, OOOArgIdx, OOOPrevArgIdx); } listener(correctNames, OOOArgIdx, OOOPrevArgIdx,
extraArgIdx, missingParamIdx);
// Use matchCallArguments to determine how close the argument list is (in // Use matchCallArguments to determine how close the argument list is (in
// shape) to the specified candidates parameters. This ignores the // shape) to the specified candidates parameters. This ignores the
@@ -3616,6 +3593,38 @@ bool FailureDiagnosis::visitApplyExpr(ApplyExpr *callExpr) {
if (matchCallArguments(args, params, hasTrailingClosure, if (matchCallArguments(args, params, hasTrailingClosure,
/*allowFixes:*/true, listener, paramBindings)) { /*allowFixes:*/true, listener, paramBindings)) {
// If we are missing an parameter, diagnose that.
if (missingParamIdx != ~0U) {
Identifier name = params[missingParamIdx].Label;
auto loc = callExpr->getArg()->getStartLoc();
if (name.empty())
diagnose(loc, diag::missing_argument_positional,
missingParamIdx+1);
else
diagnose(loc, diag::missing_argument_named, name);
return true;
}
if (extraArgIdx != ~0U) {
auto name = args[extraArgIdx].Label;
Expr *arg = argExpr;
auto tuple = dyn_cast<TupleExpr>(argExpr);
if (tuple)
arg = tuple->getElement(extraArgIdx);
auto loc = arg->getLoc();
if (tuple && extraArgIdx == tuple->getNumElements()-1 &&
tuple->hasTrailingClosure())
diagnose(loc, diag::extra_trailing_closure_in_call)
.highlight(arg->getSourceRange());
else if (name.empty())
diagnose(loc, diag::extra_argument_positional)
.highlight(arg->getSourceRange());
else
diagnose(loc, diag::extra_argument_named, name)
.highlight(arg->getSourceRange());
return true;
}
// If this is a argument label mismatch, then diagnose that error now. // If this is a argument label mismatch, then diagnose that error now.
if (!correctNames.empty() && if (!correctNames.empty() &&
CS->diagnoseArgumentLabelError(argExpr, correctNames, CS->diagnoseArgumentLabelError(argExpr, correctNames,

View File

@@ -42,8 +42,8 @@ f1(
) )
// Tuple element unused. // Tuple element unused.
f0(i, i, // expected-error{{extra argument in call}} f0(i, i,
i) i) // expected-error{{extra argument in call}}
// Position mismatch // Position mismatch
@@ -362,7 +362,7 @@ extension CurriedClass {
method3(1, b: 2) method3(1, b: 2)
method3() // expected-error {{missing argument for parameter #1 in call}} method3() // expected-error {{missing argument for parameter #1 in call}}
method3(42) // expected-error {{cannot convert value of type 'Int' to expected argument type '(Int, b: Int)'}} method3(42) // expected-error {{cannot convert value of type 'Int' to expected argument type '(Int, b: Int)'}}
method3(self) // expected-error {{missing argument for parameter 'b' in call}} method3(self) // expected-error {{cannot convert value of type 'CurriedClass' to expected argument type '(Int, b: Int)'}}
} }
} }

View File

@@ -15,8 +15,9 @@ unconstrained(x)
// FIXME: There's an inconsistency here in call argument matching between // FIXME: There's an inconsistency here in call argument matching between
// rvalues and lvalues. <rdar://problem/17786730> // rvalues and lvalues. <rdar://problem/17786730>
unconstrained((x, y)) unconstrained((x, y))
unconstrained(x, y) // expected-error{{cannot invoke 'unconstrained' with an argument list of type '(Int, String)'}}
// expected-note @-1 {{expected an argument list of type '(T)'}} unconstrained(x,
y) // expected-error{{extra argument in call}}
let a = 0 let a = 0

View File

@@ -9,8 +9,7 @@ func test15921520() {
func test20807269() { func test20807269() {
var x: Int = 0 var x: Int = 0
func f<T>(x: T) {} func f<T>(x: T) {}
// expected-note @+1 {{expected an argument list of type '(T)'}} f(1, &x) // expected-error{{extra argument in call}}
f(1, &x) // expected-error{{cannot invoke 'f' with an argument list of type '(Int, inout Int)'}}
} }
func test15921530() { func test15921530() {

View File

@@ -111,11 +111,9 @@ func test17875634() {
match += coord // expected-error{{binary operator '+=' cannot be applied to operands of type '[(Int, Int)]' and '(Int, Int)'}} match += coord // expected-error{{binary operator '+=' cannot be applied to operands of type '[(Int, Int)]' and '(Int, Int)'}}
// expected-note @-1 {{overloads for '+=' exist with these partially matching parameter lists:}} // expected-note @-1 {{overloads for '+=' exist with these partially matching parameter lists:}}
match.append(row, col) // expected-error{{cannot invoke 'append' with an argument list of type '(Int, Int)'}} match.append(row, col) // expected-error{{extra argument in call}}
// expected-note @-1 {{expected an argument list of type '(Int, Int)'}}
match.append(1, 2) // expected-error{{cannot invoke 'append' with an argument list of type '(Int, Int)'}} match.append(1, 2) // expected-error{{extra argument in call}}
// expected-note @-1 {{expected an argument list of type '(Int, Int)'}}
match.append(coord) match.append(coord)
match.append((1, 2)) match.append((1, 2))

View File

@@ -38,7 +38,7 @@ func funcdecl5(a: Int, _ y: Int) {
var testfunc : ((), Int) -> Int var testfunc : ((), Int) -> Int
testfunc( testfunc(
{$0+1}) // expected-error {{missing argument for parameter #2 in call}} {$0+1}) // expected-error {{cannot convert value of type '(Int) -> Int' to expected argument type '((), Int)'}}
funcdecl5(1, 2) // recursion. funcdecl5(1, 2) // recursion.

View File

@@ -68,7 +68,7 @@ var c3 = C().map // expected-note{{parsing trailing closure for this call}}
// <rdar://problem/16835718> Ban multiple trailing closures // <rdar://problem/16835718> Ban multiple trailing closures
func multiTrailingClosure(a : () -> (), b : () -> ()) { func multiTrailingClosure(a : () -> (), b : () -> ()) {
multiTrailingClosure({}) {} // ok multiTrailingClosure({}) {} // ok
multiTrailingClosure {} {} // expected-error {{missing argument for parameter #1 in call}} expected-error {{consecutive statements on a line must be separated by ';'}} {{26-26=;}} expected-error {{braced block of statements is an unused closure}} expected-error{{expression resolves to an unused function}} multiTrailingClosure {} {} // expected-error {{cannot convert value of type '() -> ()' to expected argument type '(() -> (), b: () -> ())'}} expected-error {{consecutive statements on a line must be separated by ';'}} {{26-26=;}} expected-error {{braced block of statements is an unused closure}} expected-error{{expression resolves to an unused function}}
} }

View File

@@ -779,11 +779,11 @@ func r22211854() {
func f(x: Int, _ y: Int, _ z: String = "") {} func f(x: Int, _ y: Int, _ z: String = "") {}
func g<T>(x: T, _ y: T, _ z: String = "") {} func g<T>(x: T, _ y: T, _ z: String = "") {}
f(1) // expected-error{{cannot invoke 'f' with an argument list of type '(Int)'}} expected-note{{expected an argument list of type '(Int, Int, String)'}} f(1) // expected-error{{missing argument for parameter #2 in call}}
g(1) // expected-error{{cannot invoke 'g' with an argument list of type '(Int)'}} expected-note{{expected an argument list of type '(T, T, String)'}} g(1) // expected-error{{missing argument for parameter #2 in call}}
func h() -> Int { return 1 } func h() -> Int { return 1 }
f(h() == 1) // expected-error{{cannot invoke 'f' with an argument list of type '(Bool)'}} expected-note{{expected an argument list of type '(Int, Int, String)'}} f(h() == 1) // expected-error{{missing argument for parameter #2 in call}}
g(h() == 1) // expected-error{{cannot invoke 'g' with an argument list of type '(Bool)'}} expected-note{{expected an argument list of type '(T, T, String)'}} g(h() == 1) // expected-error{{missing argument for parameter #2 in call}}
} }
// <rdar://problem/22348394> Compiler crash on invoking function with labeled defaulted param with non-labeled argument // <rdar://problem/22348394> Compiler crash on invoking function with labeled defaulted param with non-labeled argument

View File

@@ -168,7 +168,7 @@ class RDar16666631 {
self.init(i: i, d: 0.1, s: s) self.init(i: i, d: 0.1, s: s)
} }
} }
let rdar16666631 = RDar16666631(i: 5, d: 6) // expected-error {{missing argument for parameter 's' in call}} let rdar16666631 = RDar16666631(i: 5, d: 6) // expected-error {{incorrect argument label in call (have 'i:d:', expected 'i:s:')}}
struct S { struct S {