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 *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
|
||||||
|
|||||||
@@ -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(); }
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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; }
|
||||||
|
|||||||
@@ -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}}
|
||||||
|
|||||||
@@ -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?) {}
|
||||||
|
|||||||
@@ -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#>}}
|
||||||
|
|||||||
@@ -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) { }
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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 }
|
||||||
|
|||||||
@@ -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'}}
|
||||||
|
|||||||
@@ -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#>}}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user