@@ -10,7 +10,7 @@ use super::{
10
10
use crate :: errors;
11
11
use crate :: maybe_recover_from_interpolated_ty_qpath;
12
12
use ast:: mut_visit:: { noop_visit_expr, MutVisitor } ;
13
- use ast:: { GenBlockKind , Path , PathSegment } ;
13
+ use ast:: { GenBlockKind , Pat , Path , PathSegment } ;
14
14
use core:: mem;
15
15
use rustc_ast:: ptr:: P ;
16
16
use rustc_ast:: token:: { self , Delimiter , Token , TokenKind } ;
@@ -2856,47 +2856,10 @@ impl<'a> Parser<'a> {
2856
2856
}
2857
2857
2858
2858
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
- }
2872
2859
let attrs = self . parse_outer_attributes ( ) ?;
2873
2860
self . collect_tokens_trailing_token ( attrs, ForceCollect :: No , |this, attrs| {
2874
2861
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 ( ) ?;
2900
2863
let arrow_span = this. token . span ;
2901
2864
if let Err ( mut err) = this. expect ( & token:: FatArrow ) {
2902
2865
// We might have a `=>` -> `=` or `->` typo (issue #89396).
@@ -3026,6 +2989,90 @@ impl<'a> Parser<'a> {
3026
2989
} )
3027
2990
}
3028
2991
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
+
3029
3076
fn parse_match_guard_condition ( & mut self ) -> PResult < ' a , P < Expr > > {
3030
3077
self . parse_expr_res ( Restrictions :: ALLOW_LET | Restrictions :: IN_IF_GUARD , None ) . map_err (
3031
3078
|mut err| {
0 commit comments