Skip to content

Commit

Permalink
Rollup merge of #112199 - jieyouxu:issue-112188, r=compiler-errors
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
matthiaskrgr authored Jun 6, 2023
2 parents 21e7463 + 2a7c6a9 commit 71a72ee
Show file tree
Hide file tree
Showing 5 changed files with 111 additions and 13 deletions.
57 changes: 45 additions & 12 deletions compiler/rustc_parse/src/parser/pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -938,7 +938,8 @@ impl<'a> Parser<'a> {
let mut etc = false;
let mut ate_comma = true;
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) {
let attrs = match self.parse_outer_attributes() {
Expand Down Expand Up @@ -969,12 +970,27 @@ impl<'a> Parser<'a> {
{
etc = true;
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.bump(); // `..` || `...` || `_`

if self.token == token::CloseDelim(Delimiter::Brace) {
etc_span = Some(etc_sp);
break;
}
let token_str = super::token_descr(&self.token);
Expand All @@ -996,7 +1012,6 @@ impl<'a> Parser<'a> {
ate_comma = true;
}

etc_span = Some(etc_sp.until(self.token.span));
if self.token == token::CloseDelim(Delimiter::Brace) {
// If the struct looks otherwise well formed, recover and continue.
if let Some(sp) = comma_sp {
Expand Down Expand Up @@ -1040,6 +1055,9 @@ impl<'a> Parser<'a> {
}
}?;
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
// `TrailingToken::Comma`
Ok((field, TrailingToken::None))
Expand All @@ -1049,15 +1067,30 @@ impl<'a> Parser<'a> {
}

if let Some(mut err) = delayed_err {
if let Some(etc_span) = etc_span {
err.multipart_suggestion(
"move the `..` to the end of the field list",
vec![
(etc_span, String::new()),
(self.token.span, format!("{}.. }}", if ate_comma { "" } else { ", " })),
],
Applicability::MachineApplicable,
);
if let Some(first_etc_span) = first_etc_and_maybe_comma_span {
if self.prev_token == token::DotDot {
// We have `.., x, ..`.
err.multipart_suggestion(
"remove the starting `..`",
vec![(first_etc_span, String::new())],
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();
}
Expand Down
14 changes: 14 additions & 0 deletions tests/ui/parser/issue-112188.fixed
Original file line number Diff line number Diff line change
@@ -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 changes: 14 additions & 0 deletions tests/ui/parser/issue-112188.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 37 additions & 0 deletions tests/ui/parser/issue-112188.stderr
Original file line number Diff line number Diff line change
@@ -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

2 changes: 1 addition & 1 deletion tests/ui/parser/issue-49257.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ LL | let Point { .., y } = p;
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;
|

error: expected `}`, found `,`
Expand Down

0 comments on commit 71a72ee

Please sign in to comment.