1
1
use super :: { ForceCollect , Parser , PathStyle , TrailingToken } ;
2
2
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 ,
12
12
} ;
13
13
use crate :: { maybe_recover_from_interpolated_ty_qpath, maybe_whole} ;
14
14
use rustc_ast:: mut_visit:: { noop_visit_pat, MutVisitor } ;
@@ -19,7 +19,7 @@ use rustc_ast::{
19
19
PatField , PatFieldsRest , PatKind , Path , QSelf , RangeEnd , RangeSyntax ,
20
20
} ;
21
21
use rustc_ast_pretty:: pprust;
22
- use rustc_errors:: { Applicability , DiagnosticBuilder , MultiSpan , PResult } ;
22
+ use rustc_errors:: { Applicability , DiagnosticBuilder , PResult } ;
23
23
use rustc_session:: errors:: ExprParenthesesNeeded ;
24
24
use rustc_span:: source_map:: { respan, Spanned } ;
25
25
use rustc_span:: symbol:: { kw, sym, Ident } ;
@@ -604,7 +604,7 @@ impl<'a> Parser<'a> {
604
604
&& let Some ( form) = self . parse_range_end ( ) =>
605
605
{
606
606
self . dcx ( ) . emit_err ( UnexpectedParenInRangePat {
607
- span : MultiSpan :: from_spans ( vec ! [ open_paren, close_paren] ) ,
607
+ span : vec ! [ open_paren, close_paren] ,
608
608
sugg : UnexpectedParenInRangePatSugg {
609
609
start_span : open_paren,
610
610
end_span : close_paren,
@@ -745,24 +745,53 @@ impl<'a> Parser<'a> {
745
745
Some ( respan ( self . prev_token . span , re) )
746
746
}
747
747
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
+
748
785
/// Parse a range pattern `$begin $form $end?` where `$form = ".." | "..." | "..=" ;`.
749
786
/// `$begin $form` has already been parsed.
750
787
fn parse_pat_range_begin_with (
751
788
& mut self ,
752
789
begin : P < Expr > ,
753
790
re : Spanned < RangeEnd > ,
754
791
) -> 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
-
763
792
let end = if self . is_pat_range_end_start ( 0 ) {
764
793
// 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 ( ) ) ?)
766
795
} else {
767
796
// Parsing e.g. `X..`.
768
797
if let RangeEnd :: Included ( _) = re. node {
@@ -772,18 +801,6 @@ impl<'a> Parser<'a> {
772
801
None
773
802
} ;
774
803
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
-
787
804
Ok ( PatKind :: Range ( Some ( begin) , end, re) )
788
805
}
789
806
@@ -823,32 +840,13 @@ impl<'a> Parser<'a> {
823
840
/// The form `...X` is prohibited to reduce confusion with the potential
824
841
/// expression syntax `...expr` for splatting in expressions.
825
842
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 ( ) ) ?;
833
844
834
- let end = self . parse_pat_range_end ( ) ?;
835
845
if let RangeEnd :: Included ( syn @ RangeSyntax :: DotDotDot ) = & mut re. node {
836
846
* syn = RangeSyntax :: DotDotEq ;
837
847
self . dcx ( ) . emit_err ( DotDotDotRangeToPatternNotAllowed { span : re. span } ) ;
838
848
}
839
849
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
-
852
850
Ok ( PatKind :: Range ( None , Some ( end) , re) )
853
851
}
854
852
@@ -1013,7 +1011,7 @@ impl<'a> Parser<'a> {
1013
1011
1014
1012
if self . isnt_pattern_start ( ) {
1015
1013
let descr = super :: token_descr ( & self . token ) ;
1016
- self . dcx ( ) . emit_err ( BoxNotPat {
1014
+ self . dcx ( ) . emit_err ( errors :: BoxNotPat {
1017
1015
span : self . token . span ,
1018
1016
kw : box_span,
1019
1017
lo : box_span. shrink_to_lo ( ) ,
0 commit comments