mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +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,
|
bool hasTrailingClosure,
|
||||||
ConstraintLocatorBuilder locator) {
|
ConstraintLocatorBuilder locator) {
|
||||||
|
|
||||||
|
// 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
|
// Total hack: In Swift 3 mode, we can end up with an arity mismatch due to
|
||||||
// loss of ParenType sugar.
|
// loss of ParenType sugar.
|
||||||
if (cs.getASTContext().isSwiftVersion3()) {
|
|
||||||
if (isa<TupleExpr>(arg))
|
if (isa<TupleExpr>(arg))
|
||||||
if (auto *parenType = dyn_cast<ParenType>(paramType.getPointer()))
|
if (auto *parenType = dyn_cast<ParenType>(paramType.getPointer()))
|
||||||
if (isa<TupleType>(parenType->getUnderlyingType().getPointer()))
|
if (isa<TupleType>(parenType->getUnderlyingType().getPointer()))
|
||||||
paramType = parenType->getUnderlyingType();
|
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);
|
bool allParamsMatch = cs.getType(arg)->isEqual(paramType);
|
||||||
@@ -4778,7 +4799,8 @@ Expr *ExprRewriter::coerceCallArguments(
|
|||||||
hasTrailingClosure,
|
hasTrailingClosure,
|
||||||
/*allowFixes=*/false, listener,
|
/*allowFixes=*/false, listener,
|
||||||
parameterBindings);
|
parameterBindings);
|
||||||
assert(!failed && "Call arguments did not match up?");
|
|
||||||
|
assert((matchCanFail || !failed) && "Call arguments did not match up?");
|
||||||
(void)failed;
|
(void)failed;
|
||||||
|
|
||||||
// We should either have parentheses or a tuple.
|
// We should either have parentheses or a tuple.
|
||||||
@@ -4810,14 +4832,6 @@ Expr *ExprRewriter::coerceCallArguments(
|
|||||||
return Identifier();
|
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();
|
auto &tc = getConstraintSystem().getTypeChecker();
|
||||||
SmallVector<TupleTypeElt, 4> toSugarFields;
|
SmallVector<TupleTypeElt, 4> toSugarFields;
|
||||||
SmallVector<TupleTypeElt, 4> fromTupleExprFields(
|
SmallVector<TupleTypeElt, 4> fromTupleExprFields(
|
||||||
|
|||||||
@@ -623,6 +623,26 @@ static ConstraintSystem::SolutionKind
|
|||||||
matchCallArguments(ConstraintSystem &cs, ConstraintKind kind,
|
matchCallArguments(ConstraintSystem &cs, ConstraintKind kind,
|
||||||
Type argType, Type paramType,
|
Type argType, Type paramType,
|
||||||
ConstraintLocatorBuilder locator) {
|
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.
|
// Extract the parameters.
|
||||||
ValueDecl *callee;
|
ValueDecl *callee;
|
||||||
unsigned calleeLevel;
|
unsigned calleeLevel;
|
||||||
@@ -644,16 +664,6 @@ matchCallArguments(ConstraintSystem &cs, ConstraintKind kind,
|
|||||||
parameterBindings))
|
parameterBindings))
|
||||||
return ConstraintSystem::SolutionKind::Error;
|
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.
|
// Check the argument types for each of the parameters.
|
||||||
ConstraintSystem::TypeMatchOptions subflags =
|
ConstraintSystem::TypeMatchOptions subflags =
|
||||||
ConstraintSystem::TMF_GenerateConstraints;
|
ConstraintSystem::TMF_GenerateConstraints;
|
||||||
|
|||||||
@@ -1269,3 +1269,17 @@ do {
|
|||||||
let _: (Int, Int) -> () = { _ = ($0, $1) }
|
let _: (Int, Int) -> () = { _ = ($0, $1) }
|
||||||
let _: (Int, Int) -> () = { t, u in _ = (t, u) }
|
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 {
|
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) }
|
return c.test { o in test(o) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -829,9 +829,13 @@ func foo1255_2() -> Int {
|
|||||||
|
|
||||||
// SR-2505: "Call arguments did not match up" assertion
|
// 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 {{}}
|
func sr_2505(_ a: Any) {} // expected-note {{}}
|
||||||
sr_2505() // expected-error {{missing argument for parameter #1 in call}}
|
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(1, 2) // expected-error {{extra argument in call}}
|
||||||
sr_2505(a: 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 {
|
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
|
// 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'}}
|
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) -> () = { _ = ($0, $1) }
|
||||||
let _: (Int, Int) -> () = { t, u in _ = (t, u) }
|
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