Skip to content

Commit 036c683

Browse files
committed
Recover on 'X..' / 'X..=' / 'X...' range patterns.
1 parent cde05d3 commit 036c683

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
@@ -3736,20 +3736,15 @@ impl<'a> Parser<'a> {
37363736
|| self.token.can_begin_literal_or_bool() // e.g. `42`.
37373737
}
37383738

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

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

3826+
/// Parse the end of a `X..Y`, `X..=Y`, or `X...Y` range pattern or recover
3827+
/// if that end is missing treating it as `X..`, `X..=`, or `X...` respectively.
3828+
fn parse_pat_range_end_opt(&mut self, begin: &Expr, form: &str) -> PResult<'a, P<Expr>> {
3829+
if self.is_pat_range_end_start() {
3830+
// Parsing e.g. `X..=Y`.
3831+
self.parse_pat_range_end()
3832+
} else {
3833+
// Parsing e.g. `X..`.
3834+
let range_span = begin.span.to(self.prev_span);
3835+
3836+
self.diagnostic()
3837+
.struct_span_err(
3838+
range_span,
3839+
&format!("`X{}` range patterns are not supported", form),
3840+
)
3841+
.span_suggestion(
3842+
range_span,
3843+
"try using the maximum value for the type",
3844+
format!("{}{}MAX", pprust::expr_to_string(&begin), form),
3845+
Applicability::HasPlaceholders,
3846+
)
3847+
.emit();
3848+
3849+
Ok(self.mk_expr(range_span, ExprKind::Err, ThinVec::new()))
3850+
}
3851+
}
3852+
38313853
/// Parses a pattern, with a setting whether modern range patterns (e.g., `a..=b`, `a..b` are
38323854
/// allowed).
38333855
fn parse_pat_with_range_pat(
@@ -3943,10 +3965,10 @@ impl<'a> Parser<'a> {
39433965
pat = PatKind::Mac(mac);
39443966
}
39453967
token::DotDotDot | token::DotDotEq | token::DotDot => {
3946-
let end_kind = match self.token.kind {
3947-
token::DotDot => RangeEnd::Excluded,
3948-
token::DotDotDot => RangeEnd::Included(RangeSyntax::DotDotDot),
3949-
token::DotDotEq => RangeEnd::Included(RangeSyntax::DotDotEq),
3968+
let (end_kind, form) = match self.token.kind {
3969+
token::DotDot => (RangeEnd::Excluded, ".."),
3970+
token::DotDotDot => (RangeEnd::Included(RangeSyntax::DotDotDot), "..."),
3971+
token::DotDotEq => (RangeEnd::Included(RangeSyntax::DotDotEq), "..="),
39503972
_ => panic!("can only parse `..`/`...`/`..=` for ranges \
39513973
(checked above)"),
39523974
};
@@ -3955,7 +3977,7 @@ impl<'a> Parser<'a> {
39553977
let span = lo.to(self.prev_span);
39563978
let begin = self.mk_expr(span, ExprKind::Path(qself, path), ThinVec::new());
39573979
self.bump();
3958-
let end = self.parse_pat_range_end()?;
3980+
let end = self.parse_pat_range_end_opt(&begin, form)?;
39593981
pat = PatKind::Range(begin, end, respan(op_span, end_kind));
39603982
}
39613983
token::OpenDelim(token::Brace) => {
@@ -3995,17 +4017,17 @@ impl<'a> Parser<'a> {
39954017
let op_span = self.token.span;
39964018
if self.check(&token::DotDot) || self.check(&token::DotDotEq) ||
39974019
self.check(&token::DotDotDot) {
3998-
let end_kind = if self.eat(&token::DotDotDot) {
3999-
RangeEnd::Included(RangeSyntax::DotDotDot)
4020+
let (end_kind, form) = if self.eat(&token::DotDotDot) {
4021+
(RangeEnd::Included(RangeSyntax::DotDotDot), "...")
40004022
} else if self.eat(&token::DotDotEq) {
4001-
RangeEnd::Included(RangeSyntax::DotDotEq)
4023+
(RangeEnd::Included(RangeSyntax::DotDotEq), "..=")
40024024
} else if self.eat(&token::DotDot) {
4003-
RangeEnd::Excluded
4025+
(RangeEnd::Excluded, "..")
40044026
} else {
40054027
panic!("impossible case: we already matched \
40064028
on a range-operator token")
40074029
};
4008-
let end = self.parse_pat_range_end()?;
4030+
let end = self.parse_pat_range_end_opt(&begin, form)?;
40094031
pat = PatKind::Range(begin, end, respan(op_span, end_kind))
40104032
} else {
40114033
pat = PatKind::Lit(begin);

0 commit comments

Comments
 (0)