diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index 85419baac7eb5..a1245b55a7ff5 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -5214,7 +5214,7 @@ enum class ParamSpecifier : uint8_t { /// A function parameter declaration. class ParamDecl : public VarDecl { - Identifier ArgumentName; + llvm::PointerIntPair ArgumentNameAndDestructured; SourceLoc ParameterNameLoc; SourceLoc ArgumentNameLoc; SourceLoc SpecifierLoc; @@ -5251,7 +5251,9 @@ class ParamDecl : public VarDecl { 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 @@ class ParamDecl : public VarDecl { 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(Bits.ParamDecl.defaultArgumentKind); } diff --git a/include/swift/AST/DiagnosticsParse.def b/include/swift/AST/DiagnosticsParse.def index 372f4da91de25..1631b418a8597 100644 --- a/include/swift/AST/DiagnosticsParse.def +++ b/include/swift/AST/DiagnosticsParse.def @@ -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", ()) diff --git a/include/swift/Parse/Parser.h b/include/swift/Parse/Parser.h index 7e6aa6246f2c8..e8d16b476fe1c 100644 --- a/include/swift/Parse/Parser.h +++ b/include/swift/Parse/Parser.h @@ -1211,6 +1211,9 @@ class Parser { /// 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. diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index ebc5f71acd872..272e7ae64fab9 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -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 = diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 509832428a81d..35ed9ceeaed2d 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -2657,7 +2657,7 @@ parseClosureSignatureIfPresent(SmallVectorImpl &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(typeRepr); }; diff --git a/lib/Parse/ParsePattern.cpp b/lib/Parse/ParsePattern.cpp index f5c68ed854872..1c94c419cdda0 100644 --- a/lib/Parse/ParsePattern.cpp +++ b/lib/Parse/ParsePattern.cpp @@ -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 { @@ -492,7 +498,13 @@ mapParsedParameters(Parser &parser, // If we diagnosed this parameter as a parse error, propagate to the decl. 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. diff --git a/test/Constraints/tuple_arguments.swift b/test/Constraints/tuple_arguments.swift index 860ba5b0f1b6a..a1e694ff37250 100644 --- a/test/Constraints/tuple_arguments.swift +++ b/test/Constraints/tuple_arguments.swift @@ -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 diff --git a/test/decl/func/functions.swift b/test/decl/func/functions.swift index 347994b975f71..a306719b8886c 100644 --- a/test/decl/func/functions.swift +++ b/test/decl/func/functions.swift @@ -192,8 +192,8 @@ func bogusDestructuring() { func registerCallback(_ callback: @escaping (Bar?) -> Void) {} // expected-note {{found this candidate}} } - Foo().registerCallback { ([Bar]) in } // expected-error {{'<>' is not convertible to '[Bar]'}} - Foo().registerCallback { ([String: Bar]) in } // expected-error {{'<>' 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}} diff --git a/validation-test/compiler_crashers_fixed/28723-unreachable-executed-at-swift-lib-sema-csdiag-cpp-4012.swift b/validation-test/compiler_crashers_fixed/28723-unreachable-executed-at-swift-lib-sema-csdiag-cpp-4012.swift index 41d44b869c2d3..19e57661a94c8 100644 --- a/validation-test/compiler_crashers_fixed/28723-unreachable-executed-at-swift-lib-sema-csdiag-cpp-4012.swift +++ b/validation-test/compiler_crashers_fixed/28723-unreachable-executed-at-swift-lib-sema-csdiag-cpp-4012.swift @@ -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(