@@ -9,7 +9,7 @@ use super::{
99use crate :: errors;
1010use crate :: maybe_recover_from_interpolated_ty_qpath;
1111use ast:: mut_visit:: { noop_visit_expr, MutVisitor } ;
12- use ast:: { GenBlockKind , Path , PathSegment } ;
12+ use ast:: { GenBlockKind , Pat , Path , PathSegment } ;
1313use core:: mem;
1414use rustc_ast:: ptr:: P ;
1515use rustc_ast:: token:: { self , Delimiter , Token , TokenKind } ;
@@ -2837,47 +2837,10 @@ impl<'a> Parser<'a> {
28372837 }
28382838
28392839 pub ( super ) fn parse_arm ( & mut self ) -> PResult < ' a , Arm > {
2840- // Used to check the `let_chains` and `if_let_guard` features mostly by scanning
2841- // `&&` tokens.
2842- fn check_let_expr ( expr : & Expr ) -> ( bool , bool ) {
2843- match & expr. kind {
2844- ExprKind :: Binary ( BinOp { node : BinOpKind :: And , .. } , lhs, rhs) => {
2845- let lhs_rslt = check_let_expr ( lhs) ;
2846- let rhs_rslt = check_let_expr ( rhs) ;
2847- ( lhs_rslt. 0 || rhs_rslt. 0 , false )
2848- }
2849- ExprKind :: Let ( ..) => ( true , true ) ,
2850- _ => ( false , true ) ,
2851- }
2852- }
28532840 let attrs = self . parse_outer_attributes ( ) ?;
28542841 self . collect_tokens_trailing_token ( attrs, ForceCollect :: No , |this, attrs| {
28552842 let lo = this. token . span ;
2856- let pat = this. parse_pat_allow_top_alt (
2857- None ,
2858- RecoverComma :: Yes ,
2859- RecoverColon :: Yes ,
2860- CommaRecoveryMode :: EitherTupleOrPipe ,
2861- ) ?;
2862- let guard = if this. eat_keyword ( kw:: If ) {
2863- let if_span = this. prev_token . span ;
2864- let mut cond = this. parse_match_guard_condition ( ) ?;
2865-
2866- CondChecker { parser : this, forbid_let_reason : None } . visit_expr ( & mut cond) ;
2867-
2868- let ( has_let_expr, does_not_have_bin_op) = check_let_expr ( & cond) ;
2869- if has_let_expr {
2870- if does_not_have_bin_op {
2871- // Remove the last feature gating of a `let` expression since it's stable.
2872- this. sess . gated_spans . ungate_last ( sym:: let_chains, cond. span ) ;
2873- }
2874- let span = if_span. to ( cond. span ) ;
2875- this. sess . gated_spans . gate ( sym:: if_let_guard, span) ;
2876- }
2877- Some ( cond)
2878- } else {
2879- None
2880- } ;
2843+ let ( pat, guard) = this. parse_match_arm_pat_and_guard ( ) ?;
28812844 let arrow_span = this. token . span ;
28822845 if let Err ( mut err) = this. expect ( & token:: FatArrow ) {
28832846 // We might have a `=>` -> `=` or `->` typo (issue #89396).
@@ -3006,6 +2969,87 @@ impl<'a> Parser<'a> {
30062969 } )
30072970 }
30082971
2972+ fn parse_match_arm_guard ( & mut self ) -> PResult < ' a , Option < P < Expr > > > {
2973+ // Used to check the `let_chains` and `if_let_guard` features mostly by scanning
2974+ // `&&` tokens.
2975+ fn check_let_expr ( expr : & Expr ) -> ( bool , bool ) {
2976+ match & expr. kind {
2977+ ExprKind :: Binary ( BinOp { node : BinOpKind :: And , .. } , lhs, rhs) => {
2978+ let lhs_rslt = check_let_expr ( lhs) ;
2979+ let rhs_rslt = check_let_expr ( rhs) ;
2980+ ( lhs_rslt. 0 || rhs_rslt. 0 , false )
2981+ }
2982+ ExprKind :: Let ( ..) => ( true , true ) ,
2983+ _ => ( false , true ) ,
2984+ }
2985+ }
2986+ if !self . eat_keyword ( kw:: If ) {
2987+ // No match arm guard present.
2988+ return Ok ( None ) ;
2989+ }
2990+
2991+ let if_span = self . prev_token . span ;
2992+ let mut cond = self . parse_match_guard_condition ( ) ?;
2993+
2994+ CondChecker { parser : self , forbid_let_reason : None } . visit_expr ( & mut cond) ;
2995+
2996+ let ( has_let_expr, does_not_have_bin_op) = check_let_expr ( & cond) ;
2997+ if has_let_expr {
2998+ if does_not_have_bin_op {
2999+ // Remove the last feature gating of a `let` expression since it's stable.
3000+ self . sess . gated_spans . ungate_last ( sym:: let_chains, cond. span ) ;
3001+ }
3002+ let span = if_span. to ( cond. span ) ;
3003+ self . sess . gated_spans . gate ( sym:: if_let_guard, span) ;
3004+ }
3005+ Ok ( Some ( cond) )
3006+ }
3007+
3008+ fn parse_match_arm_pat_and_guard ( & mut self ) -> PResult < ' a , ( P < Pat > , Option < P < Expr > > ) > {
3009+ if self . token . kind == token:: OpenDelim ( Delimiter :: Parenthesis ) {
3010+ // Detect and recover from `($pat if $cond) => $arm`.
3011+ let left = self . token . span ;
3012+ match self . parse_pat_allow_top_alt (
3013+ None ,
3014+ RecoverComma :: Yes ,
3015+ RecoverColon :: Yes ,
3016+ CommaRecoveryMode :: EitherTupleOrPipe ,
3017+ ) {
3018+ Ok ( pat) => Ok ( ( pat, self . parse_match_arm_guard ( ) ?) ) ,
3019+ Err ( err) if let prev_sp = self . prev_token . span && let true = self . eat_keyword ( kw:: If ) => {
3020+ // We know for certain we've found `($pat if` so far.
3021+ let mut cond = match self . parse_match_guard_condition ( ) {
3022+ Ok ( cond) => cond,
3023+ Err ( cond_err) => {
3024+ cond_err. cancel ( ) ;
3025+ return Err ( err) ;
3026+ }
3027+ } ;
3028+ err. cancel ( ) ;
3029+ CondChecker { parser : self , forbid_let_reason : None } . visit_expr ( & mut cond) ;
3030+ self . eat_to_tokens ( & [ & token:: CloseDelim ( Delimiter :: Parenthesis ) ] ) ;
3031+ self . expect ( & token:: CloseDelim ( Delimiter :: Parenthesis ) ) ?;
3032+ let right = self . prev_token . span ;
3033+ self . sess . emit_err ( errors:: ParenthesesInMatchPat {
3034+ span : vec ! [ left, right] ,
3035+ sugg : errors:: ParenthesesInMatchPatSugg { left, right } ,
3036+ } ) ;
3037+ Ok ( ( self . mk_pat ( left. to ( prev_sp) , ast:: PatKind :: Wild ) , Some ( cond) ) )
3038+ }
3039+ Err ( err) => Err ( err) ,
3040+ }
3041+ } else {
3042+ // Regular parser flow:
3043+ let pat = self . parse_pat_allow_top_alt (
3044+ None ,
3045+ RecoverComma :: Yes ,
3046+ RecoverColon :: Yes ,
3047+ CommaRecoveryMode :: EitherTupleOrPipe ,
3048+ ) ?;
3049+ Ok ( ( pat, self . parse_match_arm_guard ( ) ?) )
3050+ }
3051+ }
3052+
30093053 fn parse_match_guard_condition ( & mut self ) -> PResult < ' a , P < Expr > > {
30103054 self . parse_expr_res ( Restrictions :: ALLOW_LET | Restrictions :: IN_IF_GUARD , None ) . map_err (
30113055 |mut err| {
0 commit comments