Skip to content

Commit c07b227

Browse files
authored
Rollup merge of rust-lang#59453 - estebank:recover-tuple-parse, r=petrochenkov
Recover from parse error in tuple syntax
2 parents 76de89e + 3592079 commit c07b227

13 files changed

+228
-34
lines changed

src/libsyntax/parse/parser.rs

+57-26
Original file line numberDiff line numberDiff line change
@@ -2626,7 +2626,13 @@ impl<'a> Parser<'a> {
26262626
let mut trailing_comma = false;
26272627
let mut recovered = false;
26282628
while self.token != token::CloseDelim(token::Paren) {
2629-
es.push(self.parse_expr()?);
2629+
es.push(match self.parse_expr() {
2630+
Ok(es) => es,
2631+
Err(err) => {
2632+
// recover from parse error in tuple list
2633+
return Ok(self.recover_seq_parse_error(token::Paren, lo, Err(err)));
2634+
}
2635+
});
26302636
recovered = self.expect_one_of(
26312637
&[],
26322638
&[token::Comma, token::CloseDelim(token::Paren)],
@@ -3237,36 +3243,54 @@ impl<'a> Parser<'a> {
32373243
}
32383244
if self.expr_is_complete(&e) { break; }
32393245
match self.token {
3240-
// expr(...)
3241-
token::OpenDelim(token::Paren) => {
3242-
let es = self.parse_unspanned_seq(
3243-
&token::OpenDelim(token::Paren),
3244-
&token::CloseDelim(token::Paren),
3245-
SeqSep::trailing_allowed(token::Comma),
3246-
|p| Ok(p.parse_expr()?)
3247-
)?;
3248-
hi = self.prev_span;
3249-
3250-
let nd = self.mk_call(e, es);
3251-
e = self.mk_expr(lo.to(hi), nd, ThinVec::new());
3252-
}
3246+
// expr(...)
3247+
token::OpenDelim(token::Paren) => {
3248+
let seq = self.parse_unspanned_seq(
3249+
&token::OpenDelim(token::Paren),
3250+
&token::CloseDelim(token::Paren),
3251+
SeqSep::trailing_allowed(token::Comma),
3252+
|p| Ok(p.parse_expr()?)
3253+
).map(|es| {
3254+
let nd = self.mk_call(e, es);
3255+
let hi = self.prev_span;
3256+
self.mk_expr(lo.to(hi), nd, ThinVec::new())
3257+
});
3258+
e = self.recover_seq_parse_error(token::Paren, lo, seq);
3259+
}
32533260

3254-
// expr[...]
3255-
// Could be either an index expression or a slicing expression.
3256-
token::OpenDelim(token::Bracket) => {
3257-
self.bump();
3258-
let ix = self.parse_expr()?;
3259-
hi = self.span;
3260-
self.expect(&token::CloseDelim(token::Bracket))?;
3261-
let index = self.mk_index(e, ix);
3262-
e = self.mk_expr(lo.to(hi), index, ThinVec::new())
3263-
}
3264-
_ => return Ok(e)
3261+
// expr[...]
3262+
// Could be either an index expression or a slicing expression.
3263+
token::OpenDelim(token::Bracket) => {
3264+
self.bump();
3265+
let ix = self.parse_expr()?;
3266+
hi = self.span;
3267+
self.expect(&token::CloseDelim(token::Bracket))?;
3268+
let index = self.mk_index(e, ix);
3269+
e = self.mk_expr(lo.to(hi), index, ThinVec::new())
3270+
}
3271+
_ => return Ok(e)
32653272
}
32663273
}
32673274
return Ok(e);
32683275
}
32693276

3277+
fn recover_seq_parse_error(
3278+
&mut self,
3279+
delim: token::DelimToken,
3280+
lo: Span,
3281+
result: PResult<'a, P<Expr>>,
3282+
) -> P<Expr> {
3283+
match result {
3284+
Ok(x) => x,
3285+
Err(mut err) => {
3286+
err.emit();
3287+
// recover from parse error
3288+
self.consume_block(delim);
3289+
self.mk_expr(lo.to(self.prev_span), ExprKind::Err, ThinVec::new())
3290+
}
3291+
}
3292+
}
3293+
32703294
crate fn process_potential_macro_variable(&mut self) {
32713295
let (token, span) = match self.token {
32723296
token::Dollar if self.span.ctxt() != syntax_pos::hygiene::SyntaxContext::empty() &&
@@ -4253,7 +4277,14 @@ impl<'a> Parser<'a> {
42534277
// Trailing commas are significant because (p) and (p,) are different patterns.
42544278
fn parse_parenthesized_pat_list(&mut self) -> PResult<'a, (Vec<P<Pat>>, Option<usize>, bool)> {
42554279
self.expect(&token::OpenDelim(token::Paren))?;
4256-
let result = self.parse_pat_list()?;
4280+
let result = match self.parse_pat_list() {
4281+
Ok(result) => result,
4282+
Err(mut err) => { // recover from parse error in tuple pattern list
4283+
err.emit();
4284+
self.consume_block(token::Paren);
4285+
return Ok((vec![], Some(0), false));
4286+
}
4287+
};
42574288
self.expect(&token::CloseDelim(token::Paren))?;
42584289
Ok(result)
42594290
}

src/test/ui/issues/issue-34334.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
11
fn main () {
2-
let sr: Vec<(u32, _, _) = vec![]; //~ ERROR expected one of `,` or `>`, found `=`
2+
let sr: Vec<(u32, _, _) = vec![];
3+
//~^ ERROR expected one of `,` or `>`, found `=`
4+
//~| ERROR expected value, found struct `Vec`
5+
//~| ERROR mismatched types
6+
//~| ERROR invalid left-hand side expression
7+
//~| ERROR expected expression, found reserved identifier `_`
38
let sr2: Vec<(u32, _, _)> = sr.iter().map(|(faction, th_sender, th_receiver)| {}).collect();
9+
//~^ ERROR no method named `iter` found for type `()` in the current scope
410
}

src/test/ui/issues/issue-34334.stderr

+40-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,47 @@
1+
error: expected expression, found reserved identifier `_`
2+
--> $DIR/issue-34334.rs:2:23
3+
|
4+
LL | let sr: Vec<(u32, _, _) = vec![];
5+
| ^ expected expression
6+
17
error: expected one of `,` or `>`, found `=`
28
--> $DIR/issue-34334.rs:2:29
39
|
410
LL | let sr: Vec<(u32, _, _) = vec![];
5-
| -- ^ expected one of `,` or `>` here
6-
| |
11+
| --- ^ expected one of `,` or `>` here
12+
| | |
13+
| | help: use `=` if you meant to assign
714
| while parsing the type for `sr`
815

9-
error: aborting due to previous error
16+
error[E0423]: expected value, found struct `Vec`
17+
--> $DIR/issue-34334.rs:2:13
18+
|
19+
LL | let sr: Vec<(u32, _, _) = vec![];
20+
| ^^^ did you mean `Vec { /* fields */ }`?
21+
22+
error[E0308]: mismatched types
23+
--> $DIR/issue-34334.rs:2:31
24+
|
25+
LL | let sr: Vec<(u32, _, _) = vec![];
26+
| ^^^^^^ expected bool, found struct `std::vec::Vec`
27+
|
28+
= note: expected type `bool`
29+
found type `std::vec::Vec<_>`
30+
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
31+
32+
error[E0070]: invalid left-hand side expression
33+
--> $DIR/issue-34334.rs:2:13
34+
|
35+
LL | let sr: Vec<(u32, _, _) = vec![];
36+
| ^^^^^^^^^^^^^^^^^^^^^^^^ left-hand of expression not valid
37+
38+
error[E0599]: no method named `iter` found for type `()` in the current scope
39+
--> $DIR/issue-34334.rs:8:36
40+
|
41+
LL | let sr2: Vec<(u32, _, _)> = sr.iter().map(|(faction, th_sender, th_receiver)| {}).collect();
42+
| ^^^^
43+
44+
error: aborting due to 6 previous errors
1045

46+
Some errors occurred: E0070, E0308, E0423, E0599.
47+
For more information about an error, try `rustc --explain E0070`.

src/test/ui/parser/pat-tuple-1.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
fn main() {
2-
match 0 {
2+
match (0, 1) {
33
(, ..) => {} //~ ERROR expected pattern, found `,`
44
}
55
}

src/test/ui/parser/pat-tuple-5.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
fn main() {
2-
match 0 {
2+
match (0, 1) {
33
(pat ..) => {} //~ ERROR unexpected token: `)`
44
}
55
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
enum Enum {
2+
Foo { a: usize, b: usize },
3+
Bar(usize, usize),
4+
}
5+
6+
fn main() {
7+
let x = Enum::Foo(a: 3, b: 4);
8+
//~^ ERROR expected type, found `3`
9+
match x {
10+
Enum::Foo(a, b) => {}
11+
//~^ ERROR expected tuple struct/variant, found struct variant `Enum::Foo`
12+
Enum::Bar(a, b) => {}
13+
}
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
error: expected type, found `3`
2+
--> $DIR/recover-from-bad-variant.rs:7:26
3+
|
4+
LL | let x = Enum::Foo(a: 3, b: 4);
5+
| ^ expecting a type here because of type ascription
6+
|
7+
= note: type ascription is a nightly-only feature that lets you annotate an expression with a type: `<expr>: <type>`
8+
note: this expression expects an ascribed type after the colon
9+
--> $DIR/recover-from-bad-variant.rs:7:23
10+
|
11+
LL | let x = Enum::Foo(a: 3, b: 4);
12+
| ^
13+
= help: this might be indicative of a syntax error elsewhere
14+
15+
error[E0532]: expected tuple struct/variant, found struct variant `Enum::Foo`
16+
--> $DIR/recover-from-bad-variant.rs:10:9
17+
|
18+
LL | Enum::Foo(a, b) => {}
19+
| ^^^^^^^^^ did you mean `Enum::Foo { /* fields */ }`?
20+
21+
error: aborting due to 2 previous errors
22+
23+
For more information about this error, try `rustc --explain E0532`.
+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
fn main() {
2+
let x = (1, 2, 3, 4);
3+
match x {
4+
(1, .., 4) => {}
5+
(1, .=., 4) => { let _: usize = ""; }
6+
//~^ ERROR expected pattern, found `.`
7+
//~| ERROR mismatched types
8+
(.=., 4) => {}
9+
//~^ ERROR expected pattern, found `.`
10+
(1, 2, 3, 4) => {}
11+
}
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
error: expected pattern, found `.`
2+
--> $DIR/recover-tuple-pat.rs:5:13
3+
|
4+
LL | (1, .=., 4) => { let _: usize = ""; }
5+
| ^ expected pattern
6+
7+
error: expected pattern, found `.`
8+
--> $DIR/recover-tuple-pat.rs:8:10
9+
|
10+
LL | (.=., 4) => {}
11+
| ^ expected pattern
12+
13+
error[E0308]: mismatched types
14+
--> $DIR/recover-tuple-pat.rs:5:41
15+
|
16+
LL | (1, .=., 4) => { let _: usize = ""; }
17+
| ^^ expected usize, found reference
18+
|
19+
= note: expected type `usize`
20+
found type `&'static str`
21+
22+
error: aborting due to 3 previous errors
23+
24+
For more information about this error, try `rustc --explain E0308`.

src/test/ui/parser/recover-tuple.rs

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
fn main() {
2+
// no complaints about the tuple not matching the expected type
3+
let x: (usize, usize, usize) = (3, .=.);
4+
//~^ ERROR expected expression, found `.`
5+
// verify that the parser recovers:
6+
let y: usize = ""; //~ ERROR mismatched types
7+
// no complaints about the type
8+
foo(x);
9+
}
10+
11+
fn foo(_: (usize, usize, usize)) {}
+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
error: expected expression, found `.`
2+
--> $DIR/recover-tuple.rs:3:40
3+
|
4+
LL | let x: (usize, usize, usize) = (3, .=.);
5+
| ^ expected expression
6+
7+
error[E0308]: mismatched types
8+
--> $DIR/recover-tuple.rs:6:20
9+
|
10+
LL | let y: usize = "";
11+
| ^^ expected usize, found reference
12+
|
13+
= note: expected type `usize`
14+
found type `&'static str`
15+
16+
error: aborting due to 2 previous errors
17+
18+
For more information about this error, try `rustc --explain E0308`.

src/test/ui/parser/trait-object-lifetime-parens.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@ fn f<'a, T: Trait + ('a)>() {} //~ ERROR parenthesized lifetime bounds are not s
66

77
fn check<'a>() {
88
let _: Box<Trait + ('a)>; //~ ERROR parenthesized lifetime bounds are not supported
9-
let _: Box<('a) + Trait>; //~ ERROR expected type, found `'a`
9+
let _: Box<('a) + Trait>;
10+
//~^ ERROR expected type, found `'a`
11+
//~| ERROR expected `:`, found `)`
12+
//~| ERROR chained comparison operators require parentheses
1013
}
1114

1215
fn main() {}

src/test/ui/parser/trait-object-lifetime-parens.stderr

+16-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,21 @@ error: parenthesized lifetime bounds are not supported
1010
LL | let _: Box<Trait + ('a)>;
1111
| ^^^^ help: remove the parentheses
1212

13+
error: expected `:`, found `)`
14+
--> $DIR/trait-object-lifetime-parens.rs:9:19
15+
|
16+
LL | let _: Box<('a) + Trait>;
17+
| ^ expected `:`
18+
19+
error: chained comparison operators require parentheses
20+
--> $DIR/trait-object-lifetime-parens.rs:9:15
21+
|
22+
LL | let _: Box<('a) + Trait>;
23+
| ^^^^^^^^^^^^^^^
24+
|
25+
= help: use `::<...>` instead of `<...>` if you meant to specify type arguments
26+
= help: or use `(...)` if you meant to specify fn arguments
27+
1328
error: expected type, found `'a`
1429
--> $DIR/trait-object-lifetime-parens.rs:9:17
1530
|
@@ -18,5 +33,5 @@ LL | let _: Box<('a) + Trait>;
1833
| |
1934
| while parsing the type for `_`
2035

21-
error: aborting due to 3 previous errors
36+
error: aborting due to 5 previous errors
2237

0 commit comments

Comments
 (0)