Skip to content

Commit a4f7e21

Browse files
committed
Recover and suggest use ; to construct array type
Signed-off-by: xizheyin <[email protected]>
1 parent 1cac8cb commit a4f7e21

File tree

14 files changed

+204
-86
lines changed

14 files changed

+204
-86
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());

src/tools/tidy/src/issues.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2338,7 +2338,6 @@ ui/issues/issue-50415.rs
23382338
ui/issues/issue-50442.rs
23392339
ui/issues/issue-50471.rs
23402340
ui/issues/issue-50518.rs
2341-
ui/issues/issue-50571.rs
23422341
ui/issues/issue-50581.rs
23432342
ui/issues/issue-50582.rs
23442343
ui/issues/issue-50585.rs

src/tools/tidy/src/ui_tests.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use ignore::Walk;
1717
const ENTRY_LIMIT: u32 = 901;
1818
// FIXME: The following limits should be reduced eventually.
1919

20-
const ISSUES_ENTRY_LIMIT: u32 = 1619;
20+
const ISSUES_ENTRY_LIMIT: u32 = 1616;
2121

2222
const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[
2323
"rs", // test source files

tests/ui/issues/issue-50571.fixed

Lines changed: 0 additions & 10 deletions
This file was deleted.

tests/ui/issues/issue-50571.rs

Lines changed: 0 additions & 10 deletions
This file was deleted.

tests/ui/issues/issue-50571.stderr

Lines changed: 0 additions & 15 deletions
This file was deleted.

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// There is a regression introduced for issue #143828
2+
//@ edition: 2015
3+
4+
#![allow(dead_code)]
5+
trait Foo {
6+
fn foo([a, b]: [i32; 2]) {}
7+
//~^ ERROR: expected `;` or `]`, found `,`
8+
//~| ERROR: patterns aren't allowed in methods without bodies
9+
}
10+
11+
fn main() {}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
error: expected `;` or `]`, found `,`
2+
--> $DIR/error-pattern-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+
14+
error[E0642]: patterns aren't allowed in methods without bodies
15+
--> $DIR/error-pattern-issue-50571.rs:6:12
16+
|
17+
LL | fn foo([a, b]: [i32; 2]) {}
18+
| ^^^^^^
19+
|
20+
help: give this argument a name or use an underscore to ignore it
21+
|
22+
LL - fn foo([a, b]: [i32; 2]) {}
23+
LL + fn foo(_: [i32; 2]) {}
24+
|
25+
26+
error: aborting due to 2 previous errors
27+
28+
For more information about this error, try `rustc --explain E0642`.

0 commit comments

Comments
 (0)