mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[Type checker] Improve diagnostics for trailing closures.
The change to the forward-scanning rule regressed some diagnostics, because we no longer generated the special "trailing closure mismatch" diagnostic. Reinstate the special-case "trailing closure mismatch" diagnostic, but this time do so as part of the normal argument mismatch diagnostics so it is based on type information. While here, clean up the handling of missing-argument diagnostics to deal with (multiple) trailing closures properly, so that we can (e.g) suggest adding a new labeled trailing closure at the end, rather than producing nonsensical Fix-Its. And, note that SR-12291 is broken (again) by the forward-scan matching rules.
This commit is contained in:
@@ -3915,9 +3915,9 @@ bool MissingArgumentsFailure::diagnoseAsError() {
|
||||
Expr *fnExpr = nullptr;
|
||||
Expr *argExpr = nullptr;
|
||||
unsigned numArguments = 0;
|
||||
bool hasTrailingClosure = false;
|
||||
Optional<unsigned> firstTrailingClosure = None;
|
||||
|
||||
std::tie(fnExpr, argExpr, numArguments, hasTrailingClosure) =
|
||||
std::tie(fnExpr, argExpr, numArguments, firstTrailingClosure) =
|
||||
getCallInfo(getRawAnchor());
|
||||
|
||||
// TODO(diagnostics): We should be able to suggest this fix-it
|
||||
@@ -3980,46 +3980,66 @@ bool MissingArgumentsFailure::diagnoseSingleMissingArgument() const {
|
||||
auto position = argument.first;
|
||||
auto label = argument.second.getLabel();
|
||||
|
||||
Expr *fnExpr = nullptr;
|
||||
Expr *argExpr = nullptr;
|
||||
unsigned numArgs = 0;
|
||||
Optional<unsigned> firstTrailingClosure = None;
|
||||
|
||||
std::tie(fnExpr, argExpr, numArgs, firstTrailingClosure) =
|
||||
getCallInfo(anchor);
|
||||
|
||||
if (!argExpr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Will the parameter accept a trailing closure?
|
||||
Type paramType = resolveType(argument.second.getPlainType());
|
||||
bool paramAcceptsTrailingClosure = paramType
|
||||
->lookThroughAllOptionalTypes()->is<AnyFunctionType>();
|
||||
|
||||
// Determine whether we're inserting as a trailing closure.
|
||||
bool insertingTrailingClosure =
|
||||
firstTrailingClosure && position > *firstTrailingClosure;
|
||||
|
||||
SmallString<32> insertBuf;
|
||||
llvm::raw_svector_ostream insertText(insertBuf);
|
||||
|
||||
if (position != 0)
|
||||
if (insertingTrailingClosure)
|
||||
insertText << " ";
|
||||
else if (position != 0)
|
||||
insertText << ", ";
|
||||
|
||||
forFixIt(insertText, argument.second);
|
||||
|
||||
Expr *fnExpr = nullptr;
|
||||
Expr *argExpr = nullptr;
|
||||
unsigned insertableEndIdx = 0;
|
||||
bool hasTrailingClosure = false;
|
||||
|
||||
std::tie(fnExpr, argExpr, insertableEndIdx, hasTrailingClosure) =
|
||||
getCallInfo(anchor);
|
||||
|
||||
if (!argExpr)
|
||||
return false;
|
||||
|
||||
if (hasTrailingClosure)
|
||||
insertableEndIdx -= 1;
|
||||
|
||||
if (position == 0 && insertableEndIdx != 0)
|
||||
if (position == 0 && numArgs > 0 &&
|
||||
(!firstTrailingClosure || position < *firstTrailingClosure))
|
||||
insertText << ", ";
|
||||
|
||||
SourceLoc insertLoc;
|
||||
if (auto *TE = dyn_cast<TupleExpr>(argExpr)) {
|
||||
// fn():
|
||||
// fn([argMissing])
|
||||
|
||||
if (position >= numArgs && insertingTrailingClosure) {
|
||||
// Add a trailing closure to the end.
|
||||
|
||||
// fn { closure }:
|
||||
// fn {closure} label: [argMissing]
|
||||
// fn() { closure }:
|
||||
// fn() {closure} label: [argMissing]
|
||||
// fn(argX) { closure }:
|
||||
// fn(argX) { closure } label: [argMissing]
|
||||
insertLoc = Lexer::getLocForEndOfToken(
|
||||
ctx.SourceMgr, argExpr->getEndLoc());
|
||||
} else if (auto *TE = dyn_cast<TupleExpr>(argExpr)) {
|
||||
// fn(argX, argY):
|
||||
// fn([argMissing, ]argX, argY)
|
||||
// fn(argX[, argMissing], argY)
|
||||
// fn(argX, argY[, argMissing])
|
||||
// fn(argX) { closure }:
|
||||
// fn([argMissing, ]argX) { closure }
|
||||
// fn(argX[, argMissing]) { closure }
|
||||
// fn(argX[, closureLabel: ]{closure}[, argMissing)] // Not impl.
|
||||
if (insertableEndIdx == 0)
|
||||
// fn(argX, argY):
|
||||
// fn(argX, argY[, argMissing])
|
||||
if (numArgs == 0) {
|
||||
insertLoc = TE->getRParenLoc();
|
||||
else if (position != 0) {
|
||||
} else if (position != 0) {
|
||||
auto argPos = std::min(TE->getNumElements(), position) - 1;
|
||||
insertLoc = Lexer::getLocForEndOfToken(
|
||||
ctx.SourceMgr, TE->getElement(argPos)->getEndLoc());
|
||||
@@ -4031,25 +4051,25 @@ bool MissingArgumentsFailure::diagnoseSingleMissingArgument() const {
|
||||
} else {
|
||||
auto *PE = cast<ParenExpr>(argExpr);
|
||||
if (PE->getRParenLoc().isValid()) {
|
||||
// fn():
|
||||
// fn([argMissing])
|
||||
// fn(argX):
|
||||
// fn([argMissing, ]argX)
|
||||
// fn(argX[, argMissing])
|
||||
// fn([argMissing, ]argX)
|
||||
// fn() { closure }:
|
||||
// fn([argMissing]) {closure}
|
||||
// fn([closureLabel: ]{closure}[, argMissing]) // Not impl.
|
||||
if (insertableEndIdx == 0)
|
||||
insertLoc = PE->getRParenLoc();
|
||||
else if (position == 0)
|
||||
insertLoc = PE->getSubExpr()->getStartLoc();
|
||||
else
|
||||
if (position == 0) {
|
||||
insertLoc = Lexer::getLocForEndOfToken(ctx.SourceMgr,
|
||||
PE->getSubExpr()->getEndLoc());
|
||||
PE->getLParenLoc());
|
||||
} else {
|
||||
insertLoc = Lexer::getLocForEndOfToken(
|
||||
ctx.SourceMgr, PE->getSubExpr()->getEndLoc());
|
||||
}
|
||||
} else {
|
||||
// fn { closure }:
|
||||
// fn[(argMissing)] { closure }
|
||||
// fn[(closureLabel:] { closure }[, missingArg)] // Not impl.
|
||||
assert(!isExpr<SubscriptExpr>(anchor) && "bracket less subscript");
|
||||
assert(PE->hasTrailingClosure() &&
|
||||
assert(firstTrailingClosure &&
|
||||
"paren less ParenExpr without trailing closure");
|
||||
insertBuf.insert(insertBuf.begin(), '(');
|
||||
insertBuf.insert(insertBuf.end(), ')');
|
||||
@@ -4061,16 +4081,28 @@ bool MissingArgumentsFailure::diagnoseSingleMissingArgument() const {
|
||||
if (insertLoc.isInvalid())
|
||||
return false;
|
||||
|
||||
// If we are trying to insert a trailing closure but the parameter
|
||||
// corresponding to the missing argument doesn't support a trailing closure,
|
||||
// don't provide a Fix-It.
|
||||
// FIXME: It's possible to parenthesize and relabel the argument list to
|
||||
// accomodate this, but it's tricky.
|
||||
bool shouldEmitFixIt =
|
||||
!(insertingTrailingClosure && !paramAcceptsTrailingClosure);
|
||||
|
||||
if (label.empty()) {
|
||||
emitDiagnosticAt(insertLoc, diag::missing_argument_positional, position + 1)
|
||||
.fixItInsert(insertLoc, insertText.str());
|
||||
auto diag = emitDiagnosticAt(
|
||||
insertLoc, diag::missing_argument_positional, position + 1);
|
||||
if (shouldEmitFixIt)
|
||||
diag.fixItInsert(insertLoc, insertText.str());
|
||||
} else if (isPropertyWrapperInitialization()) {
|
||||
auto *TE = cast<TypeExpr>(fnExpr);
|
||||
emitDiagnosticAt(TE->getLoc(), diag::property_wrapper_missing_arg_init,
|
||||
label, resolveType(TE->getInstanceType())->getString());
|
||||
} else {
|
||||
emitDiagnosticAt(insertLoc, diag::missing_argument_named, label)
|
||||
.fixItInsert(insertLoc, insertText.str());
|
||||
auto diag = emitDiagnosticAt(
|
||||
insertLoc, diag::missing_argument_named, label);
|
||||
if (shouldEmitFixIt)
|
||||
diag.fixItInsert(insertLoc, insertText.str());
|
||||
}
|
||||
|
||||
if (auto selectedOverload =
|
||||
@@ -4298,23 +4330,24 @@ bool MissingArgumentsFailure::isMisplacedMissingArgument(
|
||||
return TypeChecker::isConvertibleTo(argType, paramType, solution.getDC());
|
||||
}
|
||||
|
||||
std::tuple<Expr *, Expr *, unsigned, bool>
|
||||
std::tuple<Expr *, Expr *, unsigned, Optional<unsigned>>
|
||||
MissingArgumentsFailure::getCallInfo(ASTNode anchor) const {
|
||||
if (auto *call = getAsExpr<CallExpr>(anchor)) {
|
||||
return std::make_tuple(call->getFn(), call->getArg(),
|
||||
call->getNumArguments(), call->hasTrailingClosure());
|
||||
call->getNumArguments(),
|
||||
call->getUnlabeledTrailingClosureIndex());
|
||||
} else if (auto *UME = getAsExpr<UnresolvedMemberExpr>(anchor)) {
|
||||
return std::make_tuple(UME, UME->getArgument(), UME->getNumArguments(),
|
||||
UME->hasTrailingClosure());
|
||||
UME->getUnlabeledTrailingClosureIndex());
|
||||
} else if (auto *SE = getAsExpr<SubscriptExpr>(anchor)) {
|
||||
return std::make_tuple(SE, SE->getIndex(), SE->getNumArguments(),
|
||||
SE->hasTrailingClosure());
|
||||
SE->getUnlabeledTrailingClosureIndex());
|
||||
} else if (auto *OLE = getAsExpr<ObjectLiteralExpr>(anchor)) {
|
||||
return std::make_tuple(OLE, OLE->getArg(), OLE->getNumArguments(),
|
||||
OLE->hasTrailingClosure());
|
||||
OLE->getUnlabeledTrailingClosureIndex());
|
||||
}
|
||||
|
||||
return std::make_tuple(nullptr, nullptr, 0, false);
|
||||
return std::make_tuple(nullptr, nullptr, 0, None);
|
||||
}
|
||||
|
||||
void MissingArgumentsFailure::forFixIt(
|
||||
@@ -5509,6 +5542,9 @@ bool ArgumentMismatchFailure::diagnoseAsError() {
|
||||
if (diagnosePropertyWrapperMismatch())
|
||||
return true;
|
||||
|
||||
if (diagnoseTrailingClosureMismatch())
|
||||
return true;
|
||||
|
||||
auto argType = getFromType();
|
||||
auto paramType = getToType();
|
||||
|
||||
@@ -5743,6 +5779,26 @@ bool ArgumentMismatchFailure::diagnosePropertyWrapperMismatch() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ArgumentMismatchFailure::diagnoseTrailingClosureMismatch() const {
|
||||
if (!Info.isTrailingClosure())
|
||||
return false;
|
||||
|
||||
auto paramType = getToType();
|
||||
if (paramType->lookThroughAllOptionalTypes()->is<AnyFunctionType>())
|
||||
return false;
|
||||
|
||||
emitDiagnostic(diag::trailing_closure_bad_param, paramType)
|
||||
.highlight(getSourceRange());
|
||||
|
||||
if (auto overload = getCalleeOverloadChoiceIfAvailable(getLocator())) {
|
||||
if (auto *decl = overload->choice.getDeclOrNull()) {
|
||||
emitDiagnosticAt(decl, diag::decl_declared_here, decl->getName());
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ExpandArrayIntoVarargsFailure::tryDropArrayBracketsFixIt(
|
||||
const Expr *anchor) const {
|
||||
// If this is an array literal, offer to remove the brackets and pass the
|
||||
|
||||
@@ -1293,9 +1293,10 @@ private:
|
||||
bool isPropertyWrapperInitialization() const;
|
||||
|
||||
/// Gather information associated with expression that represents
|
||||
/// a call - function, arguments, # of arguments and whether it has
|
||||
/// a trailing closure.
|
||||
std::tuple<Expr *, Expr *, unsigned, bool> getCallInfo(ASTNode anchor) const;
|
||||
/// a call - function, arguments, # of arguments and the position of
|
||||
/// the first trailing closure.
|
||||
std::tuple<Expr *, Expr *, unsigned, Optional<unsigned>>
|
||||
getCallInfo(ASTNode anchor) const;
|
||||
|
||||
/// Transform given argument into format suitable for a fix-it
|
||||
/// text e.g. `[<label>:]? <#<type#>`
|
||||
@@ -1815,6 +1816,10 @@ public:
|
||||
/// or now deprecated `init(initialValue:)`.
|
||||
bool diagnosePropertyWrapperMismatch() const;
|
||||
|
||||
/// Tailored diagnostics for argument mismatches associated with trailing
|
||||
/// closures being passed to non-closure parameters.
|
||||
bool diagnoseTrailingClosureMismatch() const;
|
||||
|
||||
protected:
|
||||
/// \returns The position of the argument being diagnosed, starting at 1.
|
||||
unsigned getArgPosition() const { return Info.getArgPosition(); }
|
||||
|
||||
@@ -421,7 +421,8 @@ matchCallArguments(SmallVectorImpl<AnyFunctionType::Param> &args,
|
||||
|
||||
// If the parameter we are looking at does not support the (unlabeled)
|
||||
// trailing closure argument, this parameter is unfulfilled.
|
||||
if (!paramInfo.acceptsUnlabeledTrailingClosureArgument(paramIdx)) {
|
||||
if (!paramInfo.acceptsUnlabeledTrailingClosureArgument(paramIdx) &&
|
||||
!ignoreNameMismatch) {
|
||||
haveUnfulfilledParams = true;
|
||||
return;
|
||||
}
|
||||
@@ -739,7 +740,10 @@ matchCallArguments(SmallVectorImpl<AnyFunctionType::Param> &args,
|
||||
// one argument requires label and another one doesn't, but caller
|
||||
// doesn't provide either, problem is going to be identified as
|
||||
// out-of-order argument instead of label mismatch.
|
||||
const auto expectedLabel = params[paramIdx].getLabel();
|
||||
const auto expectedLabel =
|
||||
fromArgIdx == unlabeledTrailingClosureArgIndex
|
||||
? Identifier()
|
||||
: params[paramIdx].getLabel();
|
||||
const auto argumentLabel = args[fromArgIdx].getLabel();
|
||||
|
||||
if (argumentLabel != expectedLabel) {
|
||||
|
||||
@@ -595,6 +595,15 @@ public:
|
||||
return StringRef(scratch.data(), scratch.size());
|
||||
}
|
||||
|
||||
/// Whether the argument is a trailing closure.
|
||||
bool isTrailingClosure() const {
|
||||
if (auto trailingClosureArg =
|
||||
ArgListExpr->getUnlabeledTrailingClosureIndexOfPackedArgument())
|
||||
return ArgIdx >= *trailingClosureArg;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// \returns The interface type for the function being applied. Note that this
|
||||
/// may not a function type, for example it could be a generic parameter.
|
||||
Type getFnInterfaceType() const { return FnInterfaceType; }
|
||||
|
||||
@@ -1418,7 +1418,7 @@ struct RelabelAndTrailingClosure {
|
||||
func f2(aa: Int, bb: Int, _ cc: () -> Void = {}) {}
|
||||
|
||||
func test() {
|
||||
f1(aax: 1, bbx: 2) {} // expected-error {{incorrect argument labels in call (have 'aax:bbx:_:', expected 'aa:bb:cc:')}} {{8-11=aa}} {{16-19=bb}} {{none}}
|
||||
f1(aax: 1, bbx: 2) {} // expected-error {{incorrect argument labels in call (have 'aax:bbx:_:', expected 'aa:bb:_:')}} {{8-11=aa}} {{16-19=bb}} {{none}}
|
||||
f2(aax: 1, bbx: 2) {} // expected-error {{incorrect argument labels in call (have 'aax:bbx:_:', expected 'aa:bb:_:')}} {{8-11=aa}} {{16-19=bb}} {{none}}
|
||||
|
||||
f1(aax: 1, bbx: 2) // expected-error {{incorrect argument labels in call (have 'aax:bbx:', expected 'aa:bb:')}} {{8-11=aa}} {{16-19=bb}} {{none}}
|
||||
|
||||
@@ -999,11 +999,13 @@ func rdar52204414() {
|
||||
// expected-error@-1 {{declared closure result 'Int' is incompatible with contextual type 'Void'}}
|
||||
}
|
||||
|
||||
// SR-12291 - trailing closure is used as an argument to the last (positionally) parameter
|
||||
func overloaded_with_default(a: () -> Int, b: Int = 0, c: Int = 0) {}
|
||||
func overloaded_with_default(b: Int = 0, c: Int = 0, a: () -> Int) {}
|
||||
// SR-12291 - trailing closure is used as an argument to the last (positionally) parameter.
|
||||
// Note that this was accepted prior to Swift 5.3. SE-0286 changed the
|
||||
// order of argument resolution and made it ambiguous.
|
||||
func overloaded_with_default(a: () -> Int, b: Int = 0, c: Int = 0) {} // expected-note{{found this candidate}}
|
||||
func overloaded_with_default(b: Int = 0, c: Int = 0, a: () -> Int) {} // expected-note{{found this candidate}}
|
||||
|
||||
overloaded_with_default { 0 } // Ok (could be ambiguous if trailing was allowed to match `a:` in first overload)
|
||||
overloaded_with_default { 0 } // expected-error{{ambiguous use of 'overloaded_with_default'}}
|
||||
|
||||
func overloaded_with_default_and_autoclosure<T>(_ a: @autoclosure () -> T, b: Int = 0) {}
|
||||
func overloaded_with_default_and_autoclosure<T>(b: Int = 0, c: @escaping () -> T?) {}
|
||||
|
||||
@@ -35,11 +35,9 @@ trailingClosureSingle1() { 1 } // expected-error {{missing argument for paramete
|
||||
|
||||
func trailingClosureSingle2(x: () -> Int, y: Int) {} // expected-note * {{here}}
|
||||
trailingClosureSingle2 { 1 }
|
||||
// expected-error@-1 {{missing argument for parameter 'x' in call}} {{23-23=(x: <#() -> Int#>)}}
|
||||
// expected-error@-2 {{trailing closure passed to parameter of type 'Int' that does not accept a closure}}
|
||||
// expected-error@-1 {{missing argument for parameter 'y' in call}} {{none}}
|
||||
trailingClosureSingle2() { 1 }
|
||||
// expected-error@-1 {{missing argument for parameter 'x' in call}} {{24-24=x: <#() -> Int#>}}
|
||||
// expected-error@-2 {{trailing closure passed to parameter of type 'Int' that does not accept a closure}}
|
||||
// expected-error@-1 {{missing argument for parameter 'y' in call}} {{none}}
|
||||
|
||||
func trailingClosureMulti1(x: Int, y: Int, z: () -> Int) {} // expected-note * {{here}}
|
||||
trailingClosureMulti1(y: 1) { 1 } // expected-error {{missing argument for parameter 'x' in call}} {{23-23=x: <#Int#>, }}
|
||||
@@ -48,14 +46,17 @@ trailingClosureMulti1(x: 1, y: 1) // expected-error {{missing argument for param
|
||||
|
||||
func trailingClosureMulti2(x: Int, y: () -> Int, z: Int) {} // expected-note * {{here}}
|
||||
trailingClosureMulti2 { 1 }
|
||||
// expected-error@-1 {{missing arguments for parameters 'x', 'y' in call}}
|
||||
// expected-error@-2 {{trailing closure passed to parameter of type 'Int' that does not accept a closure}}
|
||||
// expected-error@-1 {{missing arguments for parameters 'x', 'z' in call}}
|
||||
trailingClosureMulti2() { 1 }
|
||||
// expected-error@-1 {{missing arguments for parameters 'x', 'y' in call}}
|
||||
// expected-error@-2 {{trailing closure passed to parameter of type 'Int' that does not accept a closure}}
|
||||
// expected-error@-1 {{missing arguments for parameters 'x', 'z' in call}}
|
||||
trailingClosureMulti2(x: 1) { 1 }
|
||||
// expected-error@-1 {{missing argument for parameter 'y' in call}} {{27-27=, y: <#() -> Int#>}}
|
||||
// expected-error@-2 {{trailing closure passed to parameter of type 'Int' that does not accept a closure}}
|
||||
// expected-error@-1 {{missing argument for parameter 'z' in call}} {{none}}
|
||||
|
||||
func trailingClosureMulti3(x: (Int) -> Int, y: (Int) -> Int, z: (Int) -> Int) {} // expected-note 2 {{declared here}}
|
||||
trailingClosureMulti3 { $0 } y: { $0 } // expected-error{{missing argument for parameter 'z' in call}}{{39-39= z: <#(Int) -> Int#>}}
|
||||
|
||||
trailingClosureMulti3 { $0 } z: { $0 } // expected-error{{missing argument for parameter 'y' in call}}{{29-29= y: <#(Int) -> Int#>}}
|
||||
|
||||
|
||||
func param2Func(x: Int, y: Int) {} // expected-note * {{here}}
|
||||
param2Func(x: 1) // expected-error {{missing argument for parameter 'y' in call}} {{16-16=, y: <#Int#>}}
|
||||
|
||||
@@ -38,14 +38,3 @@ func testUnresolvedMember(i: Int) -> X {
|
||||
// CHECK-NEXT: introducing single enabled disjunction term {{.*}} bound to decl overload_filtering.(file).X.init(_:_:)
|
||||
return .init(i, i)
|
||||
}
|
||||
|
||||
func trailing(x: Int = 0, y: () -> Void) { }
|
||||
func trailing(x: Int = 0, z: Float) { }
|
||||
|
||||
func testTrailing() {
|
||||
// CHECK: disabled disjunction term {{.*}} bound to decl overload_filtering.(file).trailing(x:z:)
|
||||
trailing() { }
|
||||
|
||||
// CHECK: disabled disjunction term {{.*}} bound to decl overload_filtering.(file).trailing(x:z:)
|
||||
trailing(x: 5) { }
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ func test_multiple_trailing_syntax_without_labels() {
|
||||
|
||||
fn {} g: {} // Ok
|
||||
|
||||
fn {} _: {} // expected-error {{extra argument in call}}
|
||||
fn {} _: {} // expected-error {{missing argument labels 'f:g:' in call}}
|
||||
|
||||
fn {} g: <#T##() -> Void#> // expected-error {{editor placeholder in source file}}
|
||||
|
||||
@@ -90,16 +90,15 @@ func test_multiple_trailing_syntax_without_labels() {
|
||||
|
||||
multiple {} _: { }
|
||||
|
||||
func mixed_args_1(a: () -> Void, _: () -> Void) {} // expected-note {{'mixed_args_1(a:_:)' declared here}}
|
||||
func mixed_args_2(_: () -> Void, a: () -> Void, _: () -> Void) {} // expected-note 2 {{'mixed_args_2(_:a:_:)' declared here}}
|
||||
func mixed_args_1(a: () -> Void, _: () -> Void) {}
|
||||
func mixed_args_2(_: () -> Void, a: () -> Void, _: () -> Void) {} // expected-note {{'mixed_args_2(_:a:_:)' declared here}}
|
||||
|
||||
mixed_args_1
|
||||
{}
|
||||
_: {}
|
||||
|
||||
// FIXME: not a good diagnostic
|
||||
mixed_args_1
|
||||
{} // expected-error {{extra argument in call}} expected-error {{missing argument for parameter #2 in call}}
|
||||
{} // expected-error {{incorrect argument labels in call (have '_:a:', expected 'a:_:')}}
|
||||
a: {}
|
||||
|
||||
mixed_args_2
|
||||
@@ -107,14 +106,13 @@ func test_multiple_trailing_syntax_without_labels() {
|
||||
a: {}
|
||||
_: {}
|
||||
|
||||
// FIXME: not a good diagnostic
|
||||
mixed_args_2
|
||||
{} // expected-error {{missing argument for parameter #1 in call}}
|
||||
{} // expected-error {{missing argument for parameter 'a' in call}}
|
||||
_: {}
|
||||
|
||||
// FIXME: not a good diagnostic
|
||||
mixed_args_2
|
||||
{} // expected-error {{extra argument in call}} expected-error {{missing argument for parameter 'a' in call}}
|
||||
{} // expected-error {{missing argument label 'a:' in call}}
|
||||
_: {}
|
||||
_: {}
|
||||
}
|
||||
@@ -123,5 +121,5 @@ func produce(fn: () -> Int?, default d: () -> Int) -> Int { // expected-note {{d
|
||||
return fn() ?? d()
|
||||
}
|
||||
// TODO: The diagnostics here are perhaps a little overboard.
|
||||
_ = produce { 0 } default: { 1 } // expected-error {{missing argument for parameter 'fn' in call}} expected-error {{consecutive statements}} expected-error {{'default' label can only appear inside a 'switch' statement}} expected-error {{top-level statement cannot begin with a closure expression}} expected-error {{closure expression is unused}} expected-note {{did you mean to use a 'do' statement?}}
|
||||
_ = produce { 0 } default: { 1 } // expected-error {{missing argument for parameter 'default' in call}} expected-error {{consecutive statements}} expected-error {{'default' label can only appear inside a 'switch' statement}} expected-error {{top-level statement cannot begin with a closure expression}} expected-error {{closure expression is unused}} expected-note {{did you mean to use a 'do' statement?}}
|
||||
_ = produce { 2 } `default`: { 3 }
|
||||
|
||||
@@ -93,7 +93,7 @@ var c3 = C().map // expected-note{{callee is here}}
|
||||
// <rdar://problem/16835718> Ban multiple trailing closures
|
||||
func multiTrailingClosure(_ a : () -> (), b : () -> ()) { // expected-note {{'multiTrailingClosure(_:b:)' declared here}}
|
||||
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 {{closure expression is unused}} expected-note{{did you mean to use a 'do' statement?}} {{27-27=do }}
|
||||
multiTrailingClosure {} {} // expected-error {{missing argument for parameter 'b' in call}} expected-error {{consecutive statements on a line must be separated by ';'}} {{26-26=;}} expected-error {{closure expression is unused}} expected-note{{did you mean to use a 'do' statement?}} {{27-27=do }}
|
||||
|
||||
|
||||
}
|
||||
@@ -106,9 +106,9 @@ func labeledArgumentAndTrailingClosure() {
|
||||
takeFuncWithDefault({ $0 + 1 }) // expected-error {{missing argument label 'f:' in call}} {{23-23=f: }}
|
||||
takeFuncWithDefault(f: { $0 + 1 })
|
||||
|
||||
// Trailing closure binds to last parameter, always.
|
||||
takeTwoFuncsWithDefaults { "Hello, " + $0 }
|
||||
takeTwoFuncsWithDefaults { $0 + 1 } // expected-error {{cannot convert value of type 'Int' to expected argument type 'String'}}
|
||||
// Trailing closure binds to first parameter.
|
||||
takeTwoFuncsWithDefaults { "Hello, " + $0 } // expected-error{{cannot convert value of type 'String' to expected argument type 'Int'}}
|
||||
takeTwoFuncsWithDefaults { $0 + 1 }
|
||||
takeTwoFuncsWithDefaults(f1: {$0 + 1 })
|
||||
}
|
||||
|
||||
@@ -420,11 +420,11 @@ func variadicAndNonOverloadLabel(b: (() -> Void)...) -> Int { return 0 }
|
||||
func testVariadic() {
|
||||
variadic {}
|
||||
variadic() {}
|
||||
variadic({}) {} // expected-error {{extra argument in call}}
|
||||
variadic({}) {}
|
||||
|
||||
variadicLabel {}
|
||||
variadicLabel() {}
|
||||
variadicLabel(closures: {}) {} // expected-error {{extra argument 'closures' in call}}
|
||||
variadicLabel(closures: {}) {}
|
||||
|
||||
let a1 = variadicOverloadMismatch {}
|
||||
_ = a1 as String // expected-error {{cannot convert value of type 'Bool' to type 'String'}}
|
||||
|
||||
@@ -7,7 +7,7 @@ func forwardMatchWithGeneric<T>( // expected-note{{'forwardMatchWithGeneric(clos
|
||||
|
||||
func testKnownSourceBreaks(i: Int) {
|
||||
forwardMatchWithGeneric { i } // expected-error{{missing argument for parameter 'closure1' in call}}
|
||||
let _: (() -> ()).Type = type { } // expected-error{{missing argument label 'of:' in call}}
|
||||
let _: (() -> ()).Type = type { }
|
||||
}
|
||||
|
||||
func testUnlabeledParamMatching(i: Int, fn: ((Int) -> Int) -> Void) {
|
||||
@@ -24,7 +24,7 @@ func forwardMatchFailure( // expected-note{{declared here}}
|
||||
) { }
|
||||
|
||||
func testForwardMatchFailure() {
|
||||
forwardMatchFailure { x in // expected-error{{missing argument for parameter 'onCompletion' in call}}
|
||||
forwardMatchFailure { x in
|
||||
print(x)
|
||||
}
|
||||
} // expected-error{{missing argument for parameter 'onCompletion' in call}}{{4-4= onCompletion: <#(Int) -> Void#>}}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user