mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Partially Revert #27862
When SE-110 was being implemented, we accidentally began to accept
closure parameter declarations that had no associated parameter names,
e.g.
foo { ([Int]) in /**/ }
This syntax has never been sanctioned by any version of Swift and should
be banned. However, the change was made long enough ago and there are
enough clients relying on this, that we cannot accept the source break
at the moment. For now, add a bit to ParamDecl that marks a parameter
as destructured, and back out setting the invalid bit on the type repr
for these kinds of declarations.
To prevent further spread of this syntax, stub in a warning that offers
to insert an anonymous parameter.
Resolves part of rdar://56673657 and improves QoI for errors like
rdar://56911630
This commit is contained in:
@@ -5214,7 +5214,7 @@ enum class ParamSpecifier : uint8_t {
|
||||
|
||||
/// A function parameter declaration.
|
||||
class ParamDecl : public VarDecl {
|
||||
Identifier ArgumentName;
|
||||
llvm::PointerIntPair<Identifier, 1, bool> ArgumentNameAndDestructured;
|
||||
SourceLoc ParameterNameLoc;
|
||||
SourceLoc ArgumentNameLoc;
|
||||
SourceLoc SpecifierLoc;
|
||||
@@ -5251,7 +5251,9 @@ public:
|
||||
static ParamDecl *cloneWithoutType(const ASTContext &Ctx, ParamDecl *PD);
|
||||
|
||||
/// Retrieve the argument (API) name for this function parameter.
|
||||
Identifier getArgumentName() const { return ArgumentName; }
|
||||
Identifier getArgumentName() const {
|
||||
return ArgumentNameAndDestructured.getPointer();
|
||||
}
|
||||
|
||||
/// Retrieve the parameter (local) name for this function parameter.
|
||||
Identifier getParameterName() const { return getName(); }
|
||||
@@ -5270,6 +5272,9 @@ public:
|
||||
TypeRepr *getTypeRepr() const { return TyRepr; }
|
||||
void setTypeRepr(TypeRepr *repr) { TyRepr = repr; }
|
||||
|
||||
bool isDestructured() const { return ArgumentNameAndDestructured.getInt(); }
|
||||
void setDestructured(bool repr) { ArgumentNameAndDestructured.setInt(repr); }
|
||||
|
||||
DefaultArgumentKind getDefaultArgumentKind() const {
|
||||
return static_cast<DefaultArgumentKind>(Bits.ParamDecl.defaultArgumentKind);
|
||||
}
|
||||
|
||||
@@ -893,6 +893,8 @@ ERROR(parameter_operator_keyword_argument,none,
|
||||
|
||||
ERROR(parameter_unnamed,none,
|
||||
"unnamed parameters must be written with the empty name '_'", ())
|
||||
WARNING(parameter_unnamed_warn,none,
|
||||
"unnamed parameters must be written with the empty name '_'", ())
|
||||
|
||||
ERROR(parameter_curry_syntax_removed,none,
|
||||
"cannot have more than one parameter list", ())
|
||||
|
||||
@@ -1211,6 +1211,9 @@ public:
|
||||
|
||||
/// True if we emitted a parse error about this parameter.
|
||||
bool isInvalid = false;
|
||||
|
||||
/// True if this parameter is potentially destructuring a tuple argument.
|
||||
bool isPotentiallyDestructured = false;
|
||||
};
|
||||
|
||||
/// Describes the context in which the given parameter is being parsed.
|
||||
|
||||
@@ -5914,7 +5914,8 @@ ParamDecl::ParamDecl(SourceLoc specifierLoc,
|
||||
VarDecl::Introducer::Let,
|
||||
/*IsCaptureList*/ false, parameterNameLoc, parameterName, dc,
|
||||
StorageIsNotMutable),
|
||||
ArgumentName(argumentName), ParameterNameLoc(parameterNameLoc),
|
||||
ArgumentNameAndDestructured(argumentName, false),
|
||||
ParameterNameLoc(parameterNameLoc),
|
||||
ArgumentNameLoc(argumentNameLoc), SpecifierLoc(specifierLoc) {
|
||||
Bits.ParamDecl.SpecifierComputed = false;
|
||||
Bits.ParamDecl.defaultArgumentKind =
|
||||
|
||||
@@ -2657,7 +2657,7 @@ parseClosureSignatureIfPresent(SmallVectorImpl<CaptureListEntry> &captureList,
|
||||
// possible and give a proper fix-it. See SE-0110 for more details.
|
||||
auto isTupleDestructuring = [](ParamDecl *param) -> bool {
|
||||
auto *typeRepr = param->getTypeRepr();
|
||||
if (!(typeRepr && typeRepr->isInvalid()))
|
||||
if (!(typeRepr && param->isDestructured()))
|
||||
return false;
|
||||
return !param->hasName() && isa<TupleTypeRepr>(typeRepr);
|
||||
};
|
||||
|
||||
@@ -363,12 +363,18 @@ Parser::parseParameterClause(SourceLoc &leftParenLoc,
|
||||
if (param.Type) {
|
||||
// Mark current parameter type as invalid so it is possible
|
||||
// to diagnose it as destructuring of the closure parameter list.
|
||||
param.Type->setInvalid();
|
||||
param.isInvalid = true;
|
||||
param.isPotentiallyDestructured = true;
|
||||
if (!isClosure) {
|
||||
// Unnamed parameters must be written as "_: Type".
|
||||
diagnose(typeStartLoc, diag::parameter_unnamed)
|
||||
.fixItInsert(typeStartLoc, "_: ");
|
||||
} else {
|
||||
// Unnamed parameters were accidentally possibly accepted after
|
||||
// SE-110 depending on the kind of declaration. We now need to
|
||||
// warn about the misuse of this syntax and offer to
|
||||
// fix it.
|
||||
diagnose(typeStartLoc, diag::parameter_unnamed_warn)
|
||||
.fixItInsert(typeStartLoc, "_: ");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -493,6 +499,12 @@ mapParsedParameters(Parser &parser,
|
||||
if (paramInfo.isInvalid)
|
||||
param->setInvalid();
|
||||
|
||||
// If we need to diagnose this parameter as a destructuring, propagate that
|
||||
// to the decl.
|
||||
// FIXME: This is a terrible way to catch this.
|
||||
if (paramInfo.isPotentiallyDestructured)
|
||||
param->setDestructured(true);
|
||||
|
||||
// If a type was provided, create the type for the parameter.
|
||||
if (auto type = paramInfo.Type) {
|
||||
// If 'inout' was specified, turn the type into an in-out type.
|
||||
|
||||
@@ -1470,6 +1470,9 @@ let _ = sr4745.enumerated().map { (count, element) in "\(count): \(element)" }
|
||||
let sr4738 = (1, (2, 3))
|
||||
[sr4738].map { (x, (y, z)) -> Int in x + y + z }
|
||||
// expected-error@-1 {{closure tuple parameter does not support destructuring}} {{20-26=arg1}} {{38-38=let (y, z) = arg1; }}
|
||||
// expected-warning@-2 {{unnamed parameters must be written with the empty name '_'}} {{20-20=_: }}
|
||||
// expected-error@-3 {{use of undeclared type 'y'}}
|
||||
// expected-error@-4 {{use of undeclared type 'z'}}
|
||||
|
||||
// rdar://problem/31892961
|
||||
let r31892961_1 = [1: 1, 2: 2]
|
||||
@@ -1478,6 +1481,9 @@ r31892961_1.forEach { (k, v) in print(k + v) }
|
||||
let r31892961_2 = [1, 2, 3]
|
||||
let _: [Int] = r31892961_2.enumerated().map { ((index, val)) in
|
||||
// expected-error@-1 {{closure tuple parameter does not support destructuring}} {{48-60=arg0}} {{3-3=\n let (index, val) = arg0\n }}
|
||||
// expected-warning@-2 {{unnamed parameters must be written with the empty name '_'}} {{48-48=_: }}
|
||||
// expected-error@-3 {{use of undeclared type 'index'}}
|
||||
// expected-error@-4 {{use of undeclared type 'val'}}
|
||||
val + 1
|
||||
}
|
||||
|
||||
@@ -1490,12 +1496,16 @@ let r31892961_4 = (1, 2)
|
||||
_ = [r31892961_4].map { x, y in x + y }
|
||||
|
||||
let r31892961_5 = (x: 1, (y: 2, (w: 3, z: 4)))
|
||||
[r31892961_5].map { (x: Int, (y: Int, (w: Int, z: Int))) in x + y }
|
||||
[r31892961_5].map { (x: Int, (y: Int, (w: Int, z: Int))) in x + y } // expected-note {{'x' declared here}}
|
||||
// expected-error@-1 {{closure tuple parameter does not support destructuring}} {{30-56=arg1}} {{61-61=let (y, (w, z)) = arg1; }}
|
||||
// expected-warning@-2 {{unnamed parameters must be written with the empty name '_'}} {{30-30=_: }}
|
||||
// expected-error@-3{{use of unresolved identifier 'y'; did you mean 'x'?}}
|
||||
|
||||
let r31892961_6 = (x: 1, (y: 2, z: 4))
|
||||
[r31892961_6].map { (x: Int, (y: Int, z: Int)) in x + y }
|
||||
[r31892961_6].map { (x: Int, (y: Int, z: Int)) in x + y } // expected-note {{'x' declared here}}
|
||||
// expected-error@-1 {{closure tuple parameter does not support destructuring}} {{30-46=arg1}} {{51-51=let (y, z) = arg1; }}
|
||||
// expected-warning@-2 {{unnamed parameters must be written with the empty name '_'}} {{30-30=_: }}
|
||||
// expected-error@-3{{use of unresolved identifier 'y'; did you mean 'x'?}}
|
||||
|
||||
// rdar://problem/32214649 -- these regressed in Swift 4 mode
|
||||
// with SE-0110 because of a problem in associated type inference
|
||||
|
||||
@@ -192,8 +192,8 @@ func bogusDestructuring() {
|
||||
func registerCallback(_ callback: @escaping (Bar?) -> Void) {} // expected-note {{found this candidate}}
|
||||
}
|
||||
|
||||
Foo().registerCallback { ([Bar]) in } // expected-error {{'<<error type>>' is not convertible to '[Bar]'}}
|
||||
Foo().registerCallback { ([String: Bar]) in } // expected-error {{'<<error type>>' is not convertible to '[Bar]'}}
|
||||
Foo().registerCallback { ([Bar]) in } // expected-warning {{unnamed parameters must be written with the empty name '_'}} {{29-29=_: }}
|
||||
Foo().registerCallback { ([String: Bar]) in }// expected-warning {{unnamed parameters must be written with the empty name '_'}} {{29-29=_: }}
|
||||
Foo().registerCallback { (Bar?) in } // expected-error {{ambiguous use of 'registerCallback'}}
|
||||
// expected-error@-1 {{expected parameter name followed by ':'}}
|
||||
// expected-error@-2 {{expected ',' separator}}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
|
||||
// rdar://56144412
|
||||
// XFAIL: asserts
|
||||
// RUN: not %target-swift-frontend %s -emit-ir
|
||||
func t(UInt=__FUNCTION__
|
||||
func&t(
|
||||
|
||||
Reference in New Issue
Block a user