Skip to content

Commit 377cf44

Browse files
committed
Suggest braces when a struct literal needs them
When writing a struct literal in an expression that expects a block to be started afterwards (like an `if` statement), do not suggest using the same struct literal: ``` did you mean `S { /* fields * /}`? ``` Instead, suggest surrounding the expression with parentheses: ``` did you mean `(S { /* fields * /})`? ```
1 parent 41affd0 commit 377cf44

File tree

3 files changed

+92
-4
lines changed

3 files changed

+92
-4
lines changed

src/librustc_resolve/lib.rs

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2934,8 +2934,38 @@ impl<'a> Resolver<'a> {
29342934
here due to private fields"));
29352935
}
29362936
} else {
2937-
err.span_label(span, format!("did you mean `{} {{ /* fields */ }}`?",
2938-
path_str));
2937+
// HACK(estebank): find a better way to figure out that this was a
2938+
// parser issue where a struct literal is being used on an expression
2939+
// where a brace being opened means a block is being started. Look
2940+
// ahead for the next text to see if `span` is followed by a `{`.
2941+
let cm = this.session.codemap();
2942+
let mut sp = span;
2943+
loop {
2944+
sp = cm.next_point(sp);
2945+
match cm.span_to_snippet(sp) {
2946+
Ok(ref snippet) => {
2947+
if snippet.chars().any(|c| { !c.is_whitespace() }) {
2948+
break;
2949+
}
2950+
}
2951+
_ => break,
2952+
}
2953+
}
2954+
let followed_by_brace = match cm.span_to_snippet(sp) {
2955+
Ok(ref snippet) if snippet == "{" => true,
2956+
_ => false,
2957+
};
2958+
if let (PathSource::Expr(None), true) = (source, followed_by_brace) {
2959+
err.span_label(
2960+
span,
2961+
format!("did you mean `({} {{ /* fields */ }})`?", path_str),
2962+
);
2963+
} else {
2964+
err.span_label(
2965+
span,
2966+
format!("did you mean `{} {{ /* fields */ }}`?", path_str),
2967+
);
2968+
}
29392969
}
29402970
return (err, candidates);
29412971
}

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

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,22 @@ fn main () {
1313

1414
let f = Foo(); //~ ERROR E0423
1515
}
16+
17+
fn bar() {
18+
struct S { x: i32, y: i32 }
19+
#[derive(PartialEq)]
20+
struct T {}
21+
22+
if let S { x: _x, y: 2 } = S { x: 1, y: 2 } { println!("Ok"); }
23+
//~^ ERROR E0423
24+
//~| expected type, found `1`
25+
if T {} == T {} { println!("Ok"); }
26+
//~^ ERROR E0423
27+
//~| ERROR expected expression, found `==`
28+
}
29+
30+
fn foo() {
31+
for _ in std::ops::Range { start: 0, end: 10 } {}
32+
//~^ ERROR E0423
33+
//~| ERROR expected type, found `0`
34+
}

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

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,48 @@
1+
error: expected type, found `1`
2+
--> $DIR/E0423.rs:22:39
3+
|
4+
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+
error: expected expression, found `==`
8+
--> $DIR/E0423.rs:25:13
9+
|
10+
LL | if T {} == T {} { println!("Ok"); }
11+
| ^^ expected expression
12+
13+
error: expected type, found `0`
14+
--> $DIR/E0423.rs:31:39
15+
|
16+
LL | for _ in std::ops::Range { start: 0, end: 10 } {}
17+
| ^ expecting a type here because of type ascription
18+
119
error[E0423]: expected function, found struct `Foo`
220
--> $DIR/E0423.rs:14:13
321
|
422
LL | let f = Foo(); //~ ERROR E0423
5-
| ^^^ did you mean `Foo { /* fields */ }`?
23+
| ^^^
24+
| |
25+
| did you mean `foo`?
26+
| did you mean `Foo { /* fields */ }`?
27+
28+
error[E0423]: expected value, found struct `S`
29+
--> $DIR/E0423.rs:22:32
30+
|
31+
LL | if let S { x: _x, y: 2 } = S { x: 1, y: 2 } { println!("Ok"); }
32+
| ^ did you mean `(S { /* fields */ })`?
33+
34+
error[E0423]: expected value, found struct `T`
35+
--> $DIR/E0423.rs:25:8
36+
|
37+
LL | if T {} == T {} { println!("Ok"); }
38+
| ^ did you mean `(T { /* fields */ })`?
39+
40+
error[E0423]: expected value, found struct `std::ops::Range`
41+
--> $DIR/E0423.rs:31:14
42+
|
43+
LL | for _ in std::ops::Range { start: 0, end: 10 } {}
44+
| ^^^^^^^^^^^^^^^ did you mean `(std::ops::Range { /* fields */ })`?
645

7-
error: aborting due to previous error
46+
error: aborting due to 7 previous errors
847

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

0 commit comments

Comments
 (0)