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
This commit is contained in:
commit
980579a5e9
5 changed files with 37 additions and 10 deletions
|
@ -3028,6 +3028,11 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let is_shorthand = parsed_field.as_ref().map_or(false, |f| f.is_shorthand);
|
||||||
|
// A shorthand field can be turned into a full field with `:`.
|
||||||
|
// We should point this out.
|
||||||
|
self.check_or_expected(!is_shorthand, TokenType::Token(token::Colon));
|
||||||
|
|
||||||
match self.expect_one_of(&[token::Comma], &[token::CloseDelim(close_delim)]) {
|
match self.expect_one_of(&[token::Comma], &[token::CloseDelim(close_delim)]) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
if let Some(f) = parsed_field.or(recovery_field) {
|
if let Some(f) = parsed_field.or(recovery_field) {
|
||||||
|
@ -3048,6 +3053,19 @@ impl<'a> Parser<'a> {
|
||||||
",",
|
",",
|
||||||
Applicability::MachineApplicable,
|
Applicability::MachineApplicable,
|
||||||
);
|
);
|
||||||
|
} else if is_shorthand
|
||||||
|
&& (AssocOp::from_token(&self.token).is_some()
|
||||||
|
|| matches!(&self.token.kind, token::OpenDelim(_))
|
||||||
|
|| self.token.kind == token::Dot)
|
||||||
|
{
|
||||||
|
// Looks like they tried to write a shorthand, complex expression.
|
||||||
|
let ident = parsed_field.expect("is_shorthand implies Some").ident;
|
||||||
|
e.span_suggestion(
|
||||||
|
ident.span.shrink_to_lo(),
|
||||||
|
"try naming a field",
|
||||||
|
&format!("{ident}: "),
|
||||||
|
Applicability::HasPlaceholders,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !recover {
|
if !recover {
|
||||||
|
|
|
@ -4,12 +4,13 @@ error: float literals must have an integer part
|
||||||
LL | let _ = Foo { bar: .5, baz: 42 };
|
LL | let _ = Foo { bar: .5, baz: 42 };
|
||||||
| ^^ help: must have an integer part: `0.5`
|
| ^^ help: must have an integer part: `0.5`
|
||||||
|
|
||||||
error: expected one of `,` or `}`, found `.`
|
error: expected one of `,`, `:`, or `}`, found `.`
|
||||||
--> $DIR/issue-52496.rs:8:22
|
--> $DIR/issue-52496.rs:8:22
|
||||||
|
|
|
|
||||||
LL | let _ = Foo { bar.into(), bat: -1, . };
|
LL | let _ = Foo { bar.into(), bat: -1, . };
|
||||||
| --- ^ expected one of `,` or `}`
|
| --- - ^ expected one of `,`, `:`, or `}`
|
||||||
| |
|
| | |
|
||||||
|
| | help: try naming a field: `bar:`
|
||||||
| while parsing this struct
|
| while parsing this struct
|
||||||
|
|
||||||
error: expected identifier, found `.`
|
error: expected identifier, found `.`
|
||||||
|
|
|
@ -20,15 +20,23 @@ LL |
|
||||||
LL |
|
LL |
|
||||||
| ^
|
| ^
|
||||||
|
|
||||||
error: expected one of `,` or `}`, found `{`
|
error: expected one of `,`, `:`, or `}`, found `{`
|
||||||
--> $DIR/issue-62973.rs:6:8
|
--> $DIR/issue-62973.rs:6:8
|
||||||
|
|
|
|
||||||
LL | fn p() { match s { v, E { [) {) }
|
LL | fn p() { match s { v, E { [) {) }
|
||||||
| ^ - -^ expected one of `,` or `}`
|
| ^ - ^ expected one of `,`, `:`, or `}`
|
||||||
| | | |
|
| | |
|
||||||
| | | help: `}` may belong here
|
|
||||||
| | while parsing this struct
|
| | while parsing this struct
|
||||||
| unclosed delimiter
|
| unclosed delimiter
|
||||||
|
|
|
||||||
|
help: `}` may belong here
|
||||||
|
|
|
||||||
|
LL | fn p() { match s { v, E} { [) {) }
|
||||||
|
| +
|
||||||
|
help: try naming a field
|
||||||
|
|
|
||||||
|
LL | fn p() { match s { v, E: E { [) {) }
|
||||||
|
| ++
|
||||||
|
|
||||||
error: struct literals are not allowed here
|
error: struct literals are not allowed here
|
||||||
--> $DIR/issue-62973.rs:6:16
|
--> $DIR/issue-62973.rs:6:16
|
||||||
|
|
|
@ -6,6 +6,6 @@ fn main() {
|
||||||
|
|
||||||
let a = S { foo: (), bar: () };
|
let a = S { foo: (), bar: () };
|
||||||
let b = S { foo: (), with a };
|
let b = S { foo: (), with a };
|
||||||
//~^ ERROR expected one of `,` or `}`, found `a`
|
//~^ ERROR expected one of `,`, `:`, or `}`, found `a`
|
||||||
//~| ERROR missing field `bar` in initializer of `S`
|
//~| ERROR missing field `bar` in initializer of `S`
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
error: expected one of `,` or `}`, found `a`
|
error: expected one of `,`, `:`, or `}`, found `a`
|
||||||
--> $DIR/removed-syntax-with-2.rs:8:31
|
--> $DIR/removed-syntax-with-2.rs:8:31
|
||||||
|
|
|
|
||||||
LL | let b = S { foo: (), with a };
|
LL | let b = S { foo: (), with a };
|
||||||
| - ^ expected one of `,` or `}`
|
| - ^ expected one of `,`, `:`, or `}`
|
||||||
| |
|
| |
|
||||||
| while parsing this struct
|
| while parsing this struct
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue