Skip to content

Commit ad78204

Browse files
committed
Parser: Explicitly ban closures at the beginning of statements.
This already can't happen in most circumstances because of trailing closures, but we didn't explicitly disallow it at the beginning of a BraceStmt or following a statement production. Fixes the parser part of rdar://problem/17850752 (though there's a type checker bug there too). Swift SVN r21663
1 parent 3c2f165 commit ad78204

File tree

8 files changed

+33
-6
lines changed

8 files changed

+33
-6
lines changed

include/swift/AST/DiagnosticsParse.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -645,13 +645,17 @@ ERROR(illegal_top_level_expr,stmt_parsing,none,
645645
"expressions are not allowed at the top level", ())
646646
ERROR(illegal_semi_stmt,stmt_parsing,none,
647647
"';' statements are not allowed", ())
648+
ERROR(statement_begins_with_closure,stmt_parsing,none,
649+
"statement cannot begin with a closure expression", ())
648650
ERROR(statement_same_line_without_semi,stmt_parsing,none,
649651
"consecutive statements on a line must be separated by ';'", ())
650652
ERROR(brace_stmt_invalid,stmt_parsing,none,
651653
"braced block of statements is an unused closure", ())
652654
ERROR(invalid_label_on_stmt,stmt_parsing,none,
653655
"labels are only valid on loops and switch statement", ())
654656

657+
NOTE(discard_result_of_closure,stmt_parsing,none,
658+
"explicitly discard the result of the closure by assigning to '_'", ())
655659

656660
// Assignment statement
657661
ERROR(expected_expr_assignment,stmt_parsing,none,

lib/Parse/ParseStmt.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,14 @@ ParserStatus Parser::parseBraceItems(SmallVectorImpl<ASTNode> &Entries,
324324
ContextChange CC(*this, TLCD, &State->getTopLevelContext());
325325
SourceLoc StartLoc = Tok.getLoc();
326326

327+
// Expressions can't begin with a closure literal at statement position.
328+
// This prevents potential ambiguities with trailing closure syntax.
329+
if (Tok.is(tok::l_brace)) {
330+
diagnose(Tok, diag::statement_begins_with_closure);
331+
diagnose(Tok, diag::discard_result_of_closure)
332+
.fixItInsert(Tok.getLoc(), "_ = ");
333+
}
334+
327335
ParserStatus Status = parseExprOrStmt(Result);
328336
if (Status.hasCodeCompletion() && isCodeCompletionFirstPass()) {
329337
consumeTopLevelDecl(BeginParserPosition, TLCD);
@@ -434,6 +442,15 @@ void Parser::parseTopLevelCodeDeclDelayed() {
434442

435443
SourceLoc StartLoc = Tok.getLoc();
436444
ASTNode Result;
445+
446+
// Expressions can't begin with a closure literal at statement position. This
447+
// prevents potential ambiguities with trailing closure syntax.
448+
if (Tok.is(tok::l_brace)) {
449+
diagnose(Tok, diag::statement_begins_with_closure);
450+
diagnose(Tok, diag::discard_result_of_closure)
451+
.fixItInsert(Tok.getLoc(), "_ = ");
452+
}
453+
437454
parseExprOrStmt(Result);
438455
if (!Result.isNull()) {
439456
auto Brace = BraceStmt::create(Context, StartLoc, Result, Tok.getLoc());

test/Interpreter/repl.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ chained
202202
[chained]
203203
// CHECK: : [(f: Int -> ()) -> Int]
204204

205-
{97210}()
205+
({97210}())
206206
// CHECK: = 97210
207207
true && true
208208
// CHECK: = true

test/decl/ext/extensions.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ protocol P2 {}
7171

7272
extension () {} // expected-error {{expected identifier in extension declaration}}
7373
// expected-error @-1{{braced block of statements is an unused closure}}
74+
// expected-error @-2{{cannot begin with a closure expression}}
75+
// expected-note @-3{{explicitly discard the result}}
7476

7577
typealias TupleAlias = (x: Int, y: Int)
7678
extension TupleAlias {} // expected-error{{non-nominal type 'TupleAlias' cannot be extended}}

test/decl/func/static_func.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ static override func gf5() {} // expected-error {{static methods may only be dec
1313
class override func gf6() {} // expected-error {{class methods may only be declared on a type}}{{1-6=}}
1414
// expected-error@-1 {{'override' can only be specified on class members}}{{7-15=}}
1515

16-
static gf7() {} // expected-error {{expected declaration}} expected-error {{braced block of statements is an unused closure}}
17-
class gf8() {} // expected-error {{expected '{' in class}} expected-error {{braced block of statements is an unused closure}}
16+
static gf7() {} // expected-error {{expected declaration}} expected-error {{braced block of statements is an unused closure}} expected-error{{begin with a closure}} expected-note{{discard the result}}
17+
class gf8() {} // expected-error {{expected '{' in class}} expected-error {{braced block of statements is an unused closure}} expected-error{{begin with a closure}} expected-note{{discard the result}}
1818

1919
func inGlobalFunc() {
2020
static func gf1() {} // expected-error {{static methods may only be declared on a type}}{{3-9=}}

test/decl/operators.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ prefix func +// this should be a comment, not an operator
6060
prefix func -/* this also should be a comment, not an operator */
6161
(arg: Int) -> Int { return arg }
6262

63-
func +*/ () {} // expected-error {{expected identifier in function declaration}} expected-error {{unexpected end of block comment}} expected-error {{braced block of statements is an unused closure}}
63+
func +*/ () {} // expected-error {{expected identifier in function declaration}} expected-error {{unexpected end of block comment}} expected-error {{braced block of statements is an unused closure}} expected-error{{begin with a closure}} expected-note{{discard the result}}
6464
func errors() {
6565
*/ // expected-error {{unexpected end of block comment}}
6666

@@ -161,7 +161,7 @@ func operator_in_func_bad () {
161161
// expected-error {{braced block of statements is an unused closure}}
162162
}
163163

164-
infix operator ? {} // expected-error {{expected operator name in operator declaration}} expected-error {{braced block of statements is an unused closure}}
164+
infix operator ? {} // expected-error {{expected operator name in operator declaration}} expected-error {{braced block of statements is an unused closure}} expected-error{{begin with a closure}} expected-note{{discard the result}}
165165

166166
infix operator ??= {}
167167

test/expr/closure/closures.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,3 +194,7 @@ var closureWithObservedProperty: () -> () = {
194194
}
195195
}
196196

197+
;
198+
199+
{}() // expected-error{{statement cannot begin with a closure}} expected-note{{explicitly discard the result of the closure}}
200+

test/stmt/if_while_var.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ if let x: B = d { }
3030
if let x {} // expected-error{{requires an initializer}}
3131

3232
// TODO poor recovery in these cases
33-
if let {} // expected-error{{expected pattern}} expected-error{{unused closure}}
33+
if let {} // expected-error{{expected pattern}} expected-error{{unused closure}} expected-error{{begin with a closure}} expected-note{{discard the result}}
3434
if let x = {} // expected-error{{'{' after 'if'}}
3535

3636
if let x = foo() {

0 commit comments

Comments
 (0)