@@ -10,7 +10,7 @@ use super::{
1010use crate :: errors;
1111use crate :: maybe_recover_from_interpolated_ty_qpath;
1212use ast:: mut_visit:: { noop_visit_expr, MutVisitor } ;
13- use ast:: { GenBlockKind , Path , PathSegment } ;
13+ use ast:: { GenBlockKind , Pat , Path , PathSegment } ;
1414use core:: mem;
1515use rustc_ast:: ptr:: P ;
1616use rustc_ast:: token:: { self , Delimiter , Token , TokenKind } ;
@@ -2856,47 +2856,10 @@ impl<'a> Parser<'a> {
28562856 }
28572857
28582858 pub ( super ) fn parse_arm ( & mut self ) -> PResult < ' a , Arm > {
2859- // Used to check the `let_chains` and `if_let_guard` features mostly by scanning
2860- // `&&` tokens.
2861- fn check_let_expr ( expr : & Expr ) -> ( bool , bool ) {
2862- match & expr. kind {
2863- ExprKind :: Binary ( BinOp { node : BinOpKind :: And , .. } , lhs, rhs) => {
2864- let lhs_rslt = check_let_expr ( lhs) ;
2865- let rhs_rslt = check_let_expr ( rhs) ;
2866- ( lhs_rslt. 0 || rhs_rslt. 0 , false )
2867- }
2868- ExprKind :: Let ( ..) => ( true , true ) ,
2869- _ => ( false , true ) ,
2870- }
2871- }
28722859 let attrs = self . parse_outer_attributes ( ) ?;
28732860 self . collect_tokens_trailing_token ( attrs, ForceCollect :: No , |this, attrs| {
28742861 let lo = this. token . span ;
2875- let pat = this. parse_pat_allow_top_alt (
2876- None ,
2877- RecoverComma :: Yes ,
2878- RecoverColon :: Yes ,
2879- CommaRecoveryMode :: EitherTupleOrPipe ,
2880- ) ?;
2881- let guard = if this. eat_keyword ( kw:: If ) {
2882- let if_span = this. prev_token . span ;
2883- let mut cond = this. parse_match_guard_condition ( ) ?;
2884-
2885- CondChecker :: new ( this) . visit_expr ( & mut cond) ;
2886-
2887- let ( has_let_expr, does_not_have_bin_op) = check_let_expr ( & cond) ;
2888- if has_let_expr {
2889- if does_not_have_bin_op {
2890- // Remove the last feature gating of a `let` expression since it's stable.
2891- this. sess . gated_spans . ungate_last ( sym:: let_chains, cond. span ) ;
2892- }
2893- let span = if_span. to ( cond. span ) ;
2894- this. sess . gated_spans . gate ( sym:: if_let_guard, span) ;
2895- }
2896- Some ( cond)
2897- } else {
2898- None
2899- } ;
2862+ let ( pat, guard) = this. parse_match_arm_pat_and_guard ( ) ?;
29002863 let arrow_span = this. token . span ;
29012864 if let Err ( mut err) = this. expect ( & token:: FatArrow ) {
29022865 // We might have a `=>` -> `=` or `->` typo (issue #89396).
@@ -3026,6 +2989,90 @@ impl<'a> Parser<'a> {
30262989 } )
30272990 }
30282991
2992+ fn parse_match_arm_guard ( & mut self ) -> PResult < ' a , Option < P < Expr > > > {
2993+ // Used to check the `let_chains` and `if_let_guard` features mostly by scanning
2994+ // `&&` tokens.
2995+ fn check_let_expr ( expr : & Expr ) -> ( bool , bool ) {
2996+ match & expr. kind {
2997+ ExprKind :: Binary ( BinOp { node : BinOpKind :: And , .. } , lhs, rhs) => {
2998+ let lhs_rslt = check_let_expr ( lhs) ;
2999+ let rhs_rslt = check_let_expr ( rhs) ;
3000+ ( lhs_rslt. 0 || rhs_rslt. 0 , false )
3001+ }
3002+ ExprKind :: Let ( ..) => ( true , true ) ,
3003+ _ => ( false , true ) ,
3004+ }
3005+ }
3006+ if !self . eat_keyword ( kw:: If ) {
3007+ // No match arm guard present.
3008+ return Ok ( None ) ;
3009+ }
3010+
3011+ let if_span = self . prev_token . span ;
3012+ let mut cond = self . parse_match_guard_condition ( ) ?;
3013+
3014+ CondChecker :: new ( self ) . visit_expr ( & mut cond) ;
3015+
3016+ let ( has_let_expr, does_not_have_bin_op) = check_let_expr ( & cond) ;
3017+ if has_let_expr {
3018+ if does_not_have_bin_op {
3019+ // Remove the last feature gating of a `let` expression since it's stable.
3020+ self . sess . gated_spans . ungate_last ( sym:: let_chains, cond. span ) ;
3021+ }
3022+ let span = if_span. to ( cond. span ) ;
3023+ self . sess . gated_spans . gate ( sym:: if_let_guard, span) ;
3024+ }
3025+ Ok ( Some ( cond) )
3026+ }
3027+
3028+ fn parse_match_arm_pat_and_guard ( & mut self ) -> PResult < ' a , ( P < Pat > , Option < P < Expr > > ) > {
3029+ if self . token . kind == token:: OpenDelim ( Delimiter :: Parenthesis ) {
3030+ // Detect and recover from `($pat if $cond) => $arm`.
3031+ let left = self . token . span ;
3032+ match self . parse_pat_allow_top_alt (
3033+ None ,
3034+ RecoverComma :: Yes ,
3035+ RecoverColon :: Yes ,
3036+ CommaRecoveryMode :: EitherTupleOrPipe ,
3037+ ) {
3038+ Ok ( pat) => Ok ( ( pat, self . parse_match_arm_guard ( ) ?) ) ,
3039+ Err ( err)
3040+ if let prev_sp = self . prev_token . span
3041+ && let true = self . eat_keyword ( kw:: If ) =>
3042+ {
3043+ // We know for certain we've found `($pat if` so far.
3044+ let mut cond = match self . parse_match_guard_condition ( ) {
3045+ Ok ( cond) => cond,
3046+ Err ( cond_err) => {
3047+ cond_err. cancel ( ) ;
3048+ return Err ( err) ;
3049+ }
3050+ } ;
3051+ err. cancel ( ) ;
3052+ CondChecker :: new ( self ) . visit_expr ( & mut cond) ;
3053+ self . eat_to_tokens ( & [ & token:: CloseDelim ( Delimiter :: Parenthesis ) ] ) ;
3054+ self . expect ( & token:: CloseDelim ( Delimiter :: Parenthesis ) ) ?;
3055+ let right = self . prev_token . span ;
3056+ self . sess . emit_err ( errors:: ParenthesesInMatchPat {
3057+ span : vec ! [ left, right] ,
3058+ sugg : errors:: ParenthesesInMatchPatSugg { left, right } ,
3059+ } ) ;
3060+ Ok ( ( self . mk_pat ( left. to ( prev_sp) , ast:: PatKind :: Wild ) , Some ( cond) ) )
3061+ }
3062+ Err ( err) => Err ( err) ,
3063+ }
3064+ } else {
3065+ // Regular parser flow:
3066+ let pat = self . parse_pat_allow_top_alt (
3067+ None ,
3068+ RecoverComma :: Yes ,
3069+ RecoverColon :: Yes ,
3070+ CommaRecoveryMode :: EitherTupleOrPipe ,
3071+ ) ?;
3072+ Ok ( ( pat, self . parse_match_arm_guard ( ) ?) )
3073+ }
3074+ }
3075+
30293076 fn parse_match_guard_condition ( & mut self ) -> PResult < ' a , P < Expr > > {
30303077 self . parse_expr_res ( Restrictions :: ALLOW_LET | Restrictions :: IN_IF_GUARD , None ) . map_err (
30313078 |mut err| {
0 commit comments