Skip to content

Commit 9566efe

Browse files
ShE3pyfmease
andcommitted
Refactor PR #119397 & improve pat range bound paren recovery
Co-authored-by: León Orell Valerian Liehr <[email protected]>
1 parent d114f47 commit 9566efe

File tree

4 files changed

+51
-61
lines changed

4 files changed

+51
-61
lines changed

compiler/rustc_parse/src/errors.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::borrow::Cow;
33
use rustc_ast::token::Token;
44
use rustc_ast::{Path, Visibility};
55
use rustc_errors::{
6-
AddToDiagnostic, Applicability, DiagCtxt, DiagnosticBuilder, IntoDiagnostic, Level, MultiSpan,
6+
AddToDiagnostic, Applicability, DiagCtxt, DiagnosticBuilder, IntoDiagnostic, Level,
77
SubdiagnosticMessage,
88
};
99
use rustc_macros::{Diagnostic, Subdiagnostic};
@@ -2382,7 +2382,7 @@ pub(crate) struct ExpectedCommaAfterPatternField {
23822382
#[diag(parse_unexpected_paren_in_range_pat)]
23832383
pub(crate) struct UnexpectedParenInRangePat {
23842384
#[primary_span]
2385-
pub span: MultiSpan,
2385+
pub span: Vec<Span>,
23862386
#[subdiagnostic]
23872387
pub sugg: UnexpectedParenInRangePatSugg,
23882388
}

compiler/rustc_parse/src/parser/pat.rs

+45-55
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
use super::{ForceCollect, Parser, PathStyle, TrailingToken};
22
use crate::errors::{
3-
AmbiguousRangePattern, BoxNotPat, DotDotDotForRemainingFields,
4-
DotDotDotRangeToPatternNotAllowed, DotDotDotRestPattern, EnumPatternInsteadOfIdentifier,
5-
ExpectedBindingLeftOfAt, ExpectedCommaAfterPatternField,
6-
GenericArgsInPatRequireTurbofishSyntax, InclusiveRangeExtraEquals, InclusiveRangeMatchArrow,
7-
InclusiveRangeNoEnd, InvalidMutInPattern, PatternOnWrongSideOfAt, RefMutOrderIncorrect,
8-
RemoveLet, RepeatedMutInPattern, SwitchRefBoxOrder, TopLevelOrPatternNotAllowed,
9-
TopLevelOrPatternNotAllowedSugg, TrailingVertNotAllowed, UnexpectedLifetimeInPattern,
10-
UnexpectedParenInRangePat, UnexpectedParenInRangePatSugg,
11-
UnexpectedVertVertBeforeFunctionParam, UnexpectedVertVertInPattern,
3+
self, AmbiguousRangePattern, DotDotDotForRemainingFields, DotDotDotRangeToPatternNotAllowed,
4+
DotDotDotRestPattern, EnumPatternInsteadOfIdentifier, ExpectedBindingLeftOfAt,
5+
ExpectedCommaAfterPatternField, GenericArgsInPatRequireTurbofishSyntax,
6+
InclusiveRangeExtraEquals, InclusiveRangeMatchArrow, InclusiveRangeNoEnd, InvalidMutInPattern,
7+
PatternOnWrongSideOfAt, RefMutOrderIncorrect, RemoveLet, RepeatedMutInPattern,
8+
SwitchRefBoxOrder, TopLevelOrPatternNotAllowed, TopLevelOrPatternNotAllowedSugg,
9+
TrailingVertNotAllowed, UnexpectedLifetimeInPattern, UnexpectedParenInRangePat,
10+
UnexpectedParenInRangePatSugg, UnexpectedVertVertBeforeFunctionParam,
11+
UnexpectedVertVertInPattern,
1212
};
1313
use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
1414
use rustc_ast::mut_visit::{noop_visit_pat, MutVisitor};
@@ -19,7 +19,7 @@ use rustc_ast::{
1919
PatField, PatFieldsRest, PatKind, Path, QSelf, RangeEnd, RangeSyntax,
2020
};
2121
use rustc_ast_pretty::pprust;
22-
use rustc_errors::{Applicability, DiagnosticBuilder, MultiSpan, PResult};
22+
use rustc_errors::{Applicability, DiagnosticBuilder, PResult};
2323
use rustc_session::errors::ExprParenthesesNeeded;
2424
use rustc_span::source_map::{respan, Spanned};
2525
use rustc_span::symbol::{kw, sym, Ident};
@@ -604,7 +604,7 @@ impl<'a> Parser<'a> {
604604
&& let Some(form) = self.parse_range_end() =>
605605
{
606606
self.dcx().emit_err(UnexpectedParenInRangePat {
607-
span: MultiSpan::from_spans(vec![open_paren, close_paren]),
607+
span: vec![open_paren, close_paren],
608608
sugg: UnexpectedParenInRangePatSugg {
609609
start_span: open_paren,
610610
end_span: close_paren,
@@ -752,14 +752,6 @@ impl<'a> Parser<'a> {
752752
begin: P<Expr>,
753753
re: Spanned<RangeEnd>,
754754
) -> PResult<'a, PatKind> {
755-
// recover from `(`
756-
let open_paren = (self.may_recover()
757-
&& self.token.kind == token::OpenDelim(Delimiter::Parenthesis))
758-
.then(|| {
759-
self.bump();
760-
self.prev_token.span
761-
});
762-
763755
let end = if self.is_pat_range_end_start(0) {
764756
// Parsing e.g. `X..=Y`.
765757
Some(self.parse_pat_range_end()?)
@@ -771,19 +763,6 @@ impl<'a> Parser<'a> {
771763
}
772764
None
773765
};
774-
775-
if let Some(span) = open_paren {
776-
self.expect(&token::CloseDelim(Delimiter::Parenthesis))?;
777-
778-
self.dcx().emit_err(UnexpectedParenInRangePat {
779-
span: MultiSpan::from_spans(vec![span, self.prev_token.span]),
780-
sugg: UnexpectedParenInRangePatSugg {
781-
start_span: span,
782-
end_span: self.prev_token.span,
783-
},
784-
});
785-
}
786-
787766
Ok(PatKind::Range(Some(begin), end, re))
788767
}
789768

@@ -823,32 +802,11 @@ impl<'a> Parser<'a> {
823802
/// The form `...X` is prohibited to reduce confusion with the potential
824803
/// expression syntax `...expr` for splatting in expressions.
825804
fn parse_pat_range_to(&mut self, mut re: Spanned<RangeEnd>) -> PResult<'a, PatKind> {
826-
// recover from `(`
827-
let open_paren = (self.may_recover()
828-
&& self.token.kind == token::OpenDelim(Delimiter::Parenthesis))
829-
.then(|| {
830-
self.bump();
831-
self.prev_token.span
832-
});
833-
834805
let end = self.parse_pat_range_end()?;
835806
if let RangeEnd::Included(syn @ RangeSyntax::DotDotDot) = &mut re.node {
836807
*syn = RangeSyntax::DotDotEq;
837808
self.dcx().emit_err(DotDotDotRangeToPatternNotAllowed { span: re.span });
838809
}
839-
840-
if let Some(span) = open_paren {
841-
self.expect(&token::CloseDelim(Delimiter::Parenthesis))?;
842-
843-
self.dcx().emit_err(UnexpectedParenInRangePat {
844-
span: MultiSpan::from_spans(vec![span, self.prev_token.span]),
845-
sugg: UnexpectedParenInRangePatSugg {
846-
start_span: span,
847-
end_span: self.prev_token.span,
848-
},
849-
});
850-
}
851-
852810
Ok(PatKind::Range(None, Some(end), re))
853811
}
854812

@@ -868,8 +826,14 @@ impl<'a> Parser<'a> {
868826
})
869827
}
870828

829+
/// Parse a range pattern end bound
871830
fn parse_pat_range_end(&mut self) -> PResult<'a, P<Expr>> {
872-
if self.check_inline_const(0) {
831+
// recover leading `(`
832+
let open_paren = (self.may_recover()
833+
&& self.eat_noexpect(&token::OpenDelim(Delimiter::Parenthesis)))
834+
.then_some(self.prev_token.span);
835+
836+
let bound = if self.check_inline_const(0) {
873837
self.parse_const_block(self.token.span, true)
874838
} else if self.check_path() {
875839
let lo = self.token.span;
@@ -885,6 +849,32 @@ impl<'a> Parser<'a> {
885849
Ok(self.mk_expr(lo.to(hi), ExprKind::Path(qself, path)))
886850
} else {
887851
self.parse_literal_maybe_minus()
852+
};
853+
854+
// recover trailing `)`
855+
if let Some(open_paren) = open_paren {
856+
let bound = bound.map_err(|err| {
857+
// we couldn't parse a bound after the `(`, so cancel the recovery
858+
err.cancel();
859+
self.dcx().struct_span_err(open_paren, "unexpected token: `(`")
860+
})?;
861+
862+
if self.eat_noexpect(&token::CloseDelim(Delimiter::Parenthesis)) {
863+
self.dcx().emit_err(UnexpectedParenInRangePat {
864+
span: vec![open_paren, self.prev_token.span],
865+
sugg: UnexpectedParenInRangePatSugg {
866+
start_span: open_paren,
867+
end_span: self.prev_token.span,
868+
},
869+
});
870+
871+
Ok(bound)
872+
} else {
873+
// the `(bound` is missing its closing `)`, so cancel the recovery
874+
Err(self.dcx().struct_span_err(open_paren, "unexpected token: `(`"))
875+
}
876+
} else {
877+
bound
888878
}
889879
}
890880

@@ -1013,7 +1003,7 @@ impl<'a> Parser<'a> {
10131003

10141004
if self.isnt_pattern_start() {
10151005
let descr = super::token_descr(&self.token);
1016-
self.dcx().emit_err(BoxNotPat {
1006+
self.dcx().emit_err(errors::BoxNotPat {
10171007
span: self.token.span,
10181008
kw: box_span,
10191009
lo: box_span.shrink_to_lo(),

tests/ui/half-open-range-patterns/range_pat_interactions2.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ fn main() {
88
for x in -9 + 1..=(9 - 2) {
99
match x as i32 {
1010
0..=(5+1) => errors_only.push(x),
11-
//~^ error: expected `)`, found `+`
11+
//~^ error: unexpected token: `(`
1212
1 | -3..0 => first_or.push(x),
1313
y @ (0..5 | 6) => or_two.push(y),
1414
y @ 0..const { 5 + 1 } => assert_eq!(y, 5),
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error: expected `)`, found `+`
2-
--> $DIR/range_pat_interactions2.rs:10:19
1+
error: unexpected token: `(`
2+
--> $DIR/range_pat_interactions2.rs:10:17
33
|
44
LL | 0..=(5+1) => errors_only.push(x),
5-
| ^ expected `)`
5+
| ^
66

77
error: aborting due to 1 previous error
88

0 commit comments

Comments
 (0)