Skip to content

Commit 04128be

Browse files
ShE3pyfmease
andcommitted
Refactor PR #119397
Co-authored-by: León Orell Valerian Liehr <[email protected]>
1 parent d114f47 commit 04128be

File tree

4 files changed

+57
-59
lines changed

4 files changed

+57
-59
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

+51-53
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,
@@ -745,24 +745,53 @@ impl<'a> Parser<'a> {
745745
Some(respan(self.prev_token.span, re))
746746
}
747747

748+
/// Parse using `f(self)`, but may eat parentheses before and after calling `f(self)` (and emit an error in this case.)
749+
/// Can trivially be generalized for other [`Delimiter`] and errors other than [`UnexpectedParenInRangePat`] if desired.
750+
fn maybe_recover_paren_around_range_bound<T, F>(&mut self, f: F) -> PResult<'a, T>
751+
where
752+
F: Fn(&mut Parser<'a>) -> PResult<'a, T>,
753+
{
754+
// recover from leading `(`
755+
if self.may_recover() && self.token.kind == token::OpenDelim(Delimiter::Parenthesis) {
756+
let mut snapshot = self.create_snapshot_for_diagnostic();
757+
snapshot.bump();
758+
759+
let open_paren = snapshot.prev_token.span;
760+
let parsed = f(&mut *snapshot)?;
761+
762+
// check for trailing `)`
763+
if snapshot.eat_noexpect(&token::CloseDelim(Delimiter::Parenthesis)) {
764+
self.restore_snapshot(snapshot);
765+
766+
self.dcx().emit_err(UnexpectedParenInRangePat {
767+
span: vec![open_paren, self.prev_token.span],
768+
sugg: UnexpectedParenInRangePatSugg {
769+
start_span: open_paren,
770+
end_span: self.prev_token.span,
771+
},
772+
});
773+
774+
Ok(parsed)
775+
} else {
776+
// `f(snapshot)` parsed something but we're now missing a `)`,
777+
// so just abort the recovery attempt
778+
f(self)
779+
}
780+
} else {
781+
f(self)
782+
}
783+
}
784+
748785
/// Parse a range pattern `$begin $form $end?` where `$form = ".." | "..." | "..=" ;`.
749786
/// `$begin $form` has already been parsed.
750787
fn parse_pat_range_begin_with(
751788
&mut self,
752789
begin: P<Expr>,
753790
re: Spanned<RangeEnd>,
754791
) -> 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-
763792
let end = if self.is_pat_range_end_start(0) {
764793
// Parsing e.g. `X..=Y`.
765-
Some(self.parse_pat_range_end()?)
794+
Some(self.maybe_recover_paren_around_range_bound(|this| this.parse_pat_range_end())?)
766795
} else {
767796
// Parsing e.g. `X..`.
768797
if let RangeEnd::Included(_) = re.node {
@@ -772,18 +801,6 @@ impl<'a> Parser<'a> {
772801
None
773802
};
774803

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-
787804
Ok(PatKind::Range(Some(begin), end, re))
788805
}
789806

@@ -823,32 +840,13 @@ impl<'a> Parser<'a> {
823840
/// The form `...X` is prohibited to reduce confusion with the potential
824841
/// expression syntax `...expr` for splatting in expressions.
825842
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-
});
843+
let end = self.maybe_recover_paren_around_range_bound(|that| that.parse_pat_range_end())?;
833844

834-
let end = self.parse_pat_range_end()?;
835845
if let RangeEnd::Included(syn @ RangeSyntax::DotDotDot) = &mut re.node {
836846
*syn = RangeSyntax::DotDotEq;
837847
self.dcx().emit_err(DotDotDotRangeToPatternNotAllowed { span: re.span });
838848
}
839849

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-
852850
Ok(PatKind::Range(None, Some(end), re))
853851
}
854852

@@ -1013,7 +1011,7 @@ impl<'a> Parser<'a> {
10131011

10141012
if self.isnt_pattern_start() {
10151013
let descr = super::token_descr(&self.token);
1016-
self.dcx().emit_err(BoxNotPat {
1014+
self.dcx().emit_err(errors::BoxNotPat {
10171015
span: self.token.span,
10181016
kw: box_span,
10191017
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)