Skip to content

Commit edd7377

Browse files
committed
Suggest use ; to construct array type when other token exists
Signed-off-by: xizheyin <[email protected]>
1 parent 1cac8cb commit edd7377

File tree

8 files changed

+174
-50
lines changed

8 files changed

+174
-50
lines changed

compiler/rustc_parse/src/parser/ty.rs

Lines changed: 72 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -575,14 +575,84 @@ impl<'a> Parser<'a> {
575575
self.expect(exp!(CloseBracket))?;
576576
}
577577
TyKind::Array(elt_ty, length)
578-
} else {
579-
self.expect(exp!(CloseBracket))?;
578+
} else if self.eat(exp!(CloseBracket)) {
580579
TyKind::Slice(elt_ty)
580+
} else {
581+
self.maybe_recover_array_ty_without_semi(elt_ty)?
581582
};
582583

583584
Ok(ty)
584585
}
585586

587+
/// Recover from malformed array type syntax.
588+
///
589+
/// This method attempts to recover from cases like:
590+
/// - `[u8, 5]` → suggests using `;`, return a Array type
591+
/// - `[u8 5]` → suggests using `;`, return a Array type
592+
/// Consider to add more cases in the future.
593+
fn maybe_recover_array_ty_without_semi(&mut self, elt_ty: P<Ty>) -> PResult<'a, TyKind> {
594+
let span = self.token.span;
595+
let token_descr = super::token_descr(&self.token);
596+
let mut err =
597+
self.dcx().struct_span_err(span, format!("expected `;` or `]`, found {}", token_descr));
598+
err.span_label(span, "expected `;` or `]`");
599+
err.note("you might have meant to write a slice or array type");
600+
601+
// If we cannot recover, return the error immediately.
602+
if !self.may_recover() {
603+
return Err(err);
604+
}
605+
606+
let snapshot = self.create_snapshot_for_diagnostic();
607+
608+
// we first try to parse pattern like `[u8 5]`
609+
let length = match self.parse_expr_anon_const() {
610+
Ok(length) => length,
611+
Err(e) => {
612+
e.cancel();
613+
self.bump();
614+
match self.parse_expr_anon_const() {
615+
Ok(expr) => {
616+
// if [u8, 5] is parsed successfully, we suggest to add `;` as the separator
617+
err.span_suggestion_verbose(
618+
span,
619+
"you might have meant to use `;` as the separator",
620+
";",
621+
Applicability::MaybeIncorrect,
622+
);
623+
if let Err(e) = self.expect(exp!(CloseBracket)) {
624+
e.cancel();
625+
self.restore_snapshot(snapshot);
626+
return Err(err);
627+
}
628+
err.emit();
629+
return Ok(TyKind::Array(elt_ty, expr));
630+
}
631+
Err(e) => {
632+
e.cancel();
633+
self.restore_snapshot(snapshot);
634+
return Err(err);
635+
}
636+
}
637+
}
638+
};
639+
640+
if let Err(e) = self.expect(exp!(CloseBracket)) {
641+
e.cancel();
642+
self.restore_snapshot(snapshot);
643+
return Err(err);
644+
}
645+
646+
err.span_suggestion_verbose(
647+
span.shrink_to_lo(),
648+
"you might have meant to use `;` as the separator",
649+
";",
650+
Applicability::MaybeIncorrect,
651+
);
652+
err.emit();
653+
Ok(TyKind::Array(elt_ty, length))
654+
}
655+
586656
fn parse_borrowed_pointee(&mut self) -> PResult<'a, TyKind> {
587657
let and_span = self.prev_token.span;
588658
let mut opt_lifetime = self.check_lifetime().then(|| self.expect_lifetime());

