Rollup merge of #51360 - estebank:braces-around-literal-structs, r=nikomatsakis

Suggest parentheses 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 * /})`?
```

Fix #47360, #50090. Leaving #42982 open to come back to this problem with a better solution.
This commit is contained in:
Mark Rousskov 2018-06-08 17:21:00 -06:00 committed by GitHub
commit 4b176b2ce2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 92 additions and 4 deletions

View File

@ -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);
}

View File

@ -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`
}

View File

@ -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: aborting due to previous error
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 7 previous errors
For more information about this error, try `rustc --explain E0423`.