syntax: recover trailing |
in or-patterns. · rust-lang/rust@3eba6c1 (original) (raw)
`@@ -18,6 +18,8 @@ type Expected = Option<&'static str>;
`
18
18
`` /// Expected
for function and lambda parameter patterns.
``
19
19
`pub(super) const PARAM_EXPECTED: Expected = Some("parameter name");
`
20
20
``
``
21
`+
const WHILE_PARSING_OR_MSG: &str = "while parsing this or-pattern starting here";
`
``
22
+
21
23
`/// Whether or not an or-pattern should be gated when occurring in the current context.
`
22
24
`#[derive(PartialEq)]
`
23
25
`pub enum GateOr { Yes, No }
`
`@@ -40,7 +42,7 @@ impl<'a> Parser<'a> {
`
40
42
`` /// Corresponds to top_pat
in RFC 2535 and allows or-pattern at the top level.
``
41
43
`pub(super) fn parse_top_pat(&mut self, gate_or: GateOr) -> PResult<'a, P> {
`
42
44
`// Allow a '|' before the pats (RFCs 1925, 2530, and 2535).
`
43
``
`-
let gated_leading_vert = self.eat_or_separator() && gate_or == GateOr::Yes;
`
``
45
`+
let gated_leading_vert = self.eat_or_separator(None) && gate_or == GateOr::Yes;
`
44
46
`let leading_vert_span = self.prev_span;
`
45
47
``
46
48
`// Parse the possibly-or-pattern.
`
`@@ -63,7 +65,7 @@ impl<'a> Parser<'a> {
`
63
65
`/// Parse the pattern for a function or function pointer parameter.
`
64
66
`` /// Special recovery is provided for or-patterns and leading |
.
``
65
67
`pub(super) fn parse_fn_param_pat(&mut self) -> PResult<'a, P> {
`
66
``
`-
self.recover_leading_vert("not allowed in a parameter pattern");
`
``
68
`+
self.recover_leading_vert(None, "not allowed in a parameter pattern");
`
67
69
`let pat = self.parse_pat_with_or(PARAM_EXPECTED, GateOr::No, RecoverComma::No)?;
`
68
70
``
69
71
`if let PatKind::Or(..) = &pat.kind {
`
`@@ -90,7 +92,7 @@ impl<'a> Parser<'a> {
`
90
92
`gate_or: GateOr,
`
91
93
`rc: RecoverComma,
`
92
94
`) -> PResult<'a, P> {
`
93
``
`-
// Parse the first pattern.
`
``
95
`` +
// Parse the first pattern (p_0
).
``
94
96
`let first_pat = self.parse_pat(expected)?;
`
95
97
`self.maybe_recover_unexpected_comma(first_pat.span, rc)?;
`
96
98
``
`@@ -100,11 +102,12 @@ impl<'a> Parser<'a> {
`
100
102
`return Ok(first_pat)
`
101
103
`}
`
102
104
``
``
105
`` +
// Parse the patterns p_1 | ... | p_n
where n > 0
.
``
103
106
`let lo = first_pat.span;
`
104
107
`let mut pats = vec![first_pat];
`
105
``
`-
while self.eat_or_separator() {
`
``
108
`+
while self.eat_or_separator(Some(lo)) {
`
106
109
`let pat = self.parse_pat(expected).map_err(|mut err| {
`
107
``
`-
err.span_label(lo, "while parsing this or-pattern starting here");
`
``
110
`+
err.span_label(lo, WHILE_PARSING_OR_MSG);
`
108
111
` err
`
109
112
`})?;
`
110
113
`self.maybe_recover_unexpected_comma(pat.span, rc)?;
`
`@@ -122,28 +125,65 @@ impl<'a> Parser<'a> {
`
122
125
``
123
126
`` /// Eat the or-pattern |
separator.
``
124
127
`` /// If instead a ||
token is encountered, recover and pretend we parsed |
.
``
125
``
`-
fn eat_or_separator(&mut self) -> bool {
`
``
128
`+
fn eat_or_separator(&mut self, lo: Option) -> bool {
`
``
129
`+
if self.recover_trailing_vert(lo) {
`
``
130
`+
return false;
`
``
131
`+
}
`
``
132
+
126
133
`match self.token.kind {
`
127
134
` token::OrOr => {
`
128
135
`` // Found ||
; Recover and pretend we parsed |
.
``
129
``
`-
self.ban_unexpected_or_or();
`
``
136
`+
self.ban_unexpected_or_or(lo);
`
130
137
`self.bump();
`
131
138
`true
`
132
139
`}
`
133
140
` _ => self.eat(&token::BinOp(token::Or)),
`
134
141
`}
`
135
142
`}
`
136
143
``
``
144
`` +
/// Recover if |
or ||
is the current token and we have one of the
``
``
145
`` +
/// tokens =>
, if
, =
, :
, ;
, ,
, ]
, )
, or }
ahead of us.
``
``
146
`+
///
`
``
147
`+
/// These tokens all indicate that we reached the end of the or-pattern
`
``
148
`` +
/// list and can now reliably say that the |
was an illegal trailing vert.
``
``
149
`` +
/// Note that there are more tokens such as @
for which we know that the |
``
``
150
`+
/// is an illegal parse. However, the user's intent is less clear in that case.
`
``
151
`+
fn recover_trailing_vert(&mut self, lo: Option) -> bool {
`
``
152
`+
let is_end_ahead = self.look_ahead(1, |token| match &token.kind {
`
``
153
`` +
token::FatArrow // e.g. a | => 0,
.
``
``
154
`` +
| token::Ident(kw::If, false) // e.g. a | if expr
.
``
``
155
`` +
| token::Eq // e.g. let a | = 0
.
``
``
156
`` +
| token::Semi // e.g. let a |;
.
``
``
157
`` +
| token::Colon // e.g. let a | :
.
``
``
158
`` +
| token::Comma // e.g. let (a |,)
.
``
``
159
`` +
| token::CloseDelim(token::Bracket) // e.g. let [a | ]
.
``
``
160
`` +
| token::CloseDelim(token::Paren) // e.g. let (a | )
.
``
``
161
`` +
| token::CloseDelim(token::Brace) => true, // e.g. let A { f: a | }
.
``
``
162
`+
_ => false,
`
``
163
`+
});
`
``
164
`+
match (is_end_ahead, &self.token.kind) {
`
``
165
`+
(true, token::BinOp(token::Or)) | (true, token::OrOr) => {
`
``
166
`+
self.ban_illegal_vert(lo, "trailing", "not allowed in an or-pattern");
`
``
167
`+
self.bump();
`
``
168
`+
true
`
``
169
`+
}
`
``
170
`+
_ => false,
`
``
171
`+
}
`
``
172
`+
}
`
``
173
+
137
174
`` /// We have parsed ||
instead of |
. Error and suggest |
instead.
``
138
``
`-
fn ban_unexpected_or_or(&mut self) {
`
139
``
`` -
self.struct_span_err(self.token.span, "unexpected token ||
after pattern")
``
140
``
`-
.span_suggestion(
`
141
``
`-
self.token.span,
`
142
``
`` -
"use a single |
to separate multiple alternative patterns",
``
143
``
`-
"|".to_owned(),
`
144
``
`-
Applicability::MachineApplicable
`
145
``
`-
)
`
146
``
`-
.emit();
`
``
175
`+
fn ban_unexpected_or_or(&mut self, lo: Option) {
`
``
176
`` +
let mut err = self.struct_span_err(self.token.span, "unexpected token ||
after pattern");
``
``
177
`+
err.span_suggestion(
`
``
178
`+
self.token.span,
`
``
179
`` +
"use a single |
to separate multiple alternative patterns",
``
``
180
`+
"|".to_owned(),
`
``
181
`+
Applicability::MachineApplicable
`
``
182
`+
);
`
``
183
`+
if let Some(lo) = lo {
`
``
184
`+
err.span_label(lo, WHILE_PARSING_OR_MSG);
`
``
185
`+
}
`
``
186
`+
err.emit();
`
147
187
`}
`
148
188
``
149
189
`/// Some special error handling for the "top-level" patterns in a match arm,
`
`@@ -198,25 +238,38 @@ impl<'a> Parser<'a> {
`
198
238
`` /// Recursive possibly-or-pattern parser with recovery for an erroneous leading |
.
``
199
239
`` /// See parse_pat_with_or
for details on parsing or-patterns.
``
200
240
`fn parse_pat_with_or_inner(&mut self) -> PResult<'a, P> {
`
201
``
`-
self.recover_leading_vert("only allowed in a top-level pattern");
`
``
241
`+
self.recover_leading_vert(None, "only allowed in a top-level pattern");
`
202
242
`self.parse_pat_with_or(None, GateOr::Yes, RecoverComma::No)
`
203
243
`}
`
204
244
``
205
245
`` /// Recover if |
or ||
is here.
``
206
246
`` /// The user is thinking that a leading |
is allowed in this position.
``
207
``
`-
fn recover_leading_vert(&mut self, ctx: &str) {
`
``
247
`+
fn recover_leading_vert(&mut self, lo: Option, ctx: &str) {
`
208
248
`if let token::BinOp(token::Or) | token::OrOr = self.token.kind {
`
209
``
`-
let span = self.token.span;
`
210
``
`` -
let rm_msg = format!("remove the {}
", pprust::token_to_string(&self.token));
``
211
``
-
212
``
`` -
self.struct_span_err(span, &format!("a leading |
is {}", ctx))
``
213
``
`-
.span_suggestion(span, &rm_msg, String::new(), Applicability::MachineApplicable)
`
214
``
`-
.emit();
`
215
``
-
``
249
`+
self.ban_illegal_vert(lo, "leading", ctx);
`
216
250
`self.bump();
`
217
251
`}
`
218
252
`}
`
219
253
``
``
254
`` +
/// A |
or possibly ||
token shouldn't be here. Ban it.
``
``
255
`+
fn ban_illegal_vert(&mut self, lo: Option, pos: &str, ctx: &str) {
`
``
256
`+
let span = self.token.span;
`
``
257
`` +
let mut err = self.struct_span_err(span, &format!("a {} |
is {}", pos, ctx));
``
``
258
`+
err.span_suggestion(
`
``
259
`+
span,
`
``
260
`` +
&format!("remove the {}
", pprust::token_to_string(&self.token)),
``
``
261
`+
String::new(),
`
``
262
`+
Applicability::MachineApplicable,
`
``
263
`+
);
`
``
264
`+
if let Some(lo) = lo {
`
``
265
`+
err.span_label(lo, WHILE_PARSING_OR_MSG);
`
``
266
`+
}
`
``
267
`+
if let token::OrOr = self.token.kind {
`
``
268
`` +
err.note("alternatives in or-patterns are separated with |
, not ||
");
``
``
269
`+
}
`
``
270
`+
err.emit();
`
``
271
`+
}
`
``
272
+
220
273
`` /// Parses a pattern, with a setting whether modern range patterns (e.g., a..=b
, a..b
are
``
221
274
`/// allowed).
`
222
275
`fn parse_pat_with_range_pat(
`
`@@ -259,7 +312,7 @@ impl<'a> Parser<'a> {
`
259
312
`self.bump();
`
260
313
`self.parse_pat_range_to(RangeEnd::Included(RangeSyntax::DotDotDot), "...")?
`
261
314
`}
`
262
``
`-
// At this point, token != &, &&, (, [
`
``
315
`` +
// At this point, token != &
, &&
, (
, [
, ..
, ..=
, or ...
.
``
263
316
` _ => if self.eat_keyword(kw::Underscore) {
`
264
317
`// Parse _
`
265
318
`PatKind::Wild
`