mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Sema: Horrific simulation of Swift 3 bug with argument labels for Swift 3 mode
In Swift 3.0.1, argument labels are ignored when calling a function
having a single parameter of 'Any' type. That is, if we have:
func foo(_: Any) {}
Both of the following were accepted in a no-assert build (an assert
build would crash, but the GM builds of Xcode ship with asserts off):
foo(123)
foo(data: 123)
This behavior was fixed by 578e36a7e1,
but unfortunately we have to revert to the old behavior *and* defeat
the assertion when in Swift 3 mode.
Swift 4 mode still has the correct behavior, where the second call
'foo(data: 123)' produces a diagnostic.
Now, I have to pour myself a strong drink to forget this ever happened.
Fixes <rdar://problem/28952837>.
This commit is contained in:
@@ -4702,13 +4702,34 @@ Expr *ExprRewriter::coerceCallArguments(
|
||||
bool hasTrailingClosure,
|
||||
ConstraintLocatorBuilder locator) {
|
||||
|
||||
// Total hack: In Swift 3 mode, we can end up with an arity mismatch due to
|
||||
// loss of ParenType sugar.
|
||||
// Local function to produce a locator to refer to the ith element of the
|
||||
// argument tuple.
|
||||
auto getArgLocator = [&](unsigned argIdx, unsigned paramIdx)
|
||||
-> ConstraintLocatorBuilder {
|
||||
return locator.withPathElement(
|
||||
LocatorPathElt::getApplyArgToParam(argIdx, paramIdx));
|
||||
};
|
||||
|
||||
bool matchCanFail = false;
|
||||
|
||||
// If you value your sanity, ignore the body of this 'if' statement.
|
||||
if (cs.getASTContext().isSwiftVersion3()) {
|
||||
// Total hack: In Swift 3 mode, we can end up with an arity mismatch due to
|
||||
// loss of ParenType sugar.
|
||||
if (isa<TupleExpr>(arg))
|
||||
if (auto *parenType = dyn_cast<ParenType>(paramType.getPointer()))
|
||||
if (isa<TupleType>(parenType->getUnderlyingType().getPointer()))
|
||||
paramType = parenType->getUnderlyingType();
|
||||
|
||||
// Total hack: In Swift 3 mode, argument labels are ignored when calling
|
||||
// function type with a single Any parameter.
|
||||
if (paramType->isAny()) {
|
||||
if (auto tupleArgType = dyn_cast<TupleType>(arg->getType().getPointer())) {
|
||||
if (tupleArgType->getNumElements() == 1) {
|
||||
matchCanFail = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool allParamsMatch = cs.getType(arg)->isEqual(paramType);
|
||||
@@ -4778,7 +4799,8 @@ Expr *ExprRewriter::coerceCallArguments(
|
||||
hasTrailingClosure,
|
||||
/*allowFixes=*/false, listener,
|
||||
parameterBindings);
|
||||
assert(!failed && "Call arguments did not match up?");
|
||||
|
||||
assert((matchCanFail || !failed) && "Call arguments did not match up?");
|
||||
(void)failed;
|
||||
|
||||
// We should either have parentheses or a tuple.
|
||||
@@ -4810,14 +4832,6 @@ Expr *ExprRewriter::coerceCallArguments(
|
||||
return Identifier();
|
||||
};
|
||||
|
||||
// Local function to produce a locator to refer to the ith element of the
|
||||
// argument tuple.
|
||||
auto getArgLocator = [&](unsigned argIdx, unsigned paramIdx)
|
||||
-> ConstraintLocatorBuilder {
|
||||
return locator.withPathElement(
|
||||
LocatorPathElt::getApplyArgToParam(argIdx, paramIdx));
|
||||
};
|
||||
|
||||
auto &tc = getConstraintSystem().getTypeChecker();
|
||||
SmallVector<TupleTypeElt, 4> toSugarFields;
|
||||
SmallVector<TupleTypeElt, 4> fromTupleExprFields(
|
||||
|
||||
@@ -623,6 +623,26 @@ static ConstraintSystem::SolutionKind
|
||||
matchCallArguments(ConstraintSystem &cs, ConstraintKind kind,
|
||||
Type argType, Type paramType,
|
||||
ConstraintLocatorBuilder locator) {
|
||||
|
||||
if (paramType->isAny()) {
|
||||
if (argType->is<InOutType>())
|
||||
return ConstraintSystem::SolutionKind::Error;
|
||||
|
||||
// If the param type is Any, the function can only have one argument.
|
||||
// Check if exactly one argument was passed to this function, otherwise
|
||||
// we obviously have a mismatch.
|
||||
if (auto tupleArgType = dyn_cast<TupleType>(argType.getPointer())) {
|
||||
// Total hack: In Swift 3 mode, argument labels are ignored when calling
|
||||
// function type with a single Any parameter.
|
||||
if (tupleArgType->getNumElements() != 1 ||
|
||||
(!cs.getASTContext().isSwiftVersion3() &&
|
||||
tupleArgType->getElement(0).hasName())) {
|
||||
return ConstraintSystem::SolutionKind::Error;
|
||||
}
|
||||
}
|
||||
return ConstraintSystem::SolutionKind::Solved;
|
||||
}
|
||||
|
||||
// Extract the parameters.
|
||||
ValueDecl *callee;
|
||||
unsigned calleeLevel;
|
||||
@@ -644,16 +664,6 @@ matchCallArguments(ConstraintSystem &cs, ConstraintKind kind,
|
||||
parameterBindings))
|
||||
return ConstraintSystem::SolutionKind::Error;
|
||||
|
||||
// In the empty existential parameter case,
|
||||
// it's sufficient to simply match call arguments.
|
||||
if (paramType->isAny()) {
|
||||
// Argument of the existential type can't be inout.
|
||||
if (argType->is<InOutType>())
|
||||
return ConstraintSystem::SolutionKind::Error;
|
||||
|
||||
return ConstraintSystem::SolutionKind::Solved;
|
||||
}
|
||||
|
||||
// Check the argument types for each of the parameters.
|
||||
ConstraintSystem::TypeMatchOptions subflags =
|
||||
ConstraintSystem::TMF_GenerateConstraints;
|
||||
|
||||
@@ -1269,3 +1269,17 @@ do {
|
||||
let _: (Int, Int) -> () = { _ = ($0, $1) }
|
||||
let _: (Int, Int) -> () = { t, u in _ = (t, u) }
|
||||
}
|
||||
|
||||
// rdar://problem/28952837 - argument labels ignored when calling function
|
||||
// with single 'Any' parameter
|
||||
func takesAny(_: Any) {}
|
||||
|
||||
do {
|
||||
let fn: (Any) -> () = { _ in }
|
||||
|
||||
fn(123)
|
||||
fn(data: 123)
|
||||
|
||||
takesAny(123)
|
||||
takesAny(data: 123)
|
||||
}
|
||||
|
||||
@@ -349,6 +349,9 @@ class C_SR_2505 : P_SR_2505 {
|
||||
}
|
||||
|
||||
func call(_ c: C_SR_2505) -> Bool {
|
||||
// Note: no diagnostic about capturing 'self', because this is a
|
||||
// non-escaping closure -- that's how we know we have selected
|
||||
// test(it:) and not test(_)
|
||||
return c.test { o in test(o) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -829,9 +829,13 @@ func foo1255_2() -> Int {
|
||||
|
||||
// SR-2505: "Call arguments did not match up" assertion
|
||||
|
||||
// Here we're simulating the busted Swift 3 behavior -- see
|
||||
// test/Constraints/diagnostics_swift4.swift for the correct
|
||||
// behavior.
|
||||
|
||||
func sr_2505(_ a: Any) {} // expected-note {{}}
|
||||
sr_2505() // expected-error {{missing argument for parameter #1 in call}}
|
||||
sr_2505(a: 1) // expected-error {{extraneous argument label 'a:' in call}}
|
||||
sr_2505(a: 1) // FIXME: emit a warning saying this becomes an error in Swift 4
|
||||
sr_2505(1, 2) // expected-error {{extra argument in call}}
|
||||
sr_2505(a: 1, 2) // expected-error {{extra argument in call}}
|
||||
|
||||
@@ -851,7 +855,8 @@ extension C_2505 {
|
||||
class C2_2505: P_2505 {
|
||||
}
|
||||
|
||||
let c_2505 = C_2505(arg: [C2_2505()]) // expected-error {{argument labels '(arg:)' do not match any available overloads}} expected-note {{overloads for 'C_2505' exist}}
|
||||
// FIXME: emit a warning saying this becomes an error in Swift 4
|
||||
let c_2505 = C_2505(arg: [C2_2505()])
|
||||
|
||||
// Diagnostic message for initialization with binary operations as right side
|
||||
let foo1255_3: String = 1 + 2 + 3 // expected-error {{cannot convert value of type 'Int' to specified type 'String'}}
|
||||
|
||||
@@ -1254,3 +1254,17 @@ do {
|
||||
let _: (Int, Int) -> () = { _ = ($0, $1) }
|
||||
let _: (Int, Int) -> () = { t, u in _ = (t, u) }
|
||||
}
|
||||
|
||||
// rdar://problem/28952837 - argument labels ignored when calling function
|
||||
// with single 'Any' parameter
|
||||
func takesAny(_: Any) {}
|
||||
|
||||
do {
|
||||
let fn: (Any) -> () = { _ in }
|
||||
|
||||
fn(123)
|
||||
fn(data: 123) // expected-error {{extraneous argument label 'data:' in call}}
|
||||
|
||||
takesAny(123)
|
||||
takesAny(data: 123) // expected-error {{extraneous argument label 'data:' in call}}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user