@@ -6,7 +6,7 @@ use clippy_utils::{
66} ;
77use core:: cmp:: max;
88use rustc_errors:: Applicability ;
9- use rustc_hir:: { Arm , BindingMode , Block , Expr , ExprKind , Pat , PatKind } ;
9+ use rustc_hir:: { Arm , BindingMode , Expr , ExprKind , Pat , PatKind } ;
1010use rustc_lint:: LateContext ;
1111use rustc_middle:: ty:: { self , Ty } ;
1212use rustc_span:: { sym, Span } ;
@@ -30,59 +30,46 @@ fn empty_arm_has_comment(cx: &LateContext<'_>, span: Span) -> bool {
3030
3131#[ rustfmt:: skip]
3232pub ( crate ) fn check ( cx : & LateContext < ' _ > , ex : & Expr < ' _ > , arms : & [ Arm < ' _ > ] , expr : & Expr < ' _ > ) {
33- if arms. len ( ) == 2 && arms[ 0 ] . guard . is_none ( ) && arms[ 1 ] . guard . is_none ( ) {
34- if expr. span . from_expansion ( ) {
35- // Don't lint match expressions present in
36- // macro_rules! block
37- return ;
38- }
39- if let PatKind :: Or ( ..) = arms[ 0 ] . pat . kind {
40- // don't lint for or patterns for now, this makes
41- // the lint noisy in unnecessary situations
42- return ;
43- }
44- let els = arms[ 1 ] . body ;
45- let els = if is_unit_expr ( peel_blocks ( els) ) && !empty_arm_has_comment ( cx, els. span ) {
33+ if let [ arm1, arm2] = arms
34+ && arm1. guard . is_none ( )
35+ && arm2. guard . is_none ( )
36+ && !expr. span . from_expansion ( )
37+ // don't lint for or patterns for now, this makes
38+ // the lint noisy in unnecessary situations
39+ && !matches ! ( arm1. pat. kind, PatKind :: Or ( ..) )
40+ {
41+ let els = if is_unit_expr ( peel_blocks ( arm2. body ) ) && !empty_arm_has_comment ( cx, arm2. body . span ) {
4642 None
47- } else if let ExprKind :: Block ( Block { stmts , expr : block_expr , .. } , _) = els . kind {
48- if stmts. len ( ) == 1 && block_expr . is_none ( ) || stmts . is_empty ( ) && block_expr . is_some ( ) {
43+ } else if let ExprKind :: Block ( block , _) = arm2 . body . kind {
44+ if matches ! ( ( block . stmts, block . expr ) , ( [ ] , Some ( _ ) ) | ( [ _ ] , None ) ) {
4945 // single statement/expr "else" block, don't lint
5046 return ;
5147 }
5248 // block with 2+ statements or 1 expr and 1+ statement
53- Some ( els )
49+ Some ( arm2 . body )
5450 } else {
5551 // not a block or an empty block w/ comments, don't lint
5652 return ;
5753 } ;
5854
5955 let ty = cx. typeck_results ( ) . expr_ty ( ex) ;
60- if ( * ty. kind ( ) != ty:: Bool || is_lint_allowed ( cx, MATCH_BOOL , ex. hir_id ) ) &&
61- ( check_single_pattern ( arms) || check_opt_like ( cx, arms, ty) ) {
62- report_single_pattern ( cx, ex, arms, expr, els) ;
56+ if ( * ty. kind ( ) != ty:: Bool || is_lint_allowed ( cx, MATCH_BOOL , ex. hir_id ) )
57+ && ( is_wild ( arm2. pat ) || form_exhaustive_matches ( cx, ty, arm1. pat , arm2. pat ) )
58+ {
59+ report_single_pattern ( cx, ex, arm1, expr, els) ;
6360 }
6461 }
6562}
6663
67- fn check_single_pattern ( arms : & [ Arm < ' _ > ] ) -> bool {
68- is_wild ( arms[ 1 ] . pat )
69- }
70-
71- fn report_single_pattern (
72- cx : & LateContext < ' _ > ,
73- ex : & Expr < ' _ > ,
74- arms : & [ Arm < ' _ > ] ,
75- expr : & Expr < ' _ > ,
76- els : Option < & Expr < ' _ > > ,
77- ) {
64+ fn report_single_pattern ( cx : & LateContext < ' _ > , ex : & Expr < ' _ > , arm : & Arm < ' _ > , expr : & Expr < ' _ > , els : Option < & Expr < ' _ > > ) {
7865 let lint = if els. is_some ( ) { SINGLE_MATCH_ELSE } else { SINGLE_MATCH } ;
7966 let ctxt = expr. span . ctxt ( ) ;
8067 let mut app = Applicability :: MachineApplicable ;
8168 let els_str = els. map_or ( String :: new ( ) , |els| {
8269 format ! ( " else {}" , expr_block( cx, els, ctxt, ".." , Some ( expr. span) , & mut app) )
8370 } ) ;
8471
85- let ( pat, pat_ref_count) = peel_hir_pat_refs ( arms [ 0 ] . pat ) ;
72+ let ( pat, pat_ref_count) = peel_hir_pat_refs ( arm . pat ) ;
8673 let ( msg, sugg) = if let PatKind :: Path ( _) | PatKind :: Lit ( _) = pat. kind
8774 && let ( ty, ty_ref_count) = peel_middle_ty_refs ( cx. typeck_results ( ) . expr_ty ( ex) )
8875 && let Some ( spe_trait_id) = cx. tcx . lang_items ( ) . structural_peq_trait ( )
@@ -116,30 +103,24 @@ fn report_single_pattern(
116103 snippet( cx, ex. span, ".." ) ,
117104 // PartialEq for different reference counts may not exist.
118105 "&" . repeat( ref_count_diff) ,
119- snippet( cx, arms [ 0 ] . pat. span, ".." ) ,
120- expr_block( cx, arms [ 0 ] . body, ctxt, ".." , Some ( expr. span) , & mut app) ,
106+ snippet( cx, arm . pat. span, ".." ) ,
107+ expr_block( cx, arm . body, ctxt, ".." , Some ( expr. span) , & mut app) ,
121108 ) ;
122109 ( msg, sugg)
123110 } else {
124111 let msg = "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`" ;
125112 let sugg = format ! (
126113 "if let {} = {} {}{els_str}" ,
127- snippet( cx, arms [ 0 ] . pat. span, ".." ) ,
114+ snippet( cx, arm . pat. span, ".." ) ,
128115 snippet( cx, ex. span, ".." ) ,
129- expr_block( cx, arms [ 0 ] . body, ctxt, ".." , Some ( expr. span) , & mut app) ,
116+ expr_block( cx, arm . body, ctxt, ".." , Some ( expr. span) , & mut app) ,
130117 ) ;
131118 ( msg, sugg)
132119 } ;
133120
134121 span_lint_and_sugg ( cx, lint, expr. span , msg, "try" , sugg, app) ;
135122}
136123
137- fn check_opt_like < ' a > ( cx : & LateContext < ' a > , arms : & [ Arm < ' _ > ] , ty : Ty < ' a > ) -> bool {
138- // We don't want to lint if the second arm contains an enum which could
139- // have more variants in the future.
140- form_exhaustive_matches ( cx, ty, arms[ 0 ] . pat , arms[ 1 ] . pat )
141- }
142-
143124/// Returns `true` if all of the types in the pattern are enums which we know
144125/// won't be expanded in the future
145126fn pat_in_candidate_enum < ' a > ( cx : & LateContext < ' a > , ty : Ty < ' a > , pat : & Pat < ' _ > ) -> bool {
0 commit comments