tests/ui/issues/issue-50571.stderr

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,16 @@
1+
error: expected `;` or `]`, found `,`
2+
--> $DIR/issue-50571.rs:6:14
3+
|
4+
LL | fn foo([a, b]: [i32; 2]) {}
5+
| ^ expected `;` or `]`
6+
|
7+
= note: you might have meant to write a slice or array type
8+
help: you might have meant to use `;` as the separator
9+
|
10+
LL - fn foo([a, b]: [i32; 2]) {}
11+
LL + fn foo([a; b]: [i32; 2]) {}
12+
|
13+
114
error[E0642]: patterns aren't allowed in methods without bodies
215
--> $DIR/issue-50571.rs:6:12
316
|
@@ -10,6 +23,6 @@ LL - fn foo([a, b]: [i32; 2]) {}
1023
LL + fn foo(_: [i32; 2]) {}
1124
|
1225

13-
error: aborting due to 1 previous error
26+
error: aborting due to 2 previous errors
1427

1528
For more information about this error, try `rustc --explain E0642`.

tests/ui/parser/better-expected.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
fn main() {
2-
let x: [isize 3]; //~ ERROR expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `3`
2+
let x: [isize 3]; //~ ERROR expected `;` or `]`, found `3`
33
}
Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
1-
error: expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `3`
1+
error: expected `;` or `]`, found `3`
22
--> $DIR/better-expected.rs:2:19
33
|
44
LL | let x: [isize 3];
5-
| - ^ expected one of 7 possible tokens
6-
| |
7-
| while parsing the type for `x`
5+
| ^ expected `;` or `]`
6+
|
7+
= note: you might have meant to write a slice or array type
8+
help: you might have meant to use `;` as the separator
9+
|
10+
LL | let x: [isize ;3];
11+
| +
812

913
error: aborting due to 1 previous error
1014

tests/ui/parser/recover/array-type-no-semi.rs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,13 @@
55
fn main() {
66
let x = 5;
77
let b: [i32, 5];
8-
//~^ ERROR expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `,`
9-
//~| ERROR expected value, found builtin type `i32` [E0423]
8+
//~^ ERROR expected `;` or `]`, found `,`
109
let a: [i32, ];
11-
//~^ ERROR expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `,`
10+
//~^ ERROR expected `;` or `]`, found `,`
1211
//~| ERROR expected value, found builtin type `i32` [E0423]
1312
let c: [i32, x];
14-
//~^ ERROR expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `,`
15-
//~| ERROR expected value, found builtin type `i32` [E0423]
13+
//~^ ERROR expected `;` or `]`, found `,`
14+
//~| ERROR attempt to use a non-constant value in a constant [E0435]
1615
let e: [i32 5];
17-
//~^ ERROR expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `5`
16+
//~^ ERROR expected `;` or `]`, found `5`
1817
}
Lines changed: 47 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,71 @@
1-
error: expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `,`
1+
error: expected `;` or `]`, found `,`
22
--> $DIR/array-type-no-semi.rs:7:16
33
|
44
LL | let b: [i32, 5];
5-
| - ^ expected one of 7 possible tokens
6-
| |
7-
| while parsing the type for `b`
8-
| help: use `=` if you meant to assign
5+
| ^ expected `;` or `]`
6+
|
7+
= note: you might have meant to write a slice or array type
8+
help: you might have meant to use `;` as the separator
9+
|
10+
LL - let b: [i32, 5];
11+
LL + let b: [i32; 5];
12+
|
913

10-
error: expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `,`
11-
--> $DIR/array-type-no-semi.rs:10:16
14+
error: expected `;` or `]`, found `,`
15+
--> $DIR/array-type-no-semi.rs:9:16
1216
|
1317
LL | let a: [i32, ];
14-
| - ^ expected one of 7 possible tokens
18+
| - ^ expected `;` or `]`
1519
| |
1620
| while parsing the type for `a`
1721
| help: use `=` if you meant to assign
22+
|
23+
= note: you might have meant to write a slice or array type
1824

