Rollup merge of #112199 - jieyouxu:issue-112188, r=compiler-errors
Fix suggestion for matching struct with `..` on both ends ### Before This PR ``` error: expected `}`, found `,` --> src\main.rs:8:17 | 8 | Foo { .., x, .. } => (), | --^ | | | | | expected `}` | `..` must be at the end and cannot have a trailing comma | help: move the `..` to the end of the field list | 8 - Foo { .., x, .. } => (), 8 + Foo { .., x, , .. } => (), | ``` ### After This PR ``` error: expected `}`, found `,` --> tests/ui/parser/issue-112188.rs:11:17 | 11 | let Foo { .., x, .. } = f; //~ ERROR expected `}`, found `,` | --^- | | | | | expected `}` | `..` must be at the end and cannot have a trailing comma | help: remove the starting `..` ``` Fixes #112188.
This commit is contained in:
commit
71a72ee34a
@ -938,7 +938,8 @@ impl<'a> Parser<'a> {
|
|||||||
let mut etc = false;
|
let mut etc = false;
|
||||||
let mut ate_comma = true;
|
let mut ate_comma = true;
|
||||||
let mut delayed_err: Option<DiagnosticBuilder<'a, ErrorGuaranteed>> = None;
|
let mut delayed_err: Option<DiagnosticBuilder<'a, ErrorGuaranteed>> = None;
|
||||||
let mut etc_span = None;
|
let mut first_etc_and_maybe_comma_span = None;
|
||||||
|
let mut last_non_comma_dotdot_span = None;
|
||||||
|
|
||||||
while self.token != token::CloseDelim(Delimiter::Brace) {
|
while self.token != token::CloseDelim(Delimiter::Brace) {
|
||||||
let attrs = match self.parse_outer_attributes() {
|
let attrs = match self.parse_outer_attributes() {
|
||||||
@ -969,12 +970,27 @@ impl<'a> Parser<'a> {
|
|||||||
{
|
{
|
||||||
etc = true;
|
etc = true;
|
||||||
let mut etc_sp = self.token.span;
|
let mut etc_sp = self.token.span;
|
||||||
|
if first_etc_and_maybe_comma_span.is_none() {
|
||||||
|
if let Some(comma_tok) = self
|
||||||
|
.look_ahead(1, |t| if *t == token::Comma { Some(t.clone()) } else { None })
|
||||||
|
{
|
||||||
|
let nw_span = self
|
||||||
|
.sess
|
||||||
|
.source_map()
|
||||||
|
.span_extend_to_line(comma_tok.span)
|
||||||
|
.trim_start(comma_tok.span.shrink_to_lo())
|
||||||
|
.map(|s| self.sess.source_map().span_until_non_whitespace(s));
|
||||||
|
first_etc_and_maybe_comma_span = nw_span.map(|s| etc_sp.to(s));
|
||||||
|
} else {
|
||||||
|
first_etc_and_maybe_comma_span =
|
||||||
|
Some(self.sess.source_map().span_until_non_whitespace(etc_sp));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
self.recover_bad_dot_dot();
|
self.recover_bad_dot_dot();
|
||||||
self.bump(); // `..` || `...` || `_`
|
self.bump(); // `..` || `...` || `_`
|
||||||
|
|
||||||
if self.token == token::CloseDelim(Delimiter::Brace) {
|
if self.token == token::CloseDelim(Delimiter::Brace) {
|
||||||
etc_span = Some(etc_sp);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
let token_str = super::token_descr(&self.token);
|
let token_str = super::token_descr(&self.token);
|
||||||
@ -996,7 +1012,6 @@ impl<'a> Parser<'a> {
|
|||||||
ate_comma = true;
|
ate_comma = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
etc_span = Some(etc_sp.until(self.token.span));
|
|
||||||
if self.token == token::CloseDelim(Delimiter::Brace) {
|
if self.token == token::CloseDelim(Delimiter::Brace) {
|
||||||
// If the struct looks otherwise well formed, recover and continue.
|
// If the struct looks otherwise well formed, recover and continue.
|
||||||
if let Some(sp) = comma_sp {
|
if let Some(sp) = comma_sp {
|
||||||
@ -1040,6 +1055,9 @@ impl<'a> Parser<'a> {
|
|||||||
}
|
}
|
||||||
}?;
|
}?;
|
||||||
ate_comma = this.eat(&token::Comma);
|
ate_comma = this.eat(&token::Comma);
|
||||||
|
|
||||||
|
last_non_comma_dotdot_span = Some(this.prev_token.span);
|
||||||
|
|
||||||
// We just ate a comma, so there's no need to use
|
// We just ate a comma, so there's no need to use
|
||||||
// `TrailingToken::Comma`
|
// `TrailingToken::Comma`
|
||||||
Ok((field, TrailingToken::None))
|
Ok((field, TrailingToken::None))
|
||||||
@ -1049,15 +1067,30 @@ impl<'a> Parser<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(mut err) = delayed_err {
|
if let Some(mut err) = delayed_err {
|
||||||
if let Some(etc_span) = etc_span {
|
if let Some(first_etc_span) = first_etc_and_maybe_comma_span {
|
||||||
err.multipart_suggestion(
|
if self.prev_token == token::DotDot {
|
||||||
"move the `..` to the end of the field list",
|
// We have `.., x, ..`.
|
||||||
vec![
|
err.multipart_suggestion(
|
||||||
(etc_span, String::new()),
|
"remove the starting `..`",
|
||||||
(self.token.span, format!("{}.. }}", if ate_comma { "" } else { ", " })),
|
vec![(first_etc_span, String::new())],
|
||||||
],
|
Applicability::MachineApplicable,
|
||||||
Applicability::MachineApplicable,
|
);
|
||||||
);
|
} else {
|
||||||
|
if let Some(last_non_comma_dotdot_span) = last_non_comma_dotdot_span {
|
||||||
|
// We have `.., x`.
|
||||||
|
err.multipart_suggestion(
|
||||||
|
"move the `..` to the end of the field list",
|
||||||
|
vec![
|
||||||
|
(first_etc_span, String::new()),
|
||||||
|
(
|
||||||
|
self.token.span.to(last_non_comma_dotdot_span.shrink_to_hi()),
|
||||||
|
format!("{} .. }}", if ate_comma { "" } else { "," }),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
err.emit();
|
err.emit();
|
||||||
}
|
}
|
||||||
|
14
tests/ui/parser/issue-112188.fixed
Normal file
14
tests/ui/parser/issue-112188.fixed
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
// run-rustfix
|
||||||
|
|
||||||
|
#![allow(unused)]
|
||||||
|
|
||||||
|
struct Foo { x: i32 }
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let f = Foo { x: 0 };
|
||||||
|
let Foo { .. } = f;
|
||||||
|
let Foo { .. } = f; //~ ERROR expected `}`, found `,`
|
||||||
|
let Foo { x, .. } = f;
|
||||||
|
let Foo { x, .. } = f; //~ ERROR expected `}`, found `,`
|
||||||
|
let Foo { x, .. } = f; //~ ERROR expected `}`, found `,`
|
||||||
|
}
|
14
tests/ui/parser/issue-112188.rs
Normal file
14
tests/ui/parser/issue-112188.rs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
// run-rustfix
|
||||||
|
|
||||||
|
#![allow(unused)]
|
||||||
|
|
||||||
|
struct Foo { x: i32 }
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let f = Foo { x: 0 };
|
||||||
|
let Foo { .. } = f;
|
||||||
|
let Foo { .., } = f; //~ ERROR expected `}`, found `,`
|
||||||
|
let Foo { x, .. } = f;
|
||||||
|
let Foo { .., x } = f; //~ ERROR expected `}`, found `,`
|
||||||
|
let Foo { .., x, .. } = f; //~ ERROR expected `}`, found `,`
|
||||||
|
}
|
37
tests/ui/parser/issue-112188.stderr
Normal file
37
tests/ui/parser/issue-112188.stderr
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
error: expected `}`, found `,`
|
||||||
|
--> $DIR/issue-112188.rs:10:17
|
||||||
|
|
|
||||||
|
LL | let Foo { .., } = f;
|
||||||
|
| --^
|
||||||
|
| | |
|
||||||
|
| | expected `}`
|
||||||
|
| | help: remove this comma
|
||||||
|
| `..` must be at the end and cannot have a trailing comma
|
||||||
|
|
||||||
|
error: expected `}`, found `,`
|
||||||
|
--> $DIR/issue-112188.rs:12:17
|
||||||
|
|
|
||||||
|
LL | let Foo { .., x } = f;
|
||||||
|
| --^
|
||||||
|
| | |
|
||||||
|
| | expected `}`
|
||||||
|
| `..` must be at the end and cannot have a trailing comma
|
||||||
|
|
|
||||||
|
help: move the `..` to the end of the field list
|
||||||
|
|
|
||||||
|
LL - let Foo { .., x } = f;
|
||||||
|
LL + let Foo { x, .. } = f;
|
||||||
|
|
|
||||||
|
|
||||||
|
error: expected `}`, found `,`
|
||||||
|
--> $DIR/issue-112188.rs:13:17
|
||||||
|
|
|
||||||
|
LL | let Foo { .., x, .. } = f;
|
||||||
|
| --^-
|
||||||
|
| | |
|
||||||
|
| | expected `}`
|
||||||
|
| `..` must be at the end and cannot have a trailing comma
|
||||||
|
| help: remove the starting `..`
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors
|
||||||
|
|
@ -25,7 +25,7 @@ LL | let Point { .., y } = p;
|
|||||||
help: move the `..` to the end of the field list
|
help: move the `..` to the end of the field list
|
||||||
|
|
|
|
||||||
LL - let Point { .., y } = p;
|
LL - let Point { .., y } = p;
|
||||||
LL + let Point { y , .. } = p;
|
LL + let Point { y, .. } = p;
|
||||||
|
|
|
|
||||||
|
|
||||||
error: expected `}`, found `,`
|
error: expected `}`, found `,`
|
||||||
|
Loading…
x
Reference in New Issue
Block a user