Skip to content

Commit 2f36b54

Browse files
committed
Emit specific error for struct literal in conditions
1 parent a2bbf7d commit 2f36b54

14 files changed

+162
-207
lines changed

src/librustc_borrowck/borrowck/mod.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -897,8 +897,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
897897
self.cannot_borrow_path_as_mutable(error_span, &descr, Origin::Ast)
898898
}
899899
BorrowViolation(euv::ClosureInvocation) => {
900-
span_bug!(err.span,
901-
"err_mutbl with a closure invocation");
900+
span_bug!(err.span, "err_mutbl with a closure invocation");
902901
}
903902
};
904903

@@ -1096,7 +1095,6 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
10961095
BorrowViolation(euv::MatchDiscriminant) => {
10971096
"cannot borrow data mutably"
10981097
}
1099-
11001098
BorrowViolation(euv::ClosureInvocation) => {
11011099
is_closure = true;
11021100
"closure invocation"

src/libsyntax/parse/parser.rs

Lines changed: 52 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2855,11 +2855,13 @@ impl<'a> Parser<'a> {
28552855
let (delim, tts) = self.expect_delimited_token_tree()?;
28562856
hi = self.prev_span;
28572857
ex = ExprKind::Mac(respan(lo.to(hi), Mac_ { path, tts, delim }));
2858-
} else if self.check(&token::OpenDelim(token::Brace)) &&
2859-
!self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL) {
2860-
// This is a struct literal, unless we're prohibited
2861-
// from parsing struct literals here.
2862-
return self.parse_struct_expr(lo, path, attrs);
2858+
} else if self.check(&token::OpenDelim(token::Brace)) {
2859+
if let Some(expr) = self.should_parse_struct_expr(lo, path.clone(), attrs.clone()) {
2860+
return expr;
2861+
} else {
2862+
hi = path.span;
2863+
ex = ExprKind::Path(None, path);
2864+
}
28632865
} else {
28642866
hi = path.span;
28652867
ex = ExprKind::Path(None, path);
@@ -2902,6 +2904,51 @@ impl<'a> Parser<'a> {
29022904
self.maybe_recover_from_bad_qpath(expr, true)
29032905
}
29042906

2907+
fn should_parse_struct_expr(
2908+
&mut self,
2909+
lo: Span,
2910+
path: ast::Path,
2911+
attrs: ThinVec<Attribute>,
2912+
) -> Option<PResult<'a, P<Expr>>> {
2913+
let could_be_struct = self.look_ahead(1, |t| t.is_ident()) && (
2914+
self.look_ahead(2, |t| *t == token::Colon)
2915+
|| self.look_ahead(2, |t| *t == token::Comma)
2916+
// We could also check for `token::CloseDelim(token::Brace)`, but that would
2917+
// have false positives in the case of `if x == y { z } { a }`.
2918+
);
2919+
let mut bad_struct = false;
2920+
let mut parse_struct = !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL);
2921+
if self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL) && could_be_struct {
2922+
// This is a struct literal, but we don't can't accept them here
2923+
bad_struct = true;
2924+
parse_struct = true;
2925+
}
2926+
if parse_struct {
2927+
match self.parse_struct_expr(lo, path, attrs) {
2928+
Err(err) => return Some(Err(err)),
2929+
Ok(expr) => {
2930+
if bad_struct {
2931+
let mut err = self.diagnostic().struct_span_err(
2932+
expr.span,
2933+
"struct literals are not allowed here",
2934+
);
2935+
err.multipart_suggestion(
2936+
"surround the struct literal with parenthesis",
2937+
vec![
2938+
(lo.shrink_to_lo(), "(".to_string()),
2939+
(expr.span.shrink_to_hi(), ")".to_string()),
2940+
],
2941+
Applicability::MachineApplicable,
2942+
);
2943+
err.emit();
2944+
}
2945+
return Some(Ok(expr));
2946+
}
2947+
}
2948+
}
2949+
None
2950+
}
2951+
29052952
fn parse_struct_expr(&mut self, lo: Span, pth: ast::Path, mut attrs: ThinVec<Attribute>)
29062953
-> PResult<'a, P<Expr>> {
29072954
let struct_sp = lo.to(self.prev_span);

src/test/ui/error-codes/E0423.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,13 @@ fn bar() {
1010
struct T {}
1111

1212
if let S { x: _x, y: 2 } = S { x: 1, y: 2 } { println!("Ok"); }
13-
//~^ ERROR E0423
14-
//~| expected type, found `1`
13+
//~^ ERROR struct literals are not allowed here
1514
if T {} == T {} { println!("Ok"); }
1615
//~^ ERROR E0423
1716
//~| ERROR expected expression, found `==`
1817
}
1918

2019
fn foo() {
2120
for _ in std::ops::Range { start: 0, end: 10 } {}
22-
//~^ ERROR E0423
23-
//~| ERROR expected type, found `0`
21+
//~^ ERROR struct literals are not allowed here
2422
}

src/test/ui/error-codes/E0423.stderr

Lines changed: 15 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,28 @@
1-
error: expected type, found `1`
2-
--> $DIR/E0423.rs:12:39
1+
error: struct literals are not allowed here
2+
--> $DIR/E0423.rs:12:32
33
|
44
LL | if let S { x: _x, y: 2 } = S { x: 1, y: 2 } { println!("Ok"); }
5-
| ^ expecting a type here because of type ascription
6-
|
7-
= note: type ascription is a nightly-only feature that lets you annotate an expression with a type: `<expr>: <type>`
8-
note: this expression expects an ascribed type after the colon
9-
--> $DIR/E0423.rs:12:36
5+
| ^^^^^^^^^^^^^^^^
6+
help: surround the struct literal with parenthesis
107
|
11-
LL | if let S { x: _x, y: 2 } = S { x: 1, y: 2 } { println!("Ok"); }
12-
| ^
13-
= help: this might be indicative of a syntax error elsewhere
8+
LL | if let S { x: _x, y: 2 } = (S { x: 1, y: 2 }) { println!("Ok"); }
9+
| ^ ^
1410

1511
error: expected expression, found `==`
16-
--> $DIR/E0423.rs:15:13
12+
--> $DIR/E0423.rs:14:13
1713
|
1814
LL | if T {} == T {} { println!("Ok"); }
1915
| ^^ expected expression
2016

21-
error: expected type, found `0`
22-
--> $DIR/E0423.rs:21:39
17+
error: struct literals are not allowed here
18+
--> $DIR/E0423.rs:20:14
2319
|
2420
LL | for _ in std::ops::Range { start: 0, end: 10 } {}
25-
| ^ expecting a type here because of type ascription
21+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
22+
help: surround the struct literal with parenthesis
2623
|
27-
= note: type ascription is a nightly-only feature that lets you annotate an expression with a type: `<expr>: <type>`
28-
note: this expression expects an ascribed type after the colon
29-
--> $DIR/E0423.rs:21:32
30-
|
31-
LL | for _ in std::ops::Range { start: 0, end: 10 } {}
32-
| ^^^^^
33-
= help: this might be indicative of a syntax error elsewhere
24+
LL | for _ in (std::ops::Range { start: 0, end: 10 }) {}
25+
| ^ ^
3426

3527
error[E0423]: expected function, found struct `Foo`
3628
--> $DIR/E0423.rs:4:13
@@ -41,30 +33,14 @@ LL | let f = Foo();
4133
| did you mean `Foo { /* fields */ }`?
4234
| help: a function with a similar name exists: `foo`
4335

44-
error[E0423]: expected value, found struct `S`
45-
--> $DIR/E0423.rs:12:32
46-
|
47-
LL | if let S { x: _x, y: 2 } = S { x: 1, y: 2 } { println!("Ok"); }
48-
| ^---------------
49-
| |
50-
| help: surround the struct literal with parenthesis: `(S { x: 1, y: 2 })`
51-
5236
error[E0423]: expected value, found struct `T`
53-
--> $DIR/E0423.rs:15:8
37+
--> $DIR/E0423.rs:14:8
5438
|
5539
LL | if T {} == T {} { println!("Ok"); }
5640
| ^---
5741
| |
5842
| help: surround the struct literal with parenthesis: `(T {})`
5943

