Skip to content

Commit

Permalink
Suggest braces when a struct literal needs them
Browse files Browse the repository at this point in the history
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 * /})`?
```
  • Loading branch information
estebank committed Jun 5, 2018
1 parent 41affd0 commit 377cf44
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 4 deletions.
34 changes: 32 additions & 2 deletions src/librustc_resolve/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2934,8 +2934,38 @@ impl<'a> Resolver<'a> {
here due to private fields"));
}
} else {
err.span_label(span, format!("did you mean `{} {{ /* fields */ }}`?",
path_str));
// HACK(estebank): find a better way to figure out that this was a
// parser issue where a struct literal is being used on an expression
// where a brace being opened means a block is being started. Look
// ahead for the next text to see if `span` is followed by a `{`.
let cm = this.session.codemap();
let mut sp = span;
loop {
sp = cm.next_point(sp);
match cm.span_to_snippet(sp) {
Ok(ref snippet) => {
if snippet.chars().any(|c| { !c.is_whitespace() }) {
break;
}
}
_ => break,
}
}
let followed_by_brace = match cm.span_to_snippet(sp) {
Ok(ref snippet) if snippet == "{" => true,
_ => false,
};
if let (PathSource::Expr(None), true) = (source, followed_by_brace) {
err.span_label(
span,
format!("did you mean `({} {{ /* fields */ }})`?", path_str),
);
} else {
err.span_label(
span,
format!("did you mean `{} {{ /* fields */ }}`?", path_str),
);
}
}
return (err, candidates);
}
Expand Down
19 changes: 19 additions & 0 deletions src/test/ui/error-codes/E0423.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,22 @@ fn main () {

let f = Foo(); //~ ERROR E0423
}

fn bar() {
struct S { x: i32, y: i32 }
#[derive(PartialEq)]
struct T {}

if let S { x: _x, y: 2 } = S { x: 1, y: 2 } { println!("Ok"); }
//~^ ERROR E0423
//~| expected type, found `1`
if T {} == T {} { println!("Ok"); }
//~^ ERROR E0423
//~| ERROR expected expression, found `==`
}

fn foo() {
for _ in std::ops::Range { start: 0, end: 10 } {}
//~^ ERROR E0423
//~| ERROR expected type, found `0`
}
43 changes: 41 additions & 2 deletions src/test/ui/error-codes/E0423.stderr
Original file line number Diff line number Diff line change
@@ -1,9 +1,48 @@
error: expected type, found `1`
--> $DIR/E0423.rs:22:39
|
LL | if let S { x: _x, y: 2 } = S { x: 1, y: 2 } { println!("Ok"); }
| ^ expecting a type here because of type ascription

error: expected expression, found `==`
--> $DIR/E0423.rs:25:13
|
LL | if T {} == T {} { println!("Ok"); }
| ^^ expected expression

error: expected type, found `0`
--> $DIR/E0423.rs:31:39
|
LL | for _ in std::ops::Range { start: 0, end: 10 } {}
| ^ expecting a type here because of type ascription

error[E0423]: expected function, found struct `Foo`
--> $DIR/E0423.rs:14:13
|
LL | let f = Foo(); //~ ERROR E0423
| ^^^ did you mean `Foo { /* fields */ }`?
| ^^^
| |
| did you mean `foo`?
| did you mean `Foo { /* fields */ }`?

error[E0423]: expected value, found struct `S`
--> $DIR/E0423.rs:22:32
|
LL | if let S { x: _x, y: 2 } = S { x: 1, y: 2 } { println!("Ok"); }
| ^ did you mean `(S { /* fields */ })`?

error[E0423]: expected value, found struct `T`
--> $DIR/E0423.rs:25:8
|
LL | if T {} == T {} { println!("Ok"); }
| ^ did you mean `(T { /* fields */ })`?

error[E0423]: expected value, found struct `std::ops::Range`
--> $DIR/E0423.rs:31:14
|
LL | for _ in std::ops::Range { start: 0, end: 10 } {}
| ^^^^^^^^^^^^^^^ did you mean `(std::ops::Range { /* fields */ })`?

error: aborting due to previous error
error: aborting due to 7 previous errors

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

0 comments on commit 377cf44

Please sign in to comment.