11use super :: { ForceCollect , Parser , PathStyle , TrailingToken } ;
22use crate :: errors:: {
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 , UnexpectedVertVertBeforeFunctionParam ,
10- UnexpectedVertVertInPattern ,
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 ,
1112} ;
1213use crate :: { maybe_recover_from_interpolated_ty_qpath, maybe_whole} ;
1314use rustc_ast:: mut_visit:: { noop_visit_pat, MutVisitor } ;
@@ -18,7 +19,7 @@ use rustc_ast::{
1819 PatField , PatFieldsRest , PatKind , Path , QSelf , RangeEnd , RangeSyntax ,
1920} ;
2021use rustc_ast_pretty:: pprust;
21- use rustc_errors:: { Applicability , DiagnosticBuilder , PResult } ;
22+ use rustc_errors:: { Applicability , DiagnosticBuilder , MultiSpan , PResult } ;
2223use rustc_session:: errors:: ExprParenthesesNeeded ;
2324use rustc_span:: source_map:: { respan, Spanned } ;
2425use rustc_span:: symbol:: { kw, sym, Ident } ;
@@ -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,28 @@ 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 let Some ( form) = self . may_recover ( ) . then ( || self . parse_range_end ( ) ) =>
604+ {
605+ self . dcx ( ) . emit_err ( UnexpectedParenInRangePat {
606+ span : MultiSpan :: from_spans ( vec ! [ open_paren, close_paren] ) ,
607+ sugg : UnexpectedParenInRangePatSugg {
608+ start_span : open_paren,
609+ end_span : close_paren,
610+ } ,
611+ } ) ;
612+
613+ self . parse_pat_range_begin_with ( begin. clone ( ) , form) ?
614+ }
615+
616+ // (pat) with optional parentheses
617+ _ => PatKind :: Paren ( pat) ,
618+ }
595619 } else {
596620 PatKind :: Tuple ( fields)
597621 } )
@@ -727,6 +751,14 @@ impl<'a> Parser<'a> {
727751 begin : P < Expr > ,
728752 re : Spanned < RangeEnd > ,
729753 ) -> PResult < ' a , PatKind > {
754+ // recover from `(`
755+ let open_paren = ( self . may_recover ( )
756+ && self . token . kind == token:: OpenDelim ( Delimiter :: Parenthesis ) )
757+ . then ( || {
758+ self . bump ( ) ;
759+ self . prev_token . span
760+ } ) ;
761+
730762 let end = if self . is_pat_range_end_start ( 0 ) {
731763 // Parsing e.g. `X..=Y`.
732764 Some ( self . parse_pat_range_end ( ) ?)
@@ -738,6 +770,19 @@ impl<'a> Parser<'a> {
738770 }
739771 None
740772 } ;
773+
774+ if let Some ( span) = open_paren {
775+ self . expect ( & token:: CloseDelim ( Delimiter :: Parenthesis ) ) ?;
776+
777+ self . dcx ( ) . emit_err ( UnexpectedParenInRangePat {
778+ span : MultiSpan :: from_spans ( vec ! [ span, self . prev_token. span] ) ,
779+ sugg : UnexpectedParenInRangePatSugg {
780+ start_span : span,
781+ end_span : self . prev_token . span ,
782+ } ,
783+ } ) ;
784+ }
785+
741786 Ok ( PatKind :: Range ( Some ( begin) , end, re) )
742787 }
743788
@@ -777,11 +822,32 @@ impl<'a> Parser<'a> {
777822 /// The form `...X` is prohibited to reduce confusion with the potential
778823 /// expression syntax `...expr` for splatting in expressions.
779824 fn parse_pat_range_to ( & mut self , mut re : Spanned < RangeEnd > ) -> PResult < ' a , PatKind > {
825+ // recover from `(`
826+ let open_paren = ( self . may_recover ( )
827+ && self . token . kind == token:: OpenDelim ( Delimiter :: Parenthesis ) )
828+ . then ( || {
829+ self . bump ( ) ;
830+ self . prev_token . span
831+ } ) ;
832+
780833 let end = self . parse_pat_range_end ( ) ?;
781834 if let RangeEnd :: Included ( syn @ RangeSyntax :: DotDotDot ) = & mut re. node {
782835 * syn = RangeSyntax :: DotDotEq ;
783836 self . dcx ( ) . emit_err ( DotDotDotRangeToPatternNotAllowed { span : re. span } ) ;
784837 }
838+
839+ if let Some ( span) = open_paren {
840+ self . expect ( & token:: CloseDelim ( Delimiter :: Parenthesis ) ) ?;
841+
842+ self . dcx ( ) . emit_err ( UnexpectedParenInRangePat {
843+ span : MultiSpan :: from_spans ( vec ! [ span, self . prev_token. span] ) ,
844+ sugg : UnexpectedParenInRangePatSugg {
845+ start_span : span,
846+ end_span : self . prev_token . span ,
847+ } ,
848+ } ) ;
849+ }
850+
785851 Ok ( PatKind :: Range ( None , Some ( end) , re) )
786852 }
787853
@@ -794,6 +860,10 @@ impl<'a> Parser<'a> {
794860 || t. can_begin_literal_maybe_minus ( ) // e.g. `42`.
795861 || t. is_whole_expr ( )
796862 || t. is_lifetime ( ) // recover `'a` instead of `'a'`
863+ || ( self . may_recover ( ) // recover leading `(`
864+ && t. kind == token:: OpenDelim ( Delimiter :: Parenthesis )
865+ && self . look_ahead ( dist + 1 , |t| t. kind != token:: OpenDelim ( Delimiter :: Parenthesis ) )
866+ && self . is_pat_range_end_start ( dist + 1 ) )
797867 } )
798868 }
799869
@@ -942,7 +1012,7 @@ impl<'a> Parser<'a> {
9421012
9431013 if self . isnt_pattern_start ( ) {
9441014 let descr = super :: token_descr ( & self . token ) ;
945- self . dcx ( ) . emit_err ( errors :: BoxNotPat {
1015+ self . dcx ( ) . emit_err ( BoxNotPat {
9461016 span : self . token . span ,
9471017 kw : box_span,
9481018 lo : box_span. shrink_to_lo ( ) ,
0 commit comments