[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:
Doug Gregor
2020-07-17 15:46:03 -07:00
parent 6c359cc6c0
commit 2395225df7
11 changed files with 158 additions and 94 deletions

View File

@@ -3915,9 +3915,9 @@ bool MissingArgumentsFailure::diagnoseAsError() {
Expr *fnExpr = nullptr; Expr *fnExpr = nullptr;
Expr *argExpr = nullptr; Expr *argExpr = nullptr;
unsigned numArguments = 0; unsigned numArguments = 0;
bool hasTrailingClosure = false; Optional<unsigned> firstTrailingClosure = None;
std::tie(fnExpr, argExpr, numArguments, hasTrailingClosure) = std::tie(fnExpr, argExpr, numArguments, firstTrailingClosure) =
getCallInfo(getRawAnchor()); getCallInfo(getRawAnchor());
// TODO(diagnostics): We should be able to suggest this fix-it // TODO(diagnostics): We should be able to suggest this fix-it
@@ -3980,46 +3980,66 @@ bool MissingArgumentsFailure::diagnoseSingleMissingArgument() const {
auto position = argument.first; auto position = argument.first;
auto label = argument.second.getLabel(); 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; SmallString<32> insertBuf;
llvm::raw_svector_ostream insertText(insertBuf); llvm::raw_svector_ostream insertText(insertBuf);
if (position != 0) if (insertingTrailingClosure)
insertText << " ";
else if (position != 0)
insertText << ", "; insertText << ", ";
forFixIt(insertText, argument.second); forFixIt(insertText, argument.second);
Expr *fnExpr = nullptr; if (position == 0 && numArgs > 0 &&
Expr *argExpr = nullptr; (!firstTrailingClosure || position < *firstTrailingClosure))
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)
insertText << ", "; insertText << ", ";
SourceLoc insertLoc; SourceLoc insertLoc;
if (auto *TE = dyn_cast<TupleExpr>(argExpr)) {
// fn(): if (position >= numArgs && insertingTrailingClosure) {
// fn([argMissing]) // 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(argX, argY):
// fn([argMissing, ]argX, argY) // fn([argMissing, ]argX, argY)
// fn(argX[, argMissing], argY) // fn(argX[, argMissing], argY)
// fn(argX, argY[, argMissing])
// fn(argX) { closure }: // fn(argX) { closure }:
// fn([argMissing, ]argX) { closure } // fn([argMissing, ]argX) { closure }
// fn(argX[, argMissing]) { closure } // fn(argX[, argMissing]) { closure }
// fn(argX[, closureLabel: ]{closure}[, argMissing)] // Not impl. // fn(argX, argY):
if (insertableEndIdx == 0) // fn(argX, argY[, argMissing])
if (numArgs == 0) {
insertLoc = TE->getRParenLoc(); insertLoc = TE->getRParenLoc();
else if (position != 0) { } else if (position != 0) {
auto argPos = std::min(TE->getNumElements(), position) - 1; auto argPos = std::min(TE->getNumElements(), position) - 1;
insertLoc = Lexer::getLocForEndOfToken( insertLoc = Lexer::getLocForEndOfToken(
ctx.SourceMgr, TE->getElement(argPos)->getEndLoc()); ctx.SourceMgr, TE->getElement(argPos)->getEndLoc());
@@ -4031,25 +4051,25 @@ bool MissingArgumentsFailure::diagnoseSingleMissingArgument() const {
} else { } else {
auto *PE = cast<ParenExpr>(argExpr); auto *PE = cast<ParenExpr>(argExpr);
if (PE->getRParenLoc().isValid()) { if (PE->getRParenLoc().isValid()) {
// fn():
// fn([argMissing])
// fn(argX): // fn(argX):
// fn([argMissing, ]argX)
// fn(argX[, argMissing]) // fn(argX[, argMissing])
// fn([argMissing, ]argX)
// fn() { closure }: // fn() { closure }:
// fn([argMissing]) {closure} // fn([argMissing]) {closure}
// fn([closureLabel: ]{closure}[, argMissing]) // Not impl. if (position == 0) {
if (insertableEndIdx == 0)
insertLoc = PE->getRParenLoc();
else if (position == 0)
insertLoc = PE->getSubExpr()->getStartLoc();
else
insertLoc = Lexer::getLocForEndOfToken(ctx.SourceMgr, insertLoc = Lexer::getLocForEndOfToken(ctx.SourceMgr,
PE->getSubExpr()->getEndLoc()); PE->getLParenLoc());
} else {
insertLoc = Lexer::getLocForEndOfToken(
ctx.SourceMgr, PE->getSubExpr()->getEndLoc());
}
} else { } else {
// fn { closure }: // fn { closure }:
// fn[(argMissing)] { closure } // fn[(argMissing)] { closure }
// fn[(closureLabel:] { closure }[, missingArg)] // Not impl.
assert(!isExpr<SubscriptExpr>(anchor) && "bracket less subscript"); assert(!isExpr<SubscriptExpr>(anchor) && "bracket less subscript");
assert(PE->hasTrailingClosure() && assert(firstTrailingClosure &&
"paren less ParenExpr without trailing closure"); "paren less ParenExpr without trailing closure");
insertBuf.insert(insertBuf.begin(), '('); insertBuf.insert(insertBuf.begin(), '(');
insertBuf.insert(insertBuf.end(), ')'); insertBuf.insert(insertBuf.end(), ')');
@@ -4061,16 +4081,28 @@ bool MissingArgumentsFailure::diagnoseSingleMissingArgument() const {
if (insertLoc.isInvalid()) if (insertLoc.isInvalid())
return false; 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()) { if (label.empty()) {
emitDiagnosticAt(insertLoc, diag::missing_argument_positional, position + 1) auto diag = emitDiagnosticAt(
.fixItInsert(insertLoc, insertText.str()); insertLoc, diag::missing_argument_positional, position + 1);
if (shouldEmitFixIt)
diag.fixItInsert(insertLoc, insertText.str());
} else if (isPropertyWrapperInitialization()) { } else if (isPropertyWrapperInitialization()) {
auto *TE = cast<TypeExpr>(fnExpr); auto *TE = cast<TypeExpr>(fnExpr);
emitDiagnosticAt(TE->getLoc(), diag::property_wrapper_missing_arg_init, emitDiagnosticAt(TE->getLoc(), diag::property_wrapper_missing_arg_init,
label, resolveType(TE->getInstanceType())->getString()); label, resolveType(TE->getInstanceType())->getString());
} else { } else {
emitDiagnosticAt(insertLoc, diag::missing_argument_named, label) auto diag = emitDiagnosticAt(
.fixItInsert(insertLoc, insertText.str()); insertLoc, diag::missing_argument_named, label);
if (shouldEmitFixIt)
diag.fixItInsert(insertLoc, insertText.str());
} }
if (auto selectedOverload = if (auto selectedOverload =
@@ -4298,23 +4330,24 @@ bool MissingArgumentsFailure::isMisplacedMissingArgument(
return TypeChecker::isConvertibleTo(argType, paramType, solution.getDC()); 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 { MissingArgumentsFailure::getCallInfo(ASTNode anchor) const {
if (auto *call = getAsExpr<CallExpr>(anchor)) { if (auto *call = getAsExpr<CallExpr>(anchor)) {
return std::make_tuple(call->getFn(), call->getArg(), return std::make_tuple(call->getFn(), call->getArg(),
call->getNumArguments(), call->hasTrailingClosure()); call->getNumArguments(),
call->getUnlabeledTrailingClosureIndex());
} else if (auto *UME = getAsExpr<UnresolvedMemberExpr>(anchor)) { } else if (auto *UME = getAsExpr<UnresolvedMemberExpr>(anchor)) {
return std::make_tuple(UME, UME->getArgument(), UME->getNumArguments(), return std::make_tuple(UME, UME->getArgument(), UME->getNumArguments(),
UME->hasTrailingClosure()); UME->getUnlabeledTrailingClosureIndex());
} else if (auto *SE = getAsExpr<SubscriptExpr>(anchor)) { } else if (auto *SE = getAsExpr<SubscriptExpr>(anchor)) {
return std::make_tuple(SE, SE->getIndex(), SE->getNumArguments(), return std::make_tuple(SE, SE->getIndex(), SE->getNumArguments(),
SE->hasTrailingClosure()); SE->getUnlabeledTrailingClosureIndex());
} else if (auto *OLE = getAsExpr<ObjectLiteralExpr>(anchor)) { } else if (auto *OLE = getAsExpr<ObjectLiteralExpr>(anchor)) {
return std::make_tuple(OLE, OLE->getArg(), OLE->getNumArguments(), 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( void MissingArgumentsFailure::forFixIt(
@@ -5509,6 +5542,9 @@ bool ArgumentMismatchFailure::diagnoseAsError() {
if (diagnosePropertyWrapperMismatch()) if (diagnosePropertyWrapperMismatch())
return true; return true;
if (diagnoseTrailingClosureMismatch())
return true;
auto argType = getFromType(); auto argType = getFromType();
auto paramType = getToType(); auto paramType = getToType();
@@ -5743,6 +5779,26 @@ bool ArgumentMismatchFailure::diagnosePropertyWrapperMismatch() const {
return true; 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( void ExpandArrayIntoVarargsFailure::tryDropArrayBracketsFixIt(
const Expr *anchor) const { const Expr *anchor) const {
// If this is an array literal, offer to remove the brackets and pass the // If this is an array literal, offer to remove the brackets and pass the

View File

@@ -1293,9 +1293,10 @@ private:
bool isPropertyWrapperInitialization() const; bool isPropertyWrapperInitialization() const;
/// Gather information associated with expression that represents /// Gather information associated with expression that represents
/// a call - function, arguments, # of arguments and whether it has /// a call - function, arguments, # of arguments and the position of
/// a trailing closure. /// the first trailing closure.
std::tuple<Expr *, Expr *, unsigned, bool> getCallInfo(ASTNode anchor) const; std::tuple<Expr *, Expr *, unsigned, Optional<unsigned>>
getCallInfo(ASTNode anchor) const;
/// Transform given argument into format suitable for a fix-it /// Transform given argument into format suitable for a fix-it
/// text e.g. `[<label>:]? <#<type#>` /// text e.g. `[<label>:]? <#<type#>`
@@ -1815,6 +1816,10 @@ public:
/// or now deprecated `init(initialValue:)`. /// or now deprecated `init(initialValue:)`.
bool diagnosePropertyWrapperMismatch() const; bool diagnosePropertyWrapperMismatch() const;
/// Tailored diagnostics for argument mismatches associated with trailing
/// closures being passed to non-closure parameters.
bool diagnoseTrailingClosureMismatch() const;
protected: protected:
/// \returns The position of the argument being diagnosed, starting at 1. /// \returns The position of the argument being diagnosed, starting at 1.
unsigned getArgPosition() const { return Info.getArgPosition(); } unsigned getArgPosition() const { return Info.getArgPosition(); }

View File

@@ -421,7 +421,8 @@ matchCallArguments(SmallVectorImpl<AnyFunctionType::Param> &args,
// If the parameter we are looking at does not support the (unlabeled) // If the parameter we are looking at does not support the (unlabeled)
// trailing closure argument, this parameter is unfulfilled. // trailing closure argument, this parameter is unfulfilled.
if (!paramInfo.acceptsUnlabeledTrailingClosureArgument(paramIdx)) { if (!paramInfo.acceptsUnlabeledTrailingClosureArgument(paramIdx) &&
!ignoreNameMismatch) {
haveUnfulfilledParams = true; haveUnfulfilledParams = true;
return; return;
} }
@@ -739,7 +740,10 @@ matchCallArguments(SmallVectorImpl<AnyFunctionType::Param> &args,
// one argument requires label and another one doesn't, but caller // one argument requires label and another one doesn't, but caller
// doesn't provide either, problem is going to be identified as // doesn't provide either, problem is going to be identified as
// out-of-order argument instead of label mismatch. // 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(); const auto argumentLabel = args[fromArgIdx].getLabel();
if (argumentLabel != expectedLabel) { if (argumentLabel != expectedLabel) {

View File

@@ -595,6 +595,15 @@ public:
return StringRef(scratch.data(), scratch.size()); 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 /// \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. /// may not a function type, for example it could be a generic parameter.
Type getFnInterfaceType() const { return FnInterfaceType; } Type getFnInterfaceType() const { return FnInterfaceType; }

View File

@@ -1418,7 +1418,7 @@ struct RelabelAndTrailingClosure {
func f2(aa: Int, bb: Int, _ cc: () -> Void = {}) {} func f2(aa: Int, bb: Int, _ cc: () -> Void = {}) {}
func test() { 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}} 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}} 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}}

View File

@@ -999,11 +999,13 @@ func rdar52204414() {
// expected-error@-1 {{declared closure result 'Int' is incompatible with contextual type 'Void'}} // 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 // 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) {} // Note that this was accepted prior to Swift 5.3. SE-0286 changed the
func overloaded_with_default(b: Int = 0, c: Int = 0, a: () -> Int) {} // 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>(_ a: @autoclosure () -> T, b: Int = 0) {}
func overloaded_with_default_and_autoclosure<T>(b: Int = 0, c: @escaping () -> T?) {} func overloaded_with_default_and_autoclosure<T>(b: Int = 0, c: @escaping () -> T?) {}

View File

@@ -35,11 +35,9 @@ trailingClosureSingle1() { 1 } // expected-error {{missing argument for paramete
func trailingClosureSingle2(x: () -> Int, y: Int) {} // expected-note * {{here}} func trailingClosureSingle2(x: () -> Int, y: Int) {} // expected-note * {{here}}
trailingClosureSingle2 { 1 } trailingClosureSingle2 { 1 }
// expected-error@-1 {{missing argument for parameter 'x' in call}} {{23-23=(x: <#() -> Int#>)}} // expected-error@-1 {{missing argument for parameter 'y' in call}} {{none}}
// expected-error@-2 {{trailing closure passed to parameter of type 'Int' that does not accept a closure}}
trailingClosureSingle2() { 1 } trailingClosureSingle2() { 1 }
// expected-error@-1 {{missing argument for parameter 'x' in call}} {{24-24=x: <#() -> Int#>}} // expected-error@-1 {{missing argument for parameter 'y' in call}} {{none}}
// expected-error@-2 {{trailing closure passed to parameter of type 'Int' that does not accept a closure}}
func trailingClosureMulti1(x: Int, y: Int, z: () -> Int) {} // expected-note * {{here}} 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#>, }} 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}} func trailingClosureMulti2(x: Int, y: () -> Int, z: Int) {} // expected-note * {{here}}
trailingClosureMulti2 { 1 } trailingClosureMulti2 { 1 }
// expected-error@-1 {{missing arguments for parameters 'x', 'y' in call}} // expected-error@-1 {{missing arguments for parameters 'x', 'z' in call}}
// expected-error@-2 {{trailing closure passed to parameter of type 'Int' that does not accept a closure}}
trailingClosureMulti2() { 1 } trailingClosureMulti2() { 1 }
// expected-error@-1 {{missing arguments for parameters 'x', 'y' in call}} // expected-error@-1 {{missing arguments for parameters 'x', 'z' in call}}
// expected-error@-2 {{trailing closure passed to parameter of type 'Int' that does not accept a closure}}
trailingClosureMulti2(x: 1) { 1 } trailingClosureMulti2(x: 1) { 1 }
// expected-error@-1 {{missing argument for parameter 'y' in call}} {{27-27=, y: <#() -> Int#>}} // expected-error@-1 {{missing argument for parameter 'z' in call}} {{none}}
// expected-error@-2 {{trailing closure passed to parameter of type 'Int' that does not accept a closure}}
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}} 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#>}} param2Func(x: 1) // expected-error {{missing argument for parameter 'y' in call}} {{16-16=, y: <#Int#>}}

View File

@@ -38,14 +38,3 @@ func testUnresolvedMember(i: Int) -> X {
// CHECK-NEXT: introducing single enabled disjunction term {{.*}} bound to decl overload_filtering.(file).X.init(_:_:) // CHECK-NEXT: introducing single enabled disjunction term {{.*}} bound to decl overload_filtering.(file).X.init(_:_:)
return .init(i, i) 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) { }
}

View File

@@ -82,7 +82,7 @@ func test_multiple_trailing_syntax_without_labels() {
fn {} g: {} // Ok 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}} fn {} g: <#T##() -> Void#> // expected-error {{editor placeholder in source file}}
@@ -90,16 +90,15 @@ func test_multiple_trailing_syntax_without_labels() {
multiple {} _: { } multiple {} _: { }
func mixed_args_1(a: () -> Void, _: () -> Void) {} // expected-note {{'mixed_args_1(a:_:)' declared here}} func mixed_args_1(a: () -> Void, _: () -> Void) {}
func mixed_args_2(_: () -> Void, a: () -> Void, _: () -> Void) {} // expected-note 2 {{'mixed_args_2(_:a:_:)' declared here}} func mixed_args_2(_: () -> Void, a: () -> Void, _: () -> Void) {} // expected-note {{'mixed_args_2(_:a:_:)' declared here}}
mixed_args_1 mixed_args_1
{} {}
_: {} _: {}
// FIXME: not a good diagnostic
mixed_args_1 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: {} a: {}
mixed_args_2 mixed_args_2
@@ -107,14 +106,13 @@ func test_multiple_trailing_syntax_without_labels() {
a: {} a: {}
_: {} _: {}
// FIXME: not a good diagnostic
mixed_args_2 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 // FIXME: not a good diagnostic
mixed_args_2 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() return fn() ?? d()
} }
// TODO: The diagnostics here are perhaps a little overboard. // 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 } _ = produce { 2 } `default`: { 3 }

View File

@@ -93,7 +93,7 @@ var c3 = C().map // expected-note{{callee is here}}
// <rdar://problem/16835718> Ban multiple trailing closures // <rdar://problem/16835718> Ban multiple trailing closures
func multiTrailingClosure(_ a : () -> (), b : () -> ()) { // expected-note {{'multiTrailingClosure(_:b:)' declared here}} func multiTrailingClosure(_ a : () -> (), b : () -> ()) { // expected-note {{'multiTrailingClosure(_:b:)' declared here}}
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 {{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({ $0 + 1 }) // expected-error {{missing argument label 'f:' in call}} {{23-23=f: }}
takeFuncWithDefault(f: { $0 + 1 }) takeFuncWithDefault(f: { $0 + 1 })
// Trailing closure binds to last parameter, always. // Trailing closure binds to first parameter.
takeTwoFuncsWithDefaults { "Hello, " + $0 } takeTwoFuncsWithDefaults { "Hello, " + $0 } // expected-error{{cannot convert value of type 'String' to expected argument type 'Int'}}
takeTwoFuncsWithDefaults { $0 + 1 } // expected-error {{cannot convert value of type 'Int' to expected argument type 'String'}} takeTwoFuncsWithDefaults { $0 + 1 }
takeTwoFuncsWithDefaults(f1: {$0 + 1 }) takeTwoFuncsWithDefaults(f1: {$0 + 1 })
} }
@@ -420,11 +420,11 @@ func variadicAndNonOverloadLabel(b: (() -> Void)...) -> Int { return 0 }
func testVariadic() { func testVariadic() {
variadic {} variadic {}
variadic() {} variadic() {}
variadic({}) {} // expected-error {{extra argument in call}} variadic({}) {}
variadicLabel {} variadicLabel {}
variadicLabel() {} variadicLabel() {}
variadicLabel(closures: {}) {} // expected-error {{extra argument 'closures' in call}} variadicLabel(closures: {}) {}
let a1 = variadicOverloadMismatch {} let a1 = variadicOverloadMismatch {}
_ = a1 as String // expected-error {{cannot convert value of type 'Bool' to type 'String'}} _ = a1 as String // expected-error {{cannot convert value of type 'Bool' to type 'String'}}

View File

@@ -7,7 +7,7 @@ func forwardMatchWithGeneric<T>( // expected-note{{'forwardMatchWithGeneric(clos
func testKnownSourceBreaks(i: Int) { func testKnownSourceBreaks(i: Int) {
forwardMatchWithGeneric { i } // expected-error{{missing argument for parameter 'closure1' in call}} 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) { func testUnlabeledParamMatching(i: Int, fn: ((Int) -> Int) -> Void) {
@@ -24,7 +24,7 @@ func forwardMatchFailure( // expected-note{{declared here}}
) { } ) { }
func testForwardMatchFailure() { func testForwardMatchFailure() {
forwardMatchFailure { x in // expected-error{{missing argument for parameter 'onCompletion' in call}} forwardMatchFailure { x in
print(x) print(x)
} } // expected-error{{missing argument for parameter 'onCompletion' in call}}{{4-4= onCompletion: <#(Int) -> Void#>}}
} }