diff --git a/include/swift/AST/DiagnosticsParse.def b/include/swift/AST/DiagnosticsParse.def index 95b9690a064af..4b2f9f076a7da 100644 --- a/include/swift/AST/DiagnosticsParse.def +++ b/include/swift/AST/DiagnosticsParse.def @@ -1311,8 +1311,6 @@ ERROR(dollar_identifier_decl,none, "cannot declare entity named %0; the '$' prefix is reserved for " "implicitly-synthesized declarations", (Identifier)) -ERROR(anon_closure_arg_not_in_closure,none, - "anonymous closure argument not contained in a closure", ()) ERROR(anon_closure_arg_in_closure_with_args,none, "anonymous closure arguments cannot be used inside a closure that has " "explicit arguments", ()) diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index f63485114f19c..a1f37210022cd 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -1702,6 +1702,8 @@ ERROR(extra_trailing_closure_in_call,none, ERROR(closure_bad_param,none, "%select{|trailing }1closure passed to parameter of type %0 that does not " "accept a closure", (Type, bool)) +ERROR(anon_closure_arg_not_in_closure,none, + "anonymous closure argument not contained in a closure", ()) GROUPED_WARNING(unlabeled_trailing_closure_deprecated, TrailingClosureMatching,Deprecation, "backward matching of the unlabeled trailing closure is deprecated; label the argument with %0 to suppress this warning", diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 84063848ec4db..3fcdad9bdda0b 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -3192,14 +3192,10 @@ Expr *Parser::parseExprAnonClosureArg() { auto closure = dyn_cast_or_null( dyn_cast(CurDeclContext)); if (!closure) { - if (Context.LangOpts.DebuggerSupport) { - auto refKind = DeclRefKind::Ordinary; - auto identifier = Context.getIdentifier(Name); - return new (Context) UnresolvedDeclRefExpr(DeclNameRef(identifier), - refKind, DeclNameLoc(Loc)); - } - diagnose(Loc, diag::anon_closure_arg_not_in_closure); - return new (Context) ErrorExpr(Loc); + auto refKind = DeclRefKind::Ordinary; + auto identifier = Context.getIdentifier(Name); + return new (Context) UnresolvedDeclRefExpr(DeclNameRef(identifier), refKind, + DeclNameLoc(Loc)); } // Check whether the closure already has explicit parameters. diff --git a/lib/Sema/PreCheckTarget.cpp b/lib/Sema/PreCheckTarget.cpp index 4ee4290dd81b4..b72ee55dd9b30 100644 --- a/lib/Sema/PreCheckTarget.cpp +++ b/lib/Sema/PreCheckTarget.cpp @@ -946,6 +946,23 @@ Expr *TypeChecker::resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE, } auto emitBasicError = [&] { + // Check for anonymous closure arguments (e.g. $0, $1) used outside + // closures. + if (Name.isSimpleName()) { + StringRef nameStr = Name.getBaseIdentifier().str(); + if (nameStr.starts_with("$")) { + StringRef numStr = nameStr.substr(1); + unsigned ArgNo; + if (!numStr.getAsInteger(10, ArgNo)) { + auto *closure = dyn_cast_or_null(DC); + if (!closure) { + Context.Diags.diagnose(Loc, diag::anon_closure_arg_not_in_closure) + .highlight(UDRE->getSourceRange()); + return; + } + } + } + } if (Name.isSimpleName(Context.Id_self)) { // `self` gets diagnosed with a different error when it can't be found. Context.Diags.diagnose(Loc, diag::cannot_find_self_in_scope) diff --git a/test/Sema/issue-54030.swift b/test/Sema/issue-54030.swift new file mode 100644 index 0000000000000..9c26d2339400d --- /dev/null +++ b/test/Sema/issue-54030.swift @@ -0,0 +1,9 @@ +// RUN: %target-typecheck-verify-swift + +// https://github.com/swiftlang/swift/issues/54030 + +if $0 {} // expected-error {{anonymous closure argument not contained in a closure}} + +#if false +if $0 {} +#endif