Skip to content

Commit 980579a

Browse files
authored
Rollup merge of #99030 - rust-lang:notriddle/field-recovery, r=petrochenkov
diagnostics: error messages when struct literals fail to parse If an expression is supplied where a field is expected, the parser can become convinced that it's a shorthand field syntax when it's not. This PR addresses it by explicitly recording the permitted `:` token immediately after the identifier, and also adds a suggestion to insert the name of the field if it looks like a complex expression. Fixes #98917
2 parents 1e7d04b + 9fcb9c6 commit 980579a

File tree

5 files changed

+37
-10
lines changed

5 files changed

+37
-10
lines changed

compiler/rustc_parse/src/parser/expr.rs

+18
Original file line numberDiff line numberDiff line change
@@ -3028,6 +3028,11 @@ impl<'a> Parser<'a> {
30283028
}
30293029
};
30303030

3031+
let is_shorthand = parsed_field.as_ref().map_or(false, |f| f.is_shorthand);
3032+
// A shorthand field can be turned into a full field with `:`.
3033+
// We should point this out.
3034+
self.check_or_expected(!is_shorthand, TokenType::Token(token::Colon));
3035+
30313036
match self.expect_one_of(&[token::Comma], &[token::CloseDelim(close_delim)]) {
30323037
Ok(_) => {
30333038
if let Some(f) = parsed_field.or(recovery_field) {
@@ -3048,6 +3053,19 @@ impl<'a> Parser<'a> {
30483053
",",
30493054
Applicability::MachineApplicable,
30503055
);
3056+
} else if is_shorthand
3057+
&& (AssocOp::from_token(&self.token).is_some()
3058+
|| matches!(&self.token.kind, token::OpenDelim(_))
3059+
|| self.token.kind == token::Dot)
3060+
{
3061+
// Looks like they tried to write a shorthand, complex expression.
3062+
let ident = parsed_field.expect("is_shorthand implies Some").ident;
3063+
e.span_suggestion(
3064+
ident.span.shrink_to_lo(),
3065+
"try naming a field",
3066+
&format!("{ident}: "),
3067+
Applicability::HasPlaceholders,
3068+
);
30513069
}
30523070
}
30533071
if !recover {

src/test/ui/parser/issues/issue-52496.stderr

+4-3
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,13 @@ error: float literals must have an integer part
44
LL | let _ = Foo { bar: .5, baz: 42 };
55
| ^^ help: must have an integer part: `0.5`
66

7-
error: expected one of `,` or `}`, found `.`
7+
error: expected one of `,`, `:`, or `}`, found `.`
88
--> $DIR/issue-52496.rs:8:22
99
|
1010
LL | let _ = Foo { bar.into(), bat: -1, . };
11-
| --- ^ expected one of `,` or `}`
12-
| |
11+
| --- - ^ expected one of `,`, `:`, or `}`
12+
| | |
13+
| | help: try naming a field: `bar:`
1314
| while parsing this struct
1415

1516
error: expected identifier, found `.`

src/test/ui/parser/issues/issue-62973.stderr

+12-4
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,23 @@ LL |
2020
LL |
2121
| ^
2222

23-
error: expected one of `,` or `}`, found `{`
23+
error: expected one of `,`, `:`, or `}`, found `{`
2424
--> $DIR/issue-62973.rs:6:8
2525
|
2626
LL | fn p() { match s { v, E { [) {) }
27-
| ^ - -^ expected one of `,` or `}`
28-
| | | |
29-
| | | help: `}` may belong here
27+
| ^ - ^ expected one of `,`, `:`, or `}`
28+
| | |
3029
| | while parsing this struct
3130
| unclosed delimiter
31+
|
32+
help: `}` may belong here
33+
|
34+
LL | fn p() { match s { v, E} { [) {) }
35+
| +
36+
help: try naming a field
37+
|
38+
LL | fn p() { match s { v, E: E { [) {) }
39+
| ++
3240

3341
error: struct literals are not allowed here
3442
--> $DIR/issue-62973.rs:6:16

src/test/ui/parser/removed-syntax-with-2.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,6 @@ fn main() {
66

77
let a = S { foo: (), bar: () };
88
let b = S { foo: (), with a };
9-
//~^ ERROR expected one of `,` or `}`, found `a`
9+
//~^ ERROR expected one of `,`, `:`, or `}`, found `a`
1010
//~| ERROR missing field `bar` in initializer of `S`
1111
}

src/test/ui/parser/removed-syntax-with-2.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error: expected one of `,` or `}`, found `a`
1+
error: expected one of `,`, `:`, or `}`, found `a`
22
--> $DIR/removed-syntax-with-2.rs:8:31
33
|
44
LL | let b = S { foo: (), with a };
5-
| - ^ expected one of `,` or `}`
5+
| - ^ expected one of `,`, `:`, or `}`
66
| |
77
| while parsing this struct
88

0 commit comments

Comments
 (0)