Skip to content

Commit b205055

Browse files
committed
parser: better recovery for || in inner pats.
1 parent 1ffea18 commit b205055

File tree

3 files changed

+96
-47
lines changed

3 files changed

+96
-47
lines changed

src/libsyntax/parse/parser/pat.rs

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,25 @@ impl<'a> Parser<'a> {
155155
Ok(())
156156
}
157157

158+
/// Recursive possibly-or-pattern parser with recovery for an erroneous leading `|`.
159+
/// See `parse_pat_with_or` for details on parsing or-patterns.
160+
fn parse_pat_with_or_inner(&mut self, expected: Expected) -> PResult<'a, P<Pat>> {
161+
// Recover if `|` or `||` is here.
162+
// The user is thinking that a leading `|` is allowed in this position.
163+
if let token::BinOp(token::Or) | token::OrOr = self.token.kind {
164+
let span = self.token.span;
165+
let rm_msg = format!("remove the `{}`", pprust::token_to_string(&self.token));
166+
167+
self.struct_span_err(span, "a leading `|` is only allowed in a top-level pattern")
168+
.span_suggestion(span, &rm_msg, String::new(), Applicability::MachineApplicable)
169+
.emit();
170+
171+
self.bump();
172+
}
173+
174+
self.parse_pat_with_or(expected, true, false)
175+
}
176+
158177
/// Parses a pattern, with a setting whether modern range patterns (e.g., `a..=b`, `a..b` are
159178
/// allowed).
160179
fn parse_pat_with_range_pat(
@@ -173,7 +192,7 @@ impl<'a> Parser<'a> {
173192
// Parse `[pat, pat,...]` as a slice pattern.
174193
let (pats, _) = self.parse_delim_comma_seq(
175194
token::Bracket,
176-
|p| p.parse_pat_with_or(None, true, false),
195+
|p| p.parse_pat_with_or_inner(None),
177196
)?;
178197
PatKind::Slice(pats)
179198
}
@@ -303,7 +322,7 @@ impl<'a> Parser<'a> {
303322
/// Parse a tuple or parenthesis pattern.
304323
fn parse_pat_tuple_or_parens(&mut self) -> PResult<'a, PatKind> {
305324
let (fields, trailing_comma) = self.parse_paren_comma_seq(|p| {
306-
p.parse_pat_with_or(None, true, false)
325+
p.parse_pat_with_or_inner(None)
307326
})?;
308327

309328
// Here, `(pat,)` is a tuple pattern.
@@ -547,7 +566,7 @@ impl<'a> Parser<'a> {
547566
err.span_label(self.token.span, msg);
548567
return Err(err);
549568
}
550-
let (fields, _) = self.parse_paren_comma_seq(|p| p.parse_pat_with_or(None, true, false))?;
569+
let (fields, _) = self.parse_paren_comma_seq(|p| p.parse_pat_with_or_inner(None))?;
551570
Ok(PatKind::TupleStruct(path, fields))
552571
}
553572

@@ -691,7 +710,7 @@ impl<'a> Parser<'a> {
691710
// Parsing a pattern of the form "fieldname: pat"
692711
let fieldname = self.parse_field_name()?;
693712
self.bump();
694-
let pat = self.parse_pat_with_or(None, true, false)?;
713+
let pat = self.parse_pat_with_or_inner(None)?;
695714
hi = pat.span;
696715
(pat, fieldname, false)
697716
} else {

src/test/ui/or-patterns/or-patterns-syntactic-fail.rs

Lines changed: 16 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -30,27 +30,20 @@ fn no_top_level_or_patterns() {
3030

3131
// We also do not allow a leading `|` when not in a top level position:
3232

33-
#[cfg(FALSE)]
34-
fn no_leading_parens() {
35-
let ( | A | B); //~ ERROR expected pattern, found `|`
36-
}
37-
38-
#[cfg(FALSE)]
39-
fn no_leading_tuple() {
40-
let ( | A | B,); //~ ERROR expected pattern, found `|`
41-
}
42-
43-
#[cfg(FALSE)]
44-
fn no_leading_slice() {
45-
let [ | A | B ]; //~ ERROR expected pattern, found `|`
46-
}
47-
48-
#[cfg(FALSE)]
49-
fn no_leading_tuple_struct() {
50-
let TS( | A | B ); //~ ERROR expected pattern, found `|`
51-
}
52-
53-
#[cfg(FALSE)]
54-
fn no_leading_struct() {
55-
let NS { f: | A | B }; //~ ERROR expected pattern, found `|`
33+
fn no_leading_inner() {
34+
struct TS(E);
35+
struct NS { f: E }
36+
37+
let ( | A | B) = E::A; //~ ERROR a leading `|` is only allowed in a top-level pattern
38+
let ( | A | B,) = (E::B,); //~ ERROR a leading `|` is only allowed in a top-level pattern
39+
let [ | A | B ] = [E::A]; //~ ERROR a leading `|` is only allowed in a top-level pattern
40+
let TS( | A | B ); //~ ERROR a leading `|` is only allowed in a top-level pattern
41+
let NS { f: | A | B }; //~ ERROR a leading `|` is only allowed in a top-level pattern
42+
43+
let ( || A | B) = E::A; //~ ERROR a leading `|` is only allowed in a top-level pattern
44+
let [ || A | B ] = [E::A]; //~ ERROR a leading `|` is only allowed in a top-level pattern
45+
let TS( || A | B ); //~ ERROR a leading `|` is only allowed in a top-level pattern
46+
let NS { f: || A | B }; //~ ERROR a leading `|` is only allowed in a top-level pattern
47+
48+
let recovery_witness: String = 0; //~ ERROR mismatched types
5649
}

src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr

Lines changed: 57 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,35 +4,59 @@ error: expected one of `:` or `@`, found `|`
44
LL | fn fun(A | B: E) {}
55
| ^ expected one of `:` or `@` here
66

7-
error: expected pattern, found `|`
8-
--> $DIR/or-patterns-syntactic-fail.rs:35:11
7+
error: a leading `|` is only allowed in a top-level pattern
8+
--> $DIR/or-patterns-syntactic-fail.rs:37:11
99
|
10-
LL | let ( | A | B);
11-
| ^ expected pattern
10+
LL | let ( | A | B) = E::A;
11+
| ^ help: remove the `|`
1212

13-
error: expected pattern, found `|`
14-
--> $DIR/or-patterns-syntactic-fail.rs:40:11
13+
error: a leading `|` is only allowed in a top-level pattern
14+
--> $DIR/or-patterns-syntactic-fail.rs:38:11
1515
|
16-
LL | let ( | A | B,);
17-
| ^ expected pattern
16+
LL | let ( | A | B,) = (E::B,);
17+
| ^ help: remove the `|`
1818

19-
error: expected pattern, found `|`
20-
--> $DIR/or-patterns-syntactic-fail.rs:45:11
19+
error: a leading `|` is only allowed in a top-level pattern
20+
--> $DIR/or-patterns-syntactic-fail.rs:39:11
2121
|
22-
LL | let [ | A | B ];
23-
| ^ expected pattern
22+
LL | let [ | A | B ] = [E::A];
23+
| ^ help: remove the `|`
2424

25-
error: expected pattern, found `|`
26-
--> $DIR/or-patterns-syntactic-fail.rs:50:13
25+
error: a leading `|` is only allowed in a top-level pattern
26+
--> $DIR/or-patterns-syntactic-fail.rs:40:13
2727
|
2828
LL | let TS( | A | B );
29-
| ^ expected pattern
29+
| ^ help: remove the `|`
3030

31-
error: expected pattern, found `|`
32-
--> $DIR/or-patterns-syntactic-fail.rs:55:17
31+
error: a leading `|` is only allowed in a top-level pattern
32+
--> $DIR/or-patterns-syntactic-fail.rs:41:17
3333
|
3434
LL | let NS { f: | A | B };
35-
| ^ expected pattern
35+
| ^ help: remove the `|`
36+
37+
error: a leading `|` is only allowed in a top-level pattern
38+
--> $DIR/or-patterns-syntactic-fail.rs:43:11
39+
|
40+
LL | let ( || A | B) = E::A;
41+
| ^^ help: remove the `||`
42+
43+
error: a leading `|` is only allowed in a top-level pattern
44+
--> $DIR/or-patterns-syntactic-fail.rs:44:11
45+
|
46+
LL | let [ || A | B ] = [E::A];
47+
| ^^ help: remove the `||`
48+
49+
error: a leading `|` is only allowed in a top-level pattern
50+
--> $DIR/or-patterns-syntactic-fail.rs:45:13
51+
|
52+
LL | let TS( || A | B );
53+
| ^^ help: remove the `||`
54+
55+
error: a leading `|` is only allowed in a top-level pattern
56+
--> $DIR/or-patterns-syntactic-fail.rs:46:17
57+
|
58+
LL | let NS { f: || A | B };
59+
| ^^ help: remove the `||`
3660

3761
error: no rules expected the token `|`
3862
--> $DIR/or-patterns-syntactic-fail.rs:14:15
@@ -70,6 +94,19 @@ LL | let _ = |A | B: E| ();
7094
|
7195
= note: an implementation of `std::ops::BitOr` might be missing for `E`
7296

73-
error: aborting due to 9 previous errors
97+
error[E0308]: mismatched types
98+
--> $DIR/or-patterns-syntactic-fail.rs:48:36
99+
|
100+
LL | let recovery_witness: String = 0;
101+
| ^
102+
| |
103+
| expected struct `std::string::String`, found integer
104+
| help: try using a conversion method: `0.to_string()`
105+
|
106+
= note: expected type `std::string::String`
107+
found type `{integer}`
108+
109+
error: aborting due to 14 previous errors
74110

75-
For more information about this error, try `rustc --explain E0369`.
111+
Some errors have detailed explanations: E0308, E0369.
112+
For more information about an error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)