19-
error: expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `,`
20-
--> $DIR/array-type-no-semi.rs:13:16
25+
error: expected `;` or `]`, found `,`
26+
--> $DIR/array-type-no-semi.rs:12:16
2127
|
2228
LL | let c: [i32, x];
23-
| - ^ expected one of 7 possible tokens
24-
| |
25-
| while parsing the type for `c`
26-
| help: use `=` if you meant to assign
29+
| ^ expected `;` or `]`
30+
|
31+
= note: you might have meant to write a slice or array type
32+
help: you might have meant to use `;` as the separator
33+
|
34+
LL - let c: [i32, x];
35+
LL + let c: [i32; x];
36+
|
2737

28-
error: expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `5`
29-
--> $DIR/array-type-no-semi.rs:16:17
38+
error: expected `;` or `]`, found `5`
39+
--> $DIR/array-type-no-semi.rs:15:17
3040
|
3141
LL | let e: [i32 5];
32-
| - ^ expected one of 7 possible tokens
33-
| |
34-
| while parsing the type for `e`
35-
36-
error[E0423]: expected value, found builtin type `i32`
37-
--> $DIR/array-type-no-semi.rs:7:13
42+
| ^ expected `;` or `]`
3843
|
39-
LL | let b: [i32, 5];
40-
| ^^^ not a value
44+
= note: you might have meant to write a slice or array type
45+
help: you might have meant to use `;` as the separator
46+
|
47+
LL | let e: [i32 ;5];
48+
| +
4149

42-
error[E0423]: expected value, found builtin type `i32`
43-
--> $DIR/array-type-no-semi.rs:10:13
50+
error[E0435]: attempt to use a non-constant value in a constant
51+
--> $DIR/array-type-no-semi.rs:12:18
52+
|
53+
LL | let c: [i32, x];
54+
| ^ non-constant value
55+
|
56+
help: consider using `const` instead of `let`
57+
|
58+
LL - let x = 5;
59+
LL + const x: /* Type */ = 5;
4460
|
45-
LL | let a: [i32, ];
46-
| ^^^ not a value
4761

4862
error[E0423]: expected value, found builtin type `i32`
49-
--> $DIR/array-type-no-semi.rs:13:13
63+
--> $DIR/array-type-no-semi.rs:9:13
5064
|
51-
LL | let c: [i32, x];
65+
LL | let a: [i32, ];
5266
| ^^^ not a value
5367

54-
error: aborting due to 7 previous errors
68+
error: aborting due to 6 previous errors
5569

56-
For more information about this error, try `rustc --explain E0423`.
70+
Some errors have detailed explanations: E0423, E0435.
71+
For more information about an error, try `rustc --explain E0423`.
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
1-
type v = [isize * 3]; //~ ERROR expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `*`
1+
type v = [isize * 3]; //~ ERROR expected `;` or `]`, found `*`
2+
3+
fn main() {}
Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,29 @@
1-
error: expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `*`
1+
error: expected `;` or `]`, found `*`
22
--> $DIR/removed-syntax-fixed-vec.rs:1:17
33
|
44
LL | type v = [isize * 3];
5-
| ^ expected one of 7 possible tokens
5+
| ^ expected `;` or `]`
6+
|
7+
= note: you might have meant to write a slice or array type
8+
help: you might have meant to use `;` as the separator
9+
|
10+
LL | type v = [isize ;* 3];
11+
| +
12+
13+
warning: type `v` should have an upper camel case name
14+
--> $DIR/removed-syntax-fixed-vec.rs:1:6
15+
|
16+
LL | type v = [isize * 3];
17+
| ^ help: convert the identifier to upper camel case (notice the capitalization): `V`
18+
|
19+
= note: `#[warn(non_camel_case_types)]` on by default
20+
21+
error[E0614]: type `{integer}` cannot be dereferenced
22+
--> $DIR/removed-syntax-fixed-vec.rs:1:17
23+
|
24+
LL | type v = [isize * 3];
25+
| ^^^ can't be dereferenced
626

7-
error: aborting due to 1 previous error
27+
error: aborting due to 2 previous errors; 1 warning emitted
828

29+
For more information about this error, try `rustc --explain E0614`.

0 commit comments

Comments
 (0)