Skip to content

Commit 2f55354

Browse files
committed
Recover on 'X..' / 'X..=' / 'X...' range patterns.
1 parent 974413f commit 2f55354

File tree

1 file changed

+43
-21
lines changed

1 file changed

+43
-21
lines changed

src/libsyntax/parse/parser.rs

Lines changed: 43 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3737,20 +3737,15 @@ impl<'a> Parser<'a> {
37373737
|| self.token.can_begin_literal_or_bool() // e.g. `42`.
37383738
}
37393739

3740-
// helper function to decide whether to parse as ident binding or to try to do
3741-
// something more complex like range patterns
3740+
// Helper function to decide whether to parse as ident binding
3741+
// or to try to do something more complex like range patterns.
37423742
fn parse_as_ident(&mut self) -> bool {
37433743
self.look_ahead(1, |t| match t.kind {
37443744
token::OpenDelim(token::Paren) | token::OpenDelim(token::Brace) |
3745-
token::DotDotDot | token::DotDotEq | token::ModSep | token::Not => Some(false),
3746-
// ensure slice patterns [a, b.., c] and [a, b, c..] don't go into the
3747-
// range pattern branch
3748-
token::DotDot => None,
3749-
_ => Some(true),
3750-
}).unwrap_or_else(|| self.look_ahead(2, |t| match t.kind {
3751-
token::Comma | token::CloseDelim(token::Bracket) => true,
3752-
_ => false,
3753-
}))
3745+
token::DotDotDot | token::DotDotEq | token::DotDot |
3746+
token::ModSep | token::Not => false,
3747+
_ => true,
3748+
})
37543749
}
37553750

37563751
/// Parse a parentesized comma separated sequence of patterns until `delim` is reached.
@@ -3829,6 +3824,33 @@ impl<'a> Parser<'a> {
38293824
Ok(PatKind::Range(begin, end, respan(lo, re)))
38303825
}
38313826

3827+
/// Parse the end of a `X..Y`, `X..=Y`, or `X...Y` range pattern or recover
3828+
/// if that end is missing treating it as `X..`, `X..=`, or `X...` respectively.
3829+
fn parse_pat_range_end_opt(&mut self, begin: &Expr, form: &str) -> PResult<'a, P<Expr>> {
3830+
if self.is_pat_range_end_start() {
3831+
// Parsing e.g. `X..=Y`.
3832+
self.parse_pat_range_end()
3833+
} else {
3834+
// Parsing e.g. `X..`.
3835+
let range_span = begin.span.to(self.prev_span);
3836+
3837+
self.diagnostic()
3838+
.struct_span_err(
3839+
range_span,
3840+
&format!("`X{}` range patterns are not supported", form),
3841+
)
3842+
.span_suggestion(
3843+
range_span,
3844+
"try using the maximum value for the type",
3845+
format!("{}{}MAX", pprust::expr_to_string(&begin), form),
3846+
Applicability::HasPlaceholders,
3847+
)
3848+
.emit();
3849+
3850+
Ok(self.mk_expr(range_span, ExprKind::Err, ThinVec::new()))
3851+
}
3852+
}
3853+
38323854
/// Parses a pattern, with a setting whether modern range patterns (e.g., `a..=b`, `a..b` are
38333855
/// allowed).
38343856
fn parse_pat_with_range_pat(
@@ -3944,10 +3966,10 @@ impl<'a> Parser<'a> {
39443966
pat = PatKind::Mac(mac);
39453967
}
39463968
token::DotDotDot | token::DotDotEq | token::DotDot => {
3947-
let end_kind = match self.token.kind {
3948-
token::DotDot => RangeEnd::Excluded,
3949-
token::DotDotDot => RangeEnd::Included(RangeSyntax::DotDotDot),
3950-
token::DotDotEq => RangeEnd::Included(RangeSyntax::DotDotEq),
3969+
let (end_kind, form) = match self.token.kind {
3970+
token::DotDot => (RangeEnd::Excluded, ".."),
3971+
token::DotDotDot => (RangeEnd::Included(RangeSyntax::DotDotDot), "..."),
3972+
token::DotDotEq => (RangeEnd::Included(RangeSyntax::DotDotEq), "..="),
39513973
_ => panic!("can only parse `..`/`...`/`..=` for ranges \
39523974
(checked above)"),
39533975
};
@@ -3956,7 +3978,7 @@ impl<'a> Parser<'a> {
39563978
let span = lo.to(self.prev_span);
39573979
let begin = self.mk_expr(span, ExprKind::Path(qself, path), ThinVec::new());
39583980
self.bump();
3959-
let end = self.parse_pat_range_end()?;
3981+
let end = self.parse_pat_range_end_opt(&begin, form)?;
39603982
pat = PatKind::Range(begin, end, respan(op_span, end_kind));
39613983
}
39623984
token::OpenDelim(token::Brace) => {
@@ -3996,17 +4018,17 @@ impl<'a> Parser<'a> {
39964018
let op_span = self.token.span;
39974019
if self.check(&token::DotDot) || self.check(&token::DotDotEq) ||
39984020
self.check(&token::DotDotDot) {
3999-
let end_kind = if self.eat(&token::DotDotDot) {
4000-
RangeEnd::Included(RangeSyntax::DotDotDot)
4021+
let (end_kind, form) = if self.eat(&token::DotDotDot) {
4022+
(RangeEnd::Included(RangeSyntax::DotDotDot), "...")
40014023
} else if self.eat(&token::DotDotEq) {
4002-
RangeEnd::Included(RangeSyntax::DotDotEq)
4024+
(RangeEnd::Included(RangeSyntax::DotDotEq), "..=")
40034025
} else if self.eat(&token::DotDot) {
4004-
RangeEnd::Excluded
4026+
(RangeEnd::Excluded, "..")
40054027
} else {
40064028
panic!("impossible case: we already matched \
40074029
on a range-operator token")
40084030
};
4009-
let end = self.parse_pat_range_end()?;
4031+
let end = self.parse_pat_range_end_opt(&begin, form)?;
40104032
pat = PatKind::Range(begin, end, respan(op_span, end_kind))
40114033
} else {
40124034
pat = PatKind::Lit(begin);

0 commit comments

Comments
 (0)