60-
error[E0423]: expected value, found struct `std::ops::Range`
61-
--> $DIR/E0423.rs:21:14
62-
|
63-
LL | for _ in std::ops::Range { start: 0, end: 10 } {}
64-
| ^^^^^^^^^^^^^^^----------------------
65-
| |
66-
| help: surround the struct literal with parenthesis: `(std::ops::Range { start: 0, end: 10 })`
67-
68-
error: aborting due to 7 previous errors
44+
error: aborting due to 5 previous errors
6945

7046
For more information about this error, try `rustc --explain E0423`.

src/test/ui/parser/struct-literal-in-for.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ impl Foo {
99
}
1010

1111
fn main() {
12-
for x in Foo { //~ ERROR expected value, found struct `Foo`
13-
x: 3 //~ ERROR expected type, found `3`
14-
}.hi() { //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `{`
12+
for x in Foo { //~ ERROR struct literals are not allowed here
13+
x: 3 //~^ ERROR `bool` is not an iterator
14+
}.hi() {
1515
println!("yo");
1616
}
1717
}
Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,30 @@
1-
error: expected type, found `3`
2-
--> $DIR/struct-literal-in-for.rs:13:12
3-
|
4-
LL | x: 3
5-
| ^ expecting a type here because of type ascription
1+
error: struct literals are not allowed here
2+
--> $DIR/struct-literal-in-for.rs:12:14
63
|
7-
= note: type ascription is a nightly-only feature that lets you annotate an expression with a type: `<expr>: <type>`
8-
note: this expression expects an ascribed type after the colon
9-
--> $DIR/struct-literal-in-for.rs:13:9
4+
LL | for x in Foo {
5+
| ______________^
6+
LL | | x: 3
7+
LL | | }.hi() {
8+
| |_____^
9+
help: surround the struct literal with parenthesis
1010
|
11+
LL | for x in (Foo {
1112
LL | x: 3
12-
| ^
13-
= help: this might be indicative of a syntax error elsewhere
14-
15-
error: expected one of `.`, `;`, `?`, `}`, or an operator, found `{`
16-
--> $DIR/struct-literal-in-for.rs:14:12
13+
LL | }).hi() {
1714
|
18-
LL | }.hi() {
19-
| ^ expected one of `.`, `;`, `?`, `}`, or an operator here
2015

21-
error[E0423]: expected value, found struct `Foo`
16+
error[E0277]: `bool` is not an iterator
2217
--> $DIR/struct-literal-in-for.rs:12:14
2318
|
24-
LL | for x in Foo {
25-
| ^^^ did you mean `(Foo { /* fields */ })`?
19+
LL | for x in Foo {
20+
| ______________^
21+
LL | | x: 3
22+
LL | | }.hi() {
23+
| |__________^ `bool` is not an iterator
24+
|
25+
= help: the trait `std::iter::Iterator` is not implemented for `bool`
26+
= note: required by `std::iter::IntoIterator::into_iter`
2627

27-
error: aborting due to 3 previous errors
28+
error: aborting due to 2 previous errors
2829

29-
For more information about this error, try `rustc --explain E0423`.
30+
For more information about this error, try `rustc --explain E0277`.

src/test/ui/parser/struct-literal-in-if.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ impl Foo {
99
}
1010

1111
fn main() {
12-
if Foo { //~ ERROR expected value, found struct `Foo`
13-
x: 3 //~ ERROR expected type, found `3`
14-
}.hi() { //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `{`
12+
if Foo { //~ ERROR struct literals are not allowed here
13+
x: 3
14+
}.hi() {
1515
println!("yo");
1616
}
1717
}
Lines changed: 11 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,17 @@
1-
error: expected type, found `3`
2-
--> $DIR/struct-literal-in-if.rs:13:12
3-
|
4-
LL | x: 3
5-
| ^ expecting a type here because of type ascription
1+
error: struct literals are not allowed here
2+
--> $DIR/struct-literal-in-if.rs:12:8
63
|
7-
= note: type ascription is a nightly-only feature that lets you annotate an expression with a type: `<expr>: <type>`
8-
note: this expression expects an ascribed type after the colon
9-
--> $DIR/struct-literal-in-if.rs:13:9
4+
LL | if Foo {
5+
| ________^
6+
LL | | x: 3
7+
LL | | }.hi() {
8+
| |_____^
9+
help: surround the struct literal with parenthesis
1010
|
11+
LL | if (Foo {
1112
LL | x: 3
12-
| ^
13-
= help: this might be indicative of a syntax error elsewhere
14-
15-
error: expected one of `.`, `;`, `?`, `}`, or an operator, found `{`
16-
--> $DIR/struct-literal-in-if.rs:14:12
17-
|
18-
LL | }.hi() {
19-
| ^ expected one of `.`, `;`, `?`, `}`, or an operator here
20-
21-
error[E0423]: expected value, found struct `Foo`
22-
--> $DIR/struct-literal-in-if.rs:12:8
13+
LL | }).hi() {
2314
|
24-
LL | if Foo {
25-
| ^^^ did you mean `(Foo { /* fields */ })`?
2615

27-
error: aborting due to 3 previous errors
16+
error: aborting due to previous error
2817

29-
For more information about this error, try `rustc --explain E0423`.

src/test/ui/parser/struct-literal-in-match-discriminant.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@ struct Foo {
33
}
44

55
fn main() {
6-
match Foo { //~ ERROR expected value, found struct `Foo`
7-
x: 3 //~ ERROR expected one of `=>`, `@`, `if`, or `|`, found `:`
6+
match Foo { //~ ERROR struct literals are not allowed here
7+
x: 3
88
} {
9-
Foo { //~ ERROR mismatched types
10-
x: x //~ ERROR cannot find value `x` in this scope
11-
} => {} //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `=>`
9+
Foo {
10+
x: x
11+
} => {}
1212
}
1313
}
Lines changed: 11 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,16 @@
1-
error: expected one of `=>`, `@`, `if`, or `|`, found `:`
2-
--> $DIR/struct-literal-in-match-discriminant.rs:7:10
3-
|
4-
LL | x: 3
5-
| ^ expected one of `=>`, `@`, `if`, or `|` here
6-
7-
error: expected one of `.`, `;`, `?`, `}`, or an operator, found `=>`
8-
--> $DIR/struct-literal-in-match-discriminant.rs:11:11
9-
|
10-
LL | } => {}
11-
| ^^ expected one of `.`, `;`, `?`, `}`, or an operator here
12-
13-
error[E0423]: expected value, found struct `Foo`
1+
error: struct literals are not allowed here
142
--> $DIR/struct-literal-in-match-discriminant.rs:6:11
153
|
16-
LL | match Foo {
17-
| ^^^ did you mean `(Foo { /* fields */ })`?
18-
19-
error[E0425]: cannot find value `x` in this scope
20-
--> $DIR/struct-literal-in-match-discriminant.rs:10:16
21-
|
22-
LL | x: x
23-
| ^ not found in this scope
24-
25-
error[E0308]: mismatched types
26-
--> $DIR/struct-literal-in-match-discriminant.rs:9:9
4+
LL | match Foo {
5+
| ___________^
6+
LL | | x: 3
7+
LL | | } {
8+
| |_____^
9+
help: surround the struct literal with parenthesis
2710
|
28-
LL | fn main() {
29-
| - expected `()` because of default return type
30-
...
31-
LL | / Foo {
32-
LL | | x: x
33-
LL | | } => {}
34-
| |_________^ expected (), found struct `Foo`
11+
LL | match (Foo {
12+
LL | x: 3
13+
LL | }) {
3514
|
36-
= note: expected type `()`
37-
found type `Foo`
38-
39-
error: aborting due to 5 previous errors
4015

41-
Some errors have detailed explanations: E0308, E0423, E0425.
42-
For more information about an error, try `rustc --explain E0308`.
16+
error: aborting due to previous error

src/test/ui/parser/struct-literal-in-while.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,9 @@ impl Foo {
99
}
1010

1111
fn main() {
12-
while Foo { //~ ERROR expected value, found struct `Foo`
13-
x: 3 //~ ERROR expected type, found `3`
14-
}.hi() { //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `{`
15-
//~| ERROR no method named `hi` found for type `()` in the current scope
12+
while Foo { //~ ERROR struct literals are not allowed here
13+
x: 3
14+
}.hi() {
1615
println!("yo");
1716
}
1817
}

0 commit comments

Comments
 (0)