mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
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:
@@ -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,
|
||||||
|
|||||||
@@ -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)'}}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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() {
|
||||||
|
|||||||
@@ -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))
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|
||||||
|
|||||||
@@ -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}}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
Reference in New Issue
Block a user