Skip to content

Commit

Permalink
Rollup merge of rust-lang#59453 - estebank:recover-tuple-parse, r=pet…
Browse files Browse the repository at this point in the history
…rochenkov

Recover from parse error in tuple syntax
  • Loading branch information
Centril authored Mar 30, 2019
2 parents d050a15 + 3592079 commit c28704c
Show file tree
Hide file tree
Showing 13 changed files with 228 additions and 34 deletions.
83 changes: 57 additions & 26 deletions src/libsyntax/parse/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2626,7 +2626,13 @@ impl<'a> Parser<'a> {
let mut trailing_comma = false;
let mut recovered = false;
while self.token != token::CloseDelim(token::Paren) {
es.push(self.parse_expr()?);
es.push(match self.parse_expr() {
Ok(es) => es,
Err(err) => {
// recover from parse error in tuple list
return Ok(self.recover_seq_parse_error(token::Paren, lo, Err(err)));
}
});
recovered = self.expect_one_of(
&[],
&[token::Comma, token::CloseDelim(token::Paren)],
Expand Down Expand Up @@ -3237,36 +3243,54 @@ impl<'a> Parser<'a> {
}
if self.expr_is_complete(&e) { break; }
match self.token {
// expr(...)
token::OpenDelim(token::Paren) => {
let es = self.parse_unspanned_seq(
&token::OpenDelim(token::Paren),
&token::CloseDelim(token::Paren),
SeqSep::trailing_allowed(token::Comma),
|p| Ok(p.parse_expr()?)
)?;
hi = self.prev_span;

let nd = self.mk_call(e, es);
e = self.mk_expr(lo.to(hi), nd, ThinVec::new());
}
// expr(...)
token::OpenDelim(token::Paren) => {
let seq = self.parse_unspanned_seq(
&token::OpenDelim(token::Paren),
&token::CloseDelim(token::Paren),
SeqSep::trailing_allowed(token::Comma),
|p| Ok(p.parse_expr()?)
).map(|es| {
let nd = self.mk_call(e, es);
let hi = self.prev_span;
self.mk_expr(lo.to(hi), nd, ThinVec::new())
});
e = self.recover_seq_parse_error(token::Paren, lo, seq);
}

// expr[...]
// Could be either an index expression or a slicing expression.
token::OpenDelim(token::Bracket) => {
self.bump();
let ix = self.parse_expr()?;
hi = self.span;
self.expect(&token::CloseDelim(token::Bracket))?;
let index = self.mk_index(e, ix);
e = self.mk_expr(lo.to(hi), index, ThinVec::new())
}
_ => return Ok(e)
// expr[...]
// Could be either an index expression or a slicing expression.
token::OpenDelim(token::Bracket) => {
self.bump();
let ix = self.parse_expr()?;
hi = self.span;
self.expect(&token::CloseDelim(token::Bracket))?;
let index = self.mk_index(e, ix);
e = self.mk_expr(lo.to(hi), index, ThinVec::new())
}
_ => return Ok(e)
}
}
return Ok(e);
}

fn recover_seq_parse_error(
&mut self,
delim: token::DelimToken,
lo: Span,
result: PResult<'a, P<Expr>>,
) -> P<Expr> {
match result {
Ok(x) => x,
Err(mut err) => {
err.emit();
// recover from parse error
self.consume_block(delim);
self.mk_expr(lo.to(self.prev_span), ExprKind::Err, ThinVec::new())
}
}
}

crate fn process_potential_macro_variable(&mut self) {
let (token, span) = match self.token {
token::Dollar if self.span.ctxt() != syntax_pos::hygiene::SyntaxContext::empty() &&
Expand Down Expand Up @@ -4253,7 +4277,14 @@ impl<'a> Parser<'a> {
// Trailing commas are significant because (p) and (p,) are different patterns.
fn parse_parenthesized_pat_list(&mut self) -> PResult<'a, (Vec<P<Pat>>, Option<usize>, bool)> {
self.expect(&token::OpenDelim(token::Paren))?;
let result = self.parse_pat_list()?;
let result = match self.parse_pat_list() {
Ok(result) => result,
Err(mut err) => { // recover from parse error in tuple pattern list
err.emit();
self.consume_block(token::Paren);
return Ok((vec![], Some(0), false));
}
};
self.expect(&token::CloseDelim(token::Paren))?;
Ok(result)
}
Expand Down
8 changes: 7 additions & 1 deletion src/test/ui/issues/issue-34334.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
fn main () {
let sr: Vec<(u32, _, _) = vec![]; //~ ERROR expected one of `,` or `>`, found `=`
let sr: Vec<(u32, _, _) = vec![];
//~^ ERROR expected one of `,` or `>`, found `=`
//~| ERROR expected value, found struct `Vec`
//~| ERROR mismatched types
//~| ERROR invalid left-hand side expression
//~| ERROR expected expression, found reserved identifier `_`
let sr2: Vec<(u32, _, _)> = sr.iter().map(|(faction, th_sender, th_receiver)| {}).collect();
//~^ ERROR no method named `iter` found for type `()` in the current scope
}
43 changes: 40 additions & 3 deletions src/test/ui/issues/issue-34334.stderr
Original file line number Diff line number Diff line change
@@ -1,10 +1,47 @@
error: expected expression, found reserved identifier `_`
--> $DIR/issue-34334.rs:2:23
|
LL | let sr: Vec<(u32, _, _) = vec![];
| ^ expected expression

error: expected one of `,` or `>`, found `=`
--> $DIR/issue-34334.rs:2:29
|
LL | let sr: Vec<(u32, _, _) = vec![];
| -- ^ expected one of `,` or `>` here
| |
| --- ^ expected one of `,` or `>` here
| | |
| | help: use `=` if you meant to assign
| while parsing the type for `sr`

error: aborting due to previous error
error[E0423]: expected value, found struct `Vec`
--> $DIR/issue-34334.rs:2:13
|
LL | let sr: Vec<(u32, _, _) = vec![];
| ^^^ did you mean `Vec { /* fields */ }`?

error[E0308]: mismatched types
--> $DIR/issue-34334.rs:2:31
|
LL | let sr: Vec<(u32, _, _) = vec![];
| ^^^^^^ expected bool, found struct `std::vec::Vec`
|
= note: expected type `bool`
found type `std::vec::Vec<_>`
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)

error[E0070]: invalid left-hand side expression
--> $DIR/issue-34334.rs:2:13
|
LL | let sr: Vec<(u32, _, _) = vec![];
| ^^^^^^^^^^^^^^^^^^^^^^^^ left-hand of expression not valid

error[E0599]: no method named `iter` found for type `()` in the current scope
--> $DIR/issue-34334.rs:8:36
|
LL | let sr2: Vec<(u32, _, _)> = sr.iter().map(|(faction, th_sender, th_receiver)| {}).collect();
| ^^^^

error: aborting due to 6 previous errors

Some errors occurred: E0070, E0308, E0423, E0599.
For more information about an error, try `rustc --explain E0070`.
2 changes: 1 addition & 1 deletion src/test/ui/parser/pat-tuple-1.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
fn main() {
match 0 {
match (0, 1) {
(, ..) => {} //~ ERROR expected pattern, found `,`
}
}
2 changes: 1 addition & 1 deletion src/test/ui/parser/pat-tuple-5.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
fn main() {
match 0 {
match (0, 1) {
(pat ..) => {} //~ ERROR unexpected token: `)`
}
}
14 changes: 14 additions & 0 deletions src/test/ui/parser/recover-from-bad-variant.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
enum Enum {
Foo { a: usize, b: usize },
Bar(usize, usize),
}

fn main() {
let x = Enum::Foo(a: 3, b: 4);
//~^ ERROR expected type, found `3`
match x {
Enum::Foo(a, b) => {}
//~^ ERROR expected tuple struct/variant, found struct variant `Enum::Foo`
Enum::Bar(a, b) => {}
}
}
23 changes: 23 additions & 0 deletions src/test/ui/parser/recover-from-bad-variant.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
error: expected type, found `3`
--> $DIR/recover-from-bad-variant.rs:7:26
|
LL | let x = Enum::Foo(a: 3, b: 4);
| ^ expecting a type here because of type ascription
|
= note: type ascription is a nightly-only feature that lets you annotate an expression with a type: `<expr>: <type>`
note: this expression expects an ascribed type after the colon
--> $DIR/recover-from-bad-variant.rs:7:23
|
LL | let x = Enum::Foo(a: 3, b: 4);
| ^
= help: this might be indicative of a syntax error elsewhere

error[E0532]: expected tuple struct/variant, found struct variant `Enum::Foo`
--> $DIR/recover-from-bad-variant.rs:10:9
|
LL | Enum::Foo(a, b) => {}
| ^^^^^^^^^ did you mean `Enum::Foo { /* fields */ }`?

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0532`.
12 changes: 12 additions & 0 deletions src/test/ui/parser/recover-tuple-pat.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
fn main() {
let x = (1, 2, 3, 4);
match x {
(1, .., 4) => {}
(1, .=., 4) => { let _: usize = ""; }
//~^ ERROR expected pattern, found `.`
//~| ERROR mismatched types
(.=., 4) => {}
//~^ ERROR expected pattern, found `.`
(1, 2, 3, 4) => {}
}
}
24 changes: 24 additions & 0 deletions src/test/ui/parser/recover-tuple-pat.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
error: expected pattern, found `.`
--> $DIR/recover-tuple-pat.rs:5:13
|
LL | (1, .=., 4) => { let _: usize = ""; }
| ^ expected pattern

error: expected pattern, found `.`
--> $DIR/recover-tuple-pat.rs:8:10
|
LL | (.=., 4) => {}
| ^ expected pattern

error[E0308]: mismatched types
--> $DIR/recover-tuple-pat.rs:5:41
|
LL | (1, .=., 4) => { let _: usize = ""; }
| ^^ expected usize, found reference
|
= note: expected type `usize`
found type `&'static str`

error: aborting due to 3 previous errors

For more information about this error, try `rustc --explain E0308`.
11 changes: 11 additions & 0 deletions src/test/ui/parser/recover-tuple.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
fn main() {
// no complaints about the tuple not matching the expected type
let x: (usize, usize, usize) = (3, .=.);
//~^ ERROR expected expression, found `.`
// verify that the parser recovers:
let y: usize = ""; //~ ERROR mismatched types
// no complaints about the type
foo(x);
}

fn foo(_: (usize, usize, usize)) {}
18 changes: 18 additions & 0 deletions src/test/ui/parser/recover-tuple.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
error: expected expression, found `.`
--> $DIR/recover-tuple.rs:3:40
|
LL | let x: (usize, usize, usize) = (3, .=.);
| ^ expected expression

error[E0308]: mismatched types
--> $DIR/recover-tuple.rs:6:20
|
LL | let y: usize = "";
| ^^ expected usize, found reference
|
= note: expected type `usize`
found type `&'static str`

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0308`.
5 changes: 4 additions & 1 deletion src/test/ui/parser/trait-object-lifetime-parens.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ fn f<'a, T: Trait + ('a)>() {} //~ ERROR parenthesized lifetime bounds are not s

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

fn main() {}
17 changes: 16 additions & 1 deletion src/test/ui/parser/trait-object-lifetime-parens.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,21 @@ error: parenthesized lifetime bounds are not supported
LL | let _: Box<Trait + ('a)>;
| ^^^^ help: remove the parentheses

error: expected `:`, found `)`
--> $DIR/trait-object-lifetime-parens.rs:9:19
|
LL | let _: Box<('a) + Trait>;
| ^ expected `:`

error: chained comparison operators require parentheses
--> $DIR/trait-object-lifetime-parens.rs:9:15
|
LL | let _: Box<('a) + Trait>;
| ^^^^^^^^^^^^^^^
|
= help: use `::<...>` instead of `<...>` if you meant to specify type arguments
= help: or use `(...)` if you meant to specify fn arguments

error: expected type, found `'a`
--> $DIR/trait-object-lifetime-parens.rs:9:17
|
Expand All @@ -18,5 +33,5 @@ LL | let _: Box<('a) + Trait>;
| |
| while parsing the type for `_`

error: aborting due to 3 previous errors
error: aborting due to 5 previous errors

0 comments on commit c28704c

Please sign in to comment.