@@ -6,7 +6,8 @@ use crate::errors::{
66 InclusiveRangeExtraEquals , InclusiveRangeMatchArrow , InclusiveRangeNoEnd , InvalidMutInPattern ,
77 PatternOnWrongSideOfAt , RefMutOrderIncorrect , RemoveLet , RepeatedMutInPattern ,
88 SwitchRefBoxOrder , TopLevelOrPatternNotAllowed , TopLevelOrPatternNotAllowedSugg ,
9- TrailingVertNotAllowed , UnexpectedLifetimeInPattern , UnexpectedVertVertBeforeFunctionParam ,
9+ TrailingVertNotAllowed , UnexpectedLifetimeInPattern , UnexpectedParenInRangePat ,
10+ UnexpectedParenInRangePatSugg , UnexpectedVertVertBeforeFunctionParam ,
1011 UnexpectedVertVertInPattern ,
1112} ;
1213use crate :: { maybe_recover_from_interpolated_ty_qpath, maybe_whole} ;
@@ -579,6 +580,8 @@ impl<'a> Parser<'a> {
579580
580581 /// Parse a tuple or parenthesis pattern.
581582 fn parse_pat_tuple_or_parens ( & mut self ) -> PResult < ' a , PatKind > {
583+ let open_paren = self . token . span ;
584+
582585 let ( fields, trailing_comma) = self . parse_paren_comma_seq ( |p| {
583586 p. parse_pat_allow_top_alt (
584587 None ,
@@ -591,7 +594,29 @@ impl<'a> Parser<'a> {
591594 // Here, `(pat,)` is a tuple pattern.
592595 // For backward compatibility, `(..)` is a tuple pattern as well.
593596 Ok ( if fields. len ( ) == 1 && !( trailing_comma || fields[ 0 ] . is_rest ( ) ) {
594- PatKind :: Paren ( fields. into_iter ( ) . next ( ) . unwrap ( ) )
597+ let pat = fields. into_iter ( ) . next ( ) . unwrap ( ) ;
598+ let close_paren = self . prev_token . span ;
599+
600+ match & pat. kind {
601+ // recover ranges with parentheses around the `(start)..`
602+ PatKind :: Lit ( begin)
603+ if self . may_recover ( )
604+ && let Some ( form) = self . parse_range_end ( ) =>
605+ {
606+ self . dcx ( ) . emit_err ( UnexpectedParenInRangePat {
607+ span : vec ! [ open_paren, close_paren] ,
608+ sugg : UnexpectedParenInRangePatSugg {
609+ start_span : open_paren,
610+ end_span : close_paren,
611+ } ,
612+ } ) ;
613+
614+ self . parse_pat_range_begin_with ( begin. clone ( ) , form) ?
615+ }
616+
617+ // (pat) with optional parentheses
618+ _ => PatKind :: Paren ( pat) ,
619+ }
595620 } else {
596621 PatKind :: Tuple ( fields)
597622 } )
@@ -794,11 +819,21 @@ impl<'a> Parser<'a> {
794819 || t. can_begin_literal_maybe_minus ( ) // e.g. `42`.
795820 || t. is_whole_expr ( )
796821 || t. is_lifetime ( ) // recover `'a` instead of `'a'`
822+ || ( self . may_recover ( ) // recover leading `(`
823+ && t. kind == token:: OpenDelim ( Delimiter :: Parenthesis )
824+ && self . look_ahead ( dist + 1 , |t| t. kind != token:: OpenDelim ( Delimiter :: Parenthesis ) )
825+ && self . is_pat_range_end_start ( dist + 1 ) )
797826 } )
798827 }
799828
829+ /// Parse a range pattern end bound
800830 fn parse_pat_range_end ( & mut self ) -> PResult < ' a , P < Expr > > {
801- 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 ) {
802837 self . parse_const_block ( self . token . span , true )
803838 } else if self . check_path ( ) {
804839 let lo = self . token . span ;
@@ -814,7 +849,22 @@ impl<'a> Parser<'a> {
814849 Ok ( self . mk_expr ( lo. to ( hi) , ExprKind :: Path ( qself, path) ) )
815850 } else {
816851 self . parse_literal_maybe_minus ( )
852+ } ?;
853+
854+ // recover trailing `)`
855+ if let Some ( open_paren) = open_paren {
856+ self . expect ( & token:: CloseDelim ( Delimiter :: Parenthesis ) ) ?;
857+
858+ self . dcx ( ) . emit_err ( UnexpectedParenInRangePat {
859+ span : vec ! [ open_paren, self . prev_token. span] ,
860+ sugg : UnexpectedParenInRangePatSugg {
861+ start_span : open_paren,
862+ end_span : self . prev_token . span ,
863+ } ,
864+ } ) ;
817865 }
866+
867+ Ok ( bound)
818868 }
819869
820870 /// Is this the start of a pattern beginning with a path?
0 commit comments