parser: better recovery for || in inner pats.

This commit is contained in:
Mazdak Farrokhzad 2019-08-19 02:40:24 +02:00
parent 1ffea18ddb
commit b205055c7b
3 changed files with 93 additions and 44 deletions

View file

@ -155,6 +155,25 @@ impl<'a> Parser<'a> {
Ok(())
}
/// Recursive possibly-or-pattern parser with recovery for an erroneous leading `|`.
/// See `parse_pat_with_or` for details on parsing or-patterns.
fn parse_pat_with_or_inner(&mut self, expected: Expected) -> PResult<'a, P<Pat>> {
// Recover if `|` or `||` is here.
// The user is thinking that a leading `|` is allowed in this position.
if let token::BinOp(token::Or) | token::OrOr = self.token.kind {
let span = self.token.span;
let rm_msg = format!("remove the `{}`", pprust::token_to_string(&self.token));
self.struct_span_err(span, "a leading `|` is only allowed in a top-level pattern")
.span_suggestion(span, &rm_msg, String::new(), Applicability::MachineApplicable)
.emit();
self.bump();
}
self.parse_pat_with_or(expected, true, false)
}
/// Parses a pattern, with a setting whether modern range patterns (e.g., `a..=b`, `a..b` are
/// allowed).
fn parse_pat_with_range_pat(
@ -173,7 +192,7 @@ impl<'a> Parser<'a> {
// Parse `[pat, pat,...]` as a slice pattern.
let (pats, _) = self.parse_delim_comma_seq(
token::Bracket,
|p| p.parse_pat_with_or(None, true, false),
|p| p.parse_pat_with_or_inner(None),
)?;
PatKind::Slice(pats)
}
@ -303,7 +322,7 @@ impl<'a> Parser<'a> {
/// Parse a tuple or parenthesis pattern.
fn parse_pat_tuple_or_parens(&mut self) -> PResult<'a, PatKind> {
let (fields, trailing_comma) = self.parse_paren_comma_seq(|p| {
p.parse_pat_with_or(None, true, false)
p.parse_pat_with_or_inner(None)
})?;
// Here, `(pat,)` is a tuple pattern.
@ -547,7 +566,7 @@ impl<'a> Parser<'a> {
err.span_label(self.token.span, msg);
return Err(err);
}
let (fields, _) = self.parse_paren_comma_seq(|p| p.parse_pat_with_or(None, true, false))?;
let (fields, _) = self.parse_paren_comma_seq(|p| p.parse_pat_with_or_inner(None))?;
Ok(PatKind::TupleStruct(path, fields))
}
@ -691,7 +710,7 @@ impl<'a> Parser<'a> {
// Parsing a pattern of the form "fieldname: pat"
let fieldname = self.parse_field_name()?;
self.bump();
let pat = self.parse_pat_with_or(None, true, false)?;
let pat = self.parse_pat_with_or_inner(None)?;
hi = pat.span;
(pat, fieldname, false)
} else {

View file

@ -30,27 +30,20 @@ fn no_top_level_or_patterns() {
// We also do not allow a leading `|` when not in a top level position:
#[cfg(FALSE)]
fn no_leading_parens() {
let ( | A | B); //~ ERROR expected pattern, found `|`
}
fn no_leading_inner() {
struct TS(E);
struct NS { f: E }
#[cfg(FALSE)]
fn no_leading_tuple() {
let ( | A | B,); //~ ERROR expected pattern, found `|`
}
let ( | A | B) = E::A; //~ ERROR a leading `|` is only allowed in a top-level pattern
let ( | A | B,) = (E::B,); //~ ERROR a leading `|` is only allowed in a top-level pattern
let [ | A | B ] = [E::A]; //~ ERROR a leading `|` is only allowed in a top-level pattern
let TS( | A | B ); //~ ERROR a leading `|` is only allowed in a top-level pattern
let NS { f: | A | B }; //~ ERROR a leading `|` is only allowed in a top-level pattern
#[cfg(FALSE)]
fn no_leading_slice() {
let [ | A | B ]; //~ ERROR expected pattern, found `|`
}
let ( || A | B) = E::A; //~ ERROR a leading `|` is only allowed in a top-level pattern
let [ || A | B ] = [E::A]; //~ ERROR a leading `|` is only allowed in a top-level pattern
let TS( || A | B ); //~ ERROR a leading `|` is only allowed in a top-level pattern
let NS { f: || A | B }; //~ ERROR a leading `|` is only allowed in a top-level pattern
#[cfg(FALSE)]
fn no_leading_tuple_struct() {
let TS( | A | B ); //~ ERROR expected pattern, found `|`
}
#[cfg(FALSE)]
fn no_leading_struct() {
let NS { f: | A | B }; //~ ERROR expected pattern, found `|`
let recovery_witness: String = 0; //~ ERROR mismatched types
}

View file

@ -4,35 +4,59 @@ error: expected one of `:` or `@`, found `|`
LL | fn fun(A | B: E) {}
| ^ expected one of `:` or `@` here
error: expected pattern, found `|`
--> $DIR/or-patterns-syntactic-fail.rs:35:11
error: a leading `|` is only allowed in a top-level pattern
--> $DIR/or-patterns-syntactic-fail.rs:37:11
|
LL | let ( | A | B);
| ^ expected pattern
LL | let ( | A | B) = E::A;
| ^ help: remove the `|`
error: expected pattern, found `|`
--> $DIR/or-patterns-syntactic-fail.rs:40:11
error: a leading `|` is only allowed in a top-level pattern
--> $DIR/or-patterns-syntactic-fail.rs:38:11
|
LL | let ( | A | B,);
| ^ expected pattern
LL | let ( | A | B,) = (E::B,);
| ^ help: remove the `|`
error: expected pattern, found `|`
--> $DIR/or-patterns-syntactic-fail.rs:45:11
error: a leading `|` is only allowed in a top-level pattern
--> $DIR/or-patterns-syntactic-fail.rs:39:11
|
LL | let [ | A | B ];
| ^ expected pattern
LL | let [ | A | B ] = [E::A];
| ^ help: remove the `|`
error: expected pattern, found `|`
--> $DIR/or-patterns-syntactic-fail.rs:50:13
error: a leading `|` is only allowed in a top-level pattern
--> $DIR/or-patterns-syntactic-fail.rs:40:13
|
LL | let TS( | A | B );
| ^ expected pattern
| ^ help: remove the `|`
error: expected pattern, found `|`
--> $DIR/or-patterns-syntactic-fail.rs:55:17
error: a leading `|` is only allowed in a top-level pattern
--> $DIR/or-patterns-syntactic-fail.rs:41:17
|
LL | let NS { f: | A | B };
| ^ expected pattern
| ^ help: remove the `|`
error: a leading `|` is only allowed in a top-level pattern
--> $DIR/or-patterns-syntactic-fail.rs:43:11
|
LL | let ( || A | B) = E::A;
| ^^ help: remove the `||`
error: a leading `|` is only allowed in a top-level pattern
--> $DIR/or-patterns-syntactic-fail.rs:44:11
|
LL | let [ || A | B ] = [E::A];
| ^^ help: remove the `||`
error: a leading `|` is only allowed in a top-level pattern
--> $DIR/or-patterns-syntactic-fail.rs:45:13
|
LL | let TS( || A | B );
| ^^ help: remove the `||`
error: a leading `|` is only allowed in a top-level pattern
--> $DIR/or-patterns-syntactic-fail.rs:46:17
|
LL | let NS { f: || A | B };
| ^^ help: remove the `||`
error: no rules expected the token `|`
--> $DIR/or-patterns-syntactic-fail.rs:14:15
@ -70,6 +94,19 @@ LL | let _ = |A | B: E| ();
|
= note: an implementation of `std::ops::BitOr` might be missing for `E`
error: aborting due to 9 previous errors
error[E0308]: mismatched types
--> $DIR/or-patterns-syntactic-fail.rs:48:36
|
LL | let recovery_witness: String = 0;
| ^
| |
| expected struct `std::string::String`, found integer
| help: try using a conversion method: `0.to_string()`
|
= note: expected type `std::string::String`
found type `{integer}`
For more information about this error, try `rustc --explain E0369`.
error: aborting due to 14 previous errors
Some errors have detailed explanations: E0308, E0369.
For more information about an error, try `rustc --explain E0308`.