Skip to content

Commit 3e7e923

Browse files
authored
[Parse] Reject trailing closures on literals (#7202)
`1 { }` was parsed as a call expression with a trailing closure. This made the diagnostics for `var x = 1 { get { ... } }` extremely bad. Resolves SR-3671.
1 parent 4854530 commit 3e7e923

File tree

6 files changed

+50
-19
lines changed

6 files changed

+50
-19
lines changed

lib/Parse/ParseExpr.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1581,8 +1581,14 @@ ParserResult<Expr> Parser::parseExprPostfix(Diag<> ID, bool isExprBasic) {
15811581
if (Tok.is(tok::l_brace) && isValidTrailingClosure(isExprBasic, *this)) {
15821582
// FIXME: if Result has a trailing closure, break out.
15831583

1584+
// Stop after literal expressions, which may never have trailing closures.
1585+
const auto *callee = Result.get();
1586+
if (isa<LiteralExpr>(callee) || isa<CollectionExpr>(callee) ||
1587+
isa<TupleExpr>(callee))
1588+
break;
1589+
15841590
ParserResult<Expr> closure =
1585-
parseTrailingClosure(Result.get()->getSourceRange());
1591+
parseTrailingClosure(callee->getSourceRange());
15861592
if (closure.isNull()) return nullptr;
15871593

15881594
// Trailing closure implicitly forms a call.

test/Constraints/closures.swift

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,19 +64,21 @@ func test13811882() {
6464

6565

6666
// <rdar://problem/21544303> QoI: "Unexpected trailing closure" should have a fixit to insert a 'do' statement
67+
// <https://bugs.swift.org/browse/SR-3671>
6768
func r21544303() {
68-
var inSubcall = true
69+
let val = true
70+
var inSubcall = val
6971
{ // expected-error {{expected 'do' keyword to designate a block of statements}} {{3-3=do }}
7072
}
7173
inSubcall = false
7274

7375
// This is a problem, but isn't clear what was intended.
74-
var somethingElse = true { // expected-error {{cannot call value of non-function type 'Bool'}}
76+
var somethingElse = val { // expected-error {{cannot call value of non-function type 'Bool'}}
7577
}
7678
inSubcall = false
7779

7880
var v2 : Bool = false
79-
v2 = true
81+
v2 = val
8082
{ // expected-error {{expected 'do' keyword to designate a block of statements}}
8183
}
8284
}

test/Parse/recovery.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ func missingControllingExprInIf() {
9191
if { true } { // expected-error {{missing condition in an 'if' statement}} expected-error {{braced block of statements is an unused closure}} expected-error{{expression resolves to an unused function}} expected-error{{consecutive statements on a line must be separated by ';'}} {{14-14=;}} expected-warning {{boolean literal is unused}}
9292
}
9393

94-
if { true }() { // expected-error {{missing condition in an 'if' statement}} expected-error{{consecutive statements on a line must be separated by ';'}} {{14-14=;}} expected-error{{cannot call value of non-function type '()'}} expected-warning {{boolean literal is unused}}
94+
if { true }() { // expected-error {{missing condition in an 'if' statement}} expected-error {{braced block of statements is an unused closure}} expected-error 2 {{consecutive statements on a line must be separated by ';'}} expected-error {{expression resolves to an unused function}} expected-warning {{boolean literal is unused}}
9595
}
9696

9797
// <rdar://problem/18940198>
@@ -113,7 +113,7 @@ func missingControllingExprInWhile() {
113113
while { true } { // expected-error {{missing condition in a 'while' statement}} expected-error {{braced block of statements is an unused closure}} expected-error{{expression resolves to an unused function}} expected-error{{consecutive statements on a line must be separated by ';'}} {{17-17=;}} expected-warning {{boolean literal is unused}}
114114
}
115115

116-
while { true }() { // expected-error {{missing condition in a 'while' statement}} expected-error{{consecutive statements on a line must be separated by ';'}} {{17-17=;}} expected-error{{cannot call value of non-function type '()'}} expected-warning {{boolean literal is unused}}
116+
while { true }() { // expected-error {{missing condition in a 'while' statement}} expected-error {{braced block of statements is an unused closure}} expected-error 2 {{consecutive statements on a line must be separated by ';'}} expected-error {{expression resolves to an unused function}} expected-warning {{boolean literal is unused}}
117117
}
118118

119119
// <rdar://problem/18940198>
@@ -223,7 +223,7 @@ func missingControllingExprInSwitch() {
223223
case _: return // expected-error{{'case' label can only appear inside a 'switch' statement}}
224224
}
225225

226-
switch { 42 }() { // expected-error {{expected expression in 'switch' statement}} expected-error {{all statements inside a switch must be covered by a 'case' or 'default'}} expected-error {{consecutive statements on a line must be separated by ';'}} {{16-16=;}} expected-error {{cannot call value of non-function type '()'}}
226+
switch { 42 }() { // expected-error {{expected expression in 'switch' statement}} expected-error {{all statements inside a switch must be covered by a 'case' or 'default'}} expected-error {{braced block of statements is an unused closure}} expected-error 2 {{consecutive statements on a line must be separated by ';'}} expected-error {{expression resolves to an unused function}}
227227
case _: return // expected-error{{'case' label can only appear inside a 'switch' statement}}
228228
}
229229
}

test/Sema/immutability.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ let bad_property_1: Int { // expected-error {{'let' declarations cannot be co
77
return 42
88
}
99
}
10-
let bad_property_2: Int = 0 {
11-
get { // expected-error {{use of unresolved identifier 'get'}}
10+
let bad_property_2: Int = 0 { // expected-error {{'let' declarations cannot be computed properties}} expected-error {{variable with getter/setter cannot have an initial value}}
11+
get {
1212
return 42
1313
}
1414
}

test/decl/var/properties.swift

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -120,20 +120,19 @@ var x15: Int {
120120

121121
// Disambiguated as stored property with a trailing closure in the initializer.
122122
//
123-
// FIXME: QoI could be much better here.
124-
var disambiguateGetSet1a: Int = 0 {
125-
get {} // expected-error {{use of unresolved identifier 'get'}}
123+
var disambiguateGetSet1a: Int = 0 { // expected-error {{variable with getter/setter cannot have an initial value}}
124+
get {}
126125
}
127-
var disambiguateGetSet1b: Int = 0 {
128-
get { // expected-error {{use of unresolved identifier 'get'}}
126+
var disambiguateGetSet1b: Int = 0 { // expected-error {{variable with getter/setter cannot have an initial value}}
127+
get {
129128
return 42
130129
}
131130
}
132-
var disambiguateGetSet1c: Int = 0 {
133-
set {} // expected-error {{use of unresolved identifier 'set'}}
131+
var disambiguateGetSet1c: Int = 0 { // expected-error {{variable with getter/setter cannot have an initial value}}
132+
set {} // expected-error {{variable with a setter must also have a getter}}
134133
}
135-
var disambiguateGetSet1d: Int = 0 {
136-
set(newValue) {} // expected-error {{use of unresolved identifier 'set'}} expected-error {{use of unresolved identifier 'newValue'}}
134+
var disambiguateGetSet1d: Int = 0 { // expected-error {{variable with getter/setter cannot have an initial value}}
135+
set(newValue) {} // expected-error {{variable with a setter must also have a getter}}
137136
}
138137

139138
// Disambiguated as stored property with a trailing closure in the initializer.
@@ -199,7 +198,7 @@ func disambiguateGetSet4Attr() {
199198
}
200199

201200
// Disambiguated as stored property with a trailing closure in the initializer.
202-
var disambiguateImplicitGet1: Int = 0 { // expected-error {{cannot call value of non-function type 'Int'}}
201+
var disambiguateImplicitGet1: Int = 0 { // expected-error {{variable with getter/setter cannot have an initial value}}
203202
return 42
204203
}
205204
var disambiguateImplicitGet2: Int = takeIntTrailingClosure {

test/expr/closure/trailing.swift

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,30 @@ func notPostfix() {
3737
_ = 1 + takeFunc { $0 }
3838
}
3939

40+
func notLiterals() {
41+
struct SR3671 { // <https://bugs.swift.org/browse/SR-3671>
42+
var v: Int = 1 { // expected-error {{variable with getter/setter cannot have an initial value}}
43+
get {
44+
return self.v
45+
}
46+
}
47+
}
48+
49+
var x: Int? = nil { get { } } // expected-error {{variable with getter/setter cannot have an initial value}}
50+
_ = 1 {}
51+
// expected-error@-1 {{consecutive statements on a line must be separated by ';'}}
52+
// expected-error@-2 {{braced block of statements is an unused closure}} expected-error@-2 {{expression resolves to an unused function}}
53+
_ = "hello" {}
54+
// expected-error@-1 {{consecutive statements on a line must be separated by ';'}}
55+
// expected-error@-2 {{braced block of statements is an unused closure}} expected-error@-2 {{expression resolves to an unused function}}
56+
_ = [42] {}
57+
// expected-error@-1 {{consecutive statements on a line must be separated by ';'}}
58+
// expected-error@-2 {{braced block of statements is an unused closure}} expected-error@-2 {{expression resolves to an unused function}}
59+
_ = (6765, 10946, 17711) {}
60+
// expected-error@-1 {{consecutive statements on a line must be separated by ';'}}
61+
// expected-error@-2 {{braced block of statements is an unused closure}} expected-error@-2 {{expression resolves to an unused function}}
62+
}
63+
4064
class C {
4165
func map(_ x: (Int) -> Int) -> C { return self }
4266
func filter(_ x: (Int) -> Bool) -> C { return self }

0 commit comments

Comments
 (0)