Skip to content

Commit 71a72ee

Browse files
authored
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.
2 parents 21e7463 + 2a7c6a9 commit 71a72ee

File tree

5 files changed

+111
-13
lines changed

5 files changed

+111
-13
lines changed

compiler/rustc_parse/src/parser/pat.rs

+45-12
Original file line numberDiff line numberDiff line change
@@ -938,7 +938,8 @@ impl<'a> Parser<'a> {
938938
let mut etc = false;
939939
let mut ate_comma = true;
940940
let mut delayed_err: Option<DiagnosticBuilder<'a, ErrorGuaranteed>> = None;
941-
let mut etc_span = None;
941+
let mut first_etc_and_maybe_comma_span = None;
942+
let mut last_non_comma_dotdot_span = None;
942943

943944
while self.token != token::CloseDelim(Delimiter::Brace) {
944945
let attrs = match self.parse_outer_attributes() {
@@ -969,12 +970,27 @@ impl<'a> Parser<'a> {
969970
{
970971
etc = true;
971972
let mut etc_sp = self.token.span;
973+
if first_etc_and_maybe_comma_span.is_none() {
974+
if let Some(comma_tok) = self
975+
.look_ahead(1, |t| if *t == token::Comma { Some(t.clone()) } else { None })
976+
{
977+
let nw_span = self
978+
.sess
979+
.source_map()
980+
.span_extend_to_line(comma_tok.span)
981+
.trim_start(comma_tok.span.shrink_to_lo())
982+
.map(|s| self.sess.source_map().span_until_non_whitespace(s));
983+
first_etc_and_maybe_comma_span = nw_span.map(|s| etc_sp.to(s));
984+
} else {
985+
first_etc_and_maybe_comma_span =
986+
Some(self.sess.source_map().span_until_non_whitespace(etc_sp));
987+
}
988+
}
972989

973990
self.recover_bad_dot_dot();
974991
self.bump(); // `..` || `...` || `_`
975992

976993
if self.token == token::CloseDelim(Delimiter::Brace) {
977-
etc_span = Some(etc_sp);
978994
break;
979995
}
980996
let token_str = super::token_descr(&self.token);
@@ -996,7 +1012,6 @@ impl<'a> Parser<'a> {
9961012
ate_comma = true;
9971013
}
9981014

999-
etc_span = Some(etc_sp.until(self.token.span));
10001015
if self.token == token::CloseDelim(Delimiter::Brace) {
10011016
// If the struct looks otherwise well formed, recover and continue.
10021017
if let Some(sp) = comma_sp {
@@ -1040,6 +1055,9 @@ impl<'a> Parser<'a> {
10401055
}
10411056
}?;
10421057
ate_comma = this.eat(&token::Comma);
1058+
1059+
last_non_comma_dotdot_span = Some(this.prev_token.span);
1060+
10431061
// We just ate a comma, so there's no need to use
10441062
// `TrailingToken::Comma`
10451063
Ok((field, TrailingToken::None))
@@ -1049,15 +1067,30 @@ impl<'a> Parser<'a> {
10491067
}
10501068

10511069
if let Some(mut err) = delayed_err {
1052-
if let Some(etc_span) = etc_span {
1053-
err.multipart_suggestion(
1054-
"move the `..` to the end of the field list",
1055-
vec![
1056-
(etc_span, String::new()),
1057-
(self.token.span, format!("{}.. }}", if ate_comma { "" } else { ", " })),
1058-
],
1059-
Applicability::MachineApplicable,
1060-
);
1070+
if let Some(first_etc_span) = first_etc_and_maybe_comma_span {
1071+
if self.prev_token == token::DotDot {
1072+
// We have `.., x, ..`.
1073+
err.multipart_suggestion(
1074+
"remove the starting `..`",
1075+
vec![(first_etc_span, String::new())],
1076+
Applicability::MachineApplicable,
1077+
);
1078+
} else {
1079+
if let Some(last_non_comma_dotdot_span) = last_non_comma_dotdot_span {
1080+
// We have `.., x`.
1081+
err.multipart_suggestion(
1082+
"move the `..` to the end of the field list",
1083+
vec![
1084+
(first_etc_span, String::new()),
1085+
(
1086+
self.token.span.to(last_non_comma_dotdot_span.shrink_to_hi()),
1087+
format!("{} .. }}", if ate_comma { "" } else { "," }),
1088+
),
1089+
],
1090+
Applicability::MachineApplicable,
1091+
);
1092+
}
1093+
}
10611094
}
10621095
err.emit();
10631096
}

tests/ui/parser/issue-112188.fixed

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// run-rustfix
2+
3+
#![allow(unused)]
4+
5+
struct Foo { x: i32 }
6+
7+
fn main() {
8+
let f = Foo { x: 0 };
9+
let Foo { .. } = f;
10+
let Foo { .. } = f; //~ ERROR expected `}`, found `,`
11+
let Foo { x, .. } = f;
12+
let Foo { x, .. } = f; //~ ERROR expected `}`, found `,`
13+
let Foo { x, .. } = f; //~ ERROR expected `}`, found `,`
14+
}

tests/ui/parser/issue-112188.rs

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// run-rustfix
2+
3+
#![allow(unused)]
4+
5+
struct Foo { x: i32 }
6+
7+
fn main() {
8+
let f = Foo { x: 0 };
9+
let Foo { .. } = f;
10+
let Foo { .., } = f; //~ ERROR expected `}`, found `,`
11+
let Foo { x, .. } = f;
12+
let Foo { .., x } = f; //~ ERROR expected `}`, found `,`
13+
let Foo { .., x, .. } = f; //~ ERROR expected `}`, found `,`
14+
}

tests/ui/parser/issue-112188.stderr

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
error: expected `}`, found `,`
2+
--> $DIR/issue-112188.rs:10:17
3+
|
4+
LL | let Foo { .., } = f;
5+
| --^
6+
| | |
7+
| | expected `}`
8+
| | help: remove this comma
9+
| `..` must be at the end and cannot have a trailing comma
10+
11+
error: expected `}`, found `,`
12+
--> $DIR/issue-112188.rs:12:17
13+
|
14+
LL | let Foo { .., x } = f;
15+
| --^
16+
| | |
17+
| | expected `}`
18+
| `..` must be at the end and cannot have a trailing comma
19+
|
20+
help: move the `..` to the end of the field list
21+
|
22+
LL - let Foo { .., x } = f;
23+
LL + let Foo { x, .. } = f;
24+
|
25+
26+
error: expected `}`, found `,`
27+
--> $DIR/issue-112188.rs:13:17
28+
|
29+
LL | let Foo { .., x, .. } = f;
30+
| --^-
31+
| | |
32+
| | expected `}`
33+
| `..` must be at the end and cannot have a trailing comma
34+
| help: remove the starting `..`
35+
36+
error: aborting due to 3 previous errors
37+

tests/ui/parser/issue-49257.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ LL | let Point { .., y } = p;
2525
help: move the `..` to the end of the field list
2626
|
2727
LL - let Point { .., y } = p;
28-
LL + let Point { y , .. } = p;
28+
LL + let Point { y, .. } = p;
2929
|
3030

3131
error: expected `}`, found `,`

0 commit comments

Comments
 (0)