Skip to content

Commit

Permalink
Refactor PR rust-lang#119397
Browse files Browse the repository at this point in the history
Co-authored-by: León Orell Valerian Liehr <me@fmease.dev>
  • Loading branch information
ShE3py and fmease committed Dec 30, 2023
1 parent d114f47 commit 04128be
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 59 deletions.
4 changes: 2 additions & 2 deletions compiler/rustc_parse/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::borrow::Cow;
use rustc_ast::token::Token;
use rustc_ast::{Path, Visibility};
use rustc_errors::{
AddToDiagnostic, Applicability, DiagCtxt, DiagnosticBuilder, IntoDiagnostic, Level, MultiSpan,
AddToDiagnostic, Applicability, DiagCtxt, DiagnosticBuilder, IntoDiagnostic, Level,
SubdiagnosticMessage,
};
use rustc_macros::{Diagnostic, Subdiagnostic};
Expand Down Expand Up @@ -2382,7 +2382,7 @@ pub(crate) struct ExpectedCommaAfterPatternField {
#[diag(parse_unexpected_paren_in_range_pat)]
pub(crate) struct UnexpectedParenInRangePat {
#[primary_span]
pub span: MultiSpan,
pub span: Vec<Span>,
#[subdiagnostic]
pub sugg: UnexpectedParenInRangePatSugg,
}
Expand Down
104 changes: 51 additions & 53 deletions compiler/rustc_parse/src/parser/pat.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
use super::{ForceCollect, Parser, PathStyle, TrailingToken};
use crate::errors::{
AmbiguousRangePattern, BoxNotPat, DotDotDotForRemainingFields,
DotDotDotRangeToPatternNotAllowed, DotDotDotRestPattern, EnumPatternInsteadOfIdentifier,
ExpectedBindingLeftOfAt, ExpectedCommaAfterPatternField,
GenericArgsInPatRequireTurbofishSyntax, InclusiveRangeExtraEquals, InclusiveRangeMatchArrow,
InclusiveRangeNoEnd, InvalidMutInPattern, PatternOnWrongSideOfAt, RefMutOrderIncorrect,
RemoveLet, RepeatedMutInPattern, SwitchRefBoxOrder, TopLevelOrPatternNotAllowed,
TopLevelOrPatternNotAllowedSugg, TrailingVertNotAllowed, UnexpectedLifetimeInPattern,
UnexpectedParenInRangePat, UnexpectedParenInRangePatSugg,
UnexpectedVertVertBeforeFunctionParam, UnexpectedVertVertInPattern,
self, AmbiguousRangePattern, DotDotDotForRemainingFields, DotDotDotRangeToPatternNotAllowed,
DotDotDotRestPattern, EnumPatternInsteadOfIdentifier, ExpectedBindingLeftOfAt,
ExpectedCommaAfterPatternField, GenericArgsInPatRequireTurbofishSyntax,
InclusiveRangeExtraEquals, InclusiveRangeMatchArrow, InclusiveRangeNoEnd, InvalidMutInPattern,
PatternOnWrongSideOfAt, RefMutOrderIncorrect, RemoveLet, RepeatedMutInPattern,
SwitchRefBoxOrder, TopLevelOrPatternNotAllowed, TopLevelOrPatternNotAllowedSugg,
TrailingVertNotAllowed, UnexpectedLifetimeInPattern, UnexpectedParenInRangePat,
UnexpectedParenInRangePatSugg, UnexpectedVertVertBeforeFunctionParam,
UnexpectedVertVertInPattern,
};
use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
use rustc_ast::mut_visit::{noop_visit_pat, MutVisitor};
Expand All @@ -19,7 +19,7 @@ use rustc_ast::{
PatField, PatFieldsRest, PatKind, Path, QSelf, RangeEnd, RangeSyntax,
};
use rustc_ast_pretty::pprust;
use rustc_errors::{Applicability, DiagnosticBuilder, MultiSpan, PResult};
use rustc_errors::{Applicability, DiagnosticBuilder, PResult};
use rustc_session::errors::ExprParenthesesNeeded;
use rustc_span::source_map::{respan, Spanned};
use rustc_span::symbol::{kw, sym, Ident};
Expand Down Expand Up @@ -604,7 +604,7 @@ impl<'a> Parser<'a> {
&& let Some(form) = self.parse_range_end() =>
{
self.dcx().emit_err(UnexpectedParenInRangePat {
span: MultiSpan::from_spans(vec![open_paren, close_paren]),
span: vec![open_paren, close_paren],
sugg: UnexpectedParenInRangePatSugg {
start_span: open_paren,
end_span: close_paren,
Expand Down Expand Up @@ -745,24 +745,53 @@ impl<'a> Parser<'a> {
Some(respan(self.prev_token.span, re))
}

/// Parse using `f(self)`, but may eat parentheses before and after calling `f(self)` (and emit an error in this case.)
/// Can trivially be generalized for other [`Delimiter`] and errors other than [`UnexpectedParenInRangePat`] if desired.
fn maybe_recover_paren_around_range_bound<T, F>(&mut self, f: F) -> PResult<'a, T>
where
F: Fn(&mut Parser<'a>) -> PResult<'a, T>,
{
// recover from leading `(`
if self.may_recover() && self.token.kind == token::OpenDelim(Delimiter::Parenthesis) {
let mut snapshot = self.create_snapshot_for_diagnostic();
snapshot.bump();

let open_paren = snapshot.prev_token.span;
let parsed = f(&mut *snapshot)?;

// check for trailing `)`
if snapshot.eat_noexpect(&token::CloseDelim(Delimiter::Parenthesis)) {
self.restore_snapshot(snapshot);

self.dcx().emit_err(UnexpectedParenInRangePat {
span: vec![open_paren, self.prev_token.span],
sugg: UnexpectedParenInRangePatSugg {
start_span: open_paren,
end_span: self.prev_token.span,
},
});

Ok(parsed)
} else {
// `f(snapshot)` parsed something but we're now missing a `)`,
// so just abort the recovery attempt
f(self)
}
} else {
f(self)
}
}

/// Parse a range pattern `$begin $form $end?` where `$form = ".." | "..." | "..=" ;`.
/// `$begin $form` has already been parsed.
fn parse_pat_range_begin_with(
&mut self,
begin: P<Expr>,
re: Spanned<RangeEnd>,
) -> PResult<'a, PatKind> {
// recover from `(`
let open_paren = (self.may_recover()
&& self.token.kind == token::OpenDelim(Delimiter::Parenthesis))
.then(|| {
self.bump();
self.prev_token.span
});

let end = if self.is_pat_range_end_start(0) {
// Parsing e.g. `X..=Y`.
Some(self.parse_pat_range_end()?)
Some(self.maybe_recover_paren_around_range_bound(|this| this.parse_pat_range_end())?)
} else {
// Parsing e.g. `X..`.
if let RangeEnd::Included(_) = re.node {
Expand All @@ -772,18 +801,6 @@ impl<'a> Parser<'a> {
None
};

if let Some(span) = open_paren {
self.expect(&token::CloseDelim(Delimiter::Parenthesis))?;

self.dcx().emit_err(UnexpectedParenInRangePat {
span: MultiSpan::from_spans(vec![span, self.prev_token.span]),
sugg: UnexpectedParenInRangePatSugg {
start_span: span,
end_span: self.prev_token.span,
},
});
}

Ok(PatKind::Range(Some(begin), end, re))
}

Expand Down Expand Up @@ -823,32 +840,13 @@ impl<'a> Parser<'a> {
/// The form `...X` is prohibited to reduce confusion with the potential
/// expression syntax `...expr` for splatting in expressions.
fn parse_pat_range_to(&mut self, mut re: Spanned<RangeEnd>) -> PResult<'a, PatKind> {
// recover from `(`
let open_paren = (self.may_recover()
&& self.token.kind == token::OpenDelim(Delimiter::Parenthesis))
.then(|| {
self.bump();
self.prev_token.span
});
let end = self.maybe_recover_paren_around_range_bound(|that| that.parse_pat_range_end())?;

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

if let Some(span) = open_paren {
self.expect(&token::CloseDelim(Delimiter::Parenthesis))?;

self.dcx().emit_err(UnexpectedParenInRangePat {
span: MultiSpan::from_spans(vec![span, self.prev_token.span]),
sugg: UnexpectedParenInRangePatSugg {
start_span: span,
end_span: self.prev_token.span,
},
});
}

Ok(PatKind::Range(None, Some(end), re))
}

Expand Down Expand Up @@ -1013,7 +1011,7 @@ impl<'a> Parser<'a> {

if self.isnt_pattern_start() {
let descr = super::token_descr(&self.token);
self.dcx().emit_err(BoxNotPat {
self.dcx().emit_err(errors::BoxNotPat {
span: self.token.span,
kw: box_span,
lo: box_span.shrink_to_lo(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ fn main() {
for x in -9 + 1..=(9 - 2) {
match x as i32 {
0..=(5+1) => errors_only.push(x),
//~^ error: expected `)`, found `+`
//~^ error: unexpected token: `(`
1 | -3..0 => first_or.push(x),
y @ (0..5 | 6) => or_two.push(y),
y @ 0..const { 5 + 1 } => assert_eq!(y, 5),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
error: expected `)`, found `+`
--> $DIR/range_pat_interactions2.rs:10:19
error: unexpected token: `(`
--> $DIR/range_pat_interactions2.rs:10:17
|
LL | 0..=(5+1) => errors_only.push(x),
| ^ expected `)`
| ^

error: aborting due to 1 previous error

0 comments on commit 04128be

Please sign in to comment.