@@ -29,56 +29,41 @@ fn empty_arm_has_comment(cx: &LateContext<'_>, span: Span) -> bool {
29
29
30
30
#[ rustfmt:: skip]
31
31
pub ( crate ) fn check ( cx : & LateContext < ' _ > , ex : & Expr < ' _ > , arms : & [ Arm < ' _ > ] , expr : & Expr < ' _ > ) {
32
- if arms. len ( ) == 2 && arms[ 0 ] . guard . is_none ( ) && arms[ 1 ] . guard . is_none ( ) {
33
- if expr. span . from_expansion ( ) {
34
- // Don't lint match expressions present in
35
- // macro_rules! block
36
- return ;
37
- }
38
- if let PatKind :: Or ( ..) = arms[ 0 ] . pat . kind {
39
- // don't lint for or patterns for now, this makes
40
- // the lint noisy in unnecessary situations
41
- return ;
42
- }
43
- let els = arms[ 1 ] . body ;
44
- let els = if is_unit_expr ( peel_blocks ( els) ) && !empty_arm_has_comment ( cx, els. span ) {
32
+ if let [ arm1, arm2] = arms
33
+ && arm1. guard . is_none ( )
34
+ && arm2. guard . is_none ( )
35
+ && !expr. span . from_expansion ( )
36
+ // don't lint for or patterns for now, this makes
37
+ // the lint noisy in unnecessary situations
38
+ && !matches ! ( arm1. pat. kind, PatKind :: Or ( ..) )
39
+ {
40
+ let els = if is_unit_expr ( peel_blocks ( arm2. body ) ) && !empty_arm_has_comment ( cx, arm2. body . span ) {
45
41
None
46
- } else if let ExprKind :: Block ( Block { stmts , expr : block_expr , .. } , _) = els . kind {
47
- if stmts. len ( ) == 1 && block_expr . is_none ( ) || stmts . is_empty ( ) && block_expr . is_some ( ) {
42
+ } else if let ExprKind :: Block ( block , _) = arm2 . body . kind {
43
+ if matches ! ( ( block . stmts, block . expr ) , ( [ ] , Some ( _ ) ) | ( [ _ ] , None ) ) {
48
44
// single statement/expr "else" block, don't lint
49
45
return ;
50
46
}
51
47
// block with 2+ statements or 1 expr and 1+ statement
52
- Some ( els )
48
+ Some ( arm2 . body )
53
49
} else {
54
- // not a block or an emtpy block w/ comments, don't lint
50
+ // not a block or an empty block w/ comments, don't lint
55
51
return ;
56
52
} ;
57
53
58
54
let ty = cx. typeck_results ( ) . expr_ty ( ex) ;
59
- if * ty. kind ( ) != ty:: Bool || is_lint_allowed ( cx, MATCH_BOOL , ex. hir_id ) {
60
- check_single_pattern ( cx, ex, arms, expr, els) ;
61
- check_opt_like ( cx, ex, arms, expr, ty, els) ;
55
+ if ( * ty. kind ( ) != ty:: Bool || is_lint_allowed ( cx, MATCH_BOOL , ex. hir_id ) )
56
+ && ( is_wild ( arm2. pat ) || form_exhaustive_matches ( cx, ty, arm1. pat , arm2. pat ) )
57
+ {
58
+ report_single_pattern ( cx, ex, arm1, expr, els) ;
62
59
}
63
60
}
64
61
}
65
62
66
- fn check_single_pattern (
67
- cx : & LateContext < ' _ > ,
68
- ex : & Expr < ' _ > ,
69
- arms : & [ Arm < ' _ > ] ,
70
- expr : & Expr < ' _ > ,
71
- els : Option < & Expr < ' _ > > ,
72
- ) {
73
- if is_wild ( arms[ 1 ] . pat ) {
74
- report_single_pattern ( cx, ex, arms, expr, els) ;
75
- }
76
- }
77
-
78
63
fn report_single_pattern (
79
64
cx : & LateContext < ' _ > ,
80
65
ex : & Expr < ' _ > ,
81
- arms : & [ Arm < ' _ > ] ,
66
+ arm : & Arm < ' _ > ,
82
67
expr : & Expr < ' _ > ,
83
68
els : Option < & Expr < ' _ > > ,
84
69
) {
@@ -89,71 +74,54 @@ fn report_single_pattern(
89
74
format ! ( " else {}" , expr_block( cx, els, ctxt, ".." , Some ( expr. span) , & mut app) )
90
75
} ) ;
91
76
92
- let ( pat, pat_ref_count) = peel_hir_pat_refs ( arms[ 0 ] . pat ) ;
93
- let ( msg, sugg) = if_chain ! {
94
- if let PatKind :: Path ( _) | PatKind :: Lit ( _) = pat. kind;
95
- let ( ty, ty_ref_count) = peel_mid_ty_refs( cx. typeck_results( ) . expr_ty( ex) ) ;
96
- if let Some ( spe_trait_id) = cx. tcx. lang_items( ) . structural_peq_trait( ) ;
97
- if let Some ( pe_trait_id) = cx. tcx. lang_items( ) . eq_trait( ) ;
98
- if ty. is_integral( ) || ty. is_char( ) || ty. is_str( )
77
+ let ( pat, pat_ref_count) = peel_hir_pat_refs ( arm. pat ) ;
78
+ let ( msg, sugg) = if let PatKind :: Path ( _) | PatKind :: Lit ( _) = pat. kind
79
+ && let ( ty, ty_ref_count) = peel_mid_ty_refs ( cx. typeck_results ( ) . expr_ty ( ex) )
80
+ && let Some ( spe_trait_id) = cx. tcx . lang_items ( ) . structural_peq_trait ( )
81
+ && let Some ( pe_trait_id) = cx. tcx . lang_items ( ) . eq_trait ( )
82
+ && ( ty. is_integral ( ) || ty. is_char ( ) || ty. is_str ( )
99
83
|| ( implements_trait ( cx, ty, spe_trait_id, & [ ] )
100
- && implements_trait( cx, ty, pe_trait_id, & [ ty. into( ) ] ) ) ;
101
- then {
102
- // scrutinee derives PartialEq and the pattern is a constant.
103
- let pat_ref_count = match pat. kind {
104
- // string literals are already a reference.
105
- PatKind :: Lit ( Expr { kind: ExprKind :: Lit ( lit) , .. } ) if lit. node. is_str( ) => pat_ref_count + 1 ,
106
- _ => pat_ref_count,
107
- } ;
108
- // References are only implicitly added to the pattern, so no overflow here.
109
- // e.g. will work: match &Some(_) { Some(_) => () }
110
- // will not: match Some(_) { &Some(_) => () }
111
- let ref_count_diff = ty_ref_count - pat_ref_count;
112
-
113
- // Try to remove address of expressions first.
114
- let ( ex, removed) = peel_n_hir_expr_refs( ex, ref_count_diff) ;
115
- let ref_count_diff = ref_count_diff - removed;
116
-
117
- let msg = "you seem to be trying to use `match` for an equality check. Consider using `if`" ;
118
- let sugg = format!(
119
- "if {} == {}{} {}{els_str}" ,
120
- snippet( cx, ex. span, ".." ) ,
121
- // PartialEq for different reference counts may not exist.
122
- "&" . repeat( ref_count_diff) ,
123
- snippet( cx, arms[ 0 ] . pat. span, ".." ) ,
124
- expr_block( cx, arms[ 0 ] . body, ctxt, ".." , Some ( expr. span) , & mut app) ,
125
- ) ;
126
- ( msg, sugg)
127
- } else {
128
- let msg = "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`" ;
129
- let sugg = format!(
130
- "if let {} = {} {}{els_str}" ,
131
- snippet( cx, arms[ 0 ] . pat. span, ".." ) ,
132
- snippet( cx, ex. span, ".." ) ,
133
- expr_block( cx, arms[ 0 ] . body, ctxt, ".." , Some ( expr. span) , & mut app) ,
134
- ) ;
135
- ( msg, sugg)
136
- }
84
+ && implements_trait ( cx, ty, pe_trait_id, & [ ty. into ( ) ] ) ) )
85
+ {
86
+ // scrutinee derives PartialEq and the pattern is a constant.
87
+ let pat_ref_count = match pat. kind {
88
+ // string literals are already a reference.
89
+ PatKind :: Lit ( Expr { kind : ExprKind :: Lit ( lit) , .. } ) if lit. node . is_str ( ) => pat_ref_count + 1 ,
90
+ _ => pat_ref_count,
91
+ } ;
92
+ // References are only implicitly added to the pattern, so no overflow here.
93
+ // e.g. will work: match &Some(_) { Some(_) => () }
94
+ // will not: match Some(_) { &Some(_) => () }
95
+ let ref_count_diff = ty_ref_count - pat_ref_count;
96
+
97
+ // Try to remove address of expressions first.
98
+ let ( ex, removed) = peel_n_hir_expr_refs ( ex, ref_count_diff) ;
99
+ let ref_count_diff = ref_count_diff - removed;
100
+
101
+ let msg = "you seem to be trying to use `match` for an equality check. Consider using `if`" ;
102
+ let sugg = format ! (
103
+ "if {} == {}{} {}{els_str}" ,
104
+ snippet( cx, ex. span, ".." ) ,
105
+ // PartialEq for different reference counts may not exist.
106
+ "&" . repeat( ref_count_diff) ,
107
+ snippet( cx, arm. pat. span, ".." ) ,
108
+ expr_block( cx, arm. body, ctxt, ".." , Some ( expr. span) , & mut app) ,
109
+ ) ;
110
+ ( msg, sugg)
111
+ } else {
112
+ let msg = "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`" ;
113
+ let sugg = format ! (
114
+ "if let {} = {} {}{els_str}" ,
115
+ snippet( cx, arm. pat. span, ".." ) ,
116
+ snippet( cx, ex. span, ".." ) ,
117
+ expr_block( cx, arm. body, ctxt, ".." , Some ( expr. span) , & mut app) ,
118
+ ) ;
119
+ ( msg, sugg)
137
120
} ;
138
121
139
122
span_lint_and_sugg ( cx, lint, expr. span , msg, "try" , sugg, app) ;
140
123
}
141
124
142
- fn check_opt_like < ' a > (
143
- cx : & LateContext < ' a > ,
144
- ex : & Expr < ' _ > ,
145
- arms : & [ Arm < ' _ > ] ,
146
- expr : & Expr < ' _ > ,
147
- ty : Ty < ' a > ,
148
- els : Option < & Expr < ' _ > > ,
149
- ) {
150
- // We don't want to lint if the second arm contains an enum which could
151
- // have more variants in the future.
152
- if form_exhaustive_matches ( cx, ty, arms[ 0 ] . pat , arms[ 1 ] . pat ) {
153
- report_single_pattern ( cx, ex, arms, expr, els) ;
154
- }
155
- }
156
-
157
125
/// Returns `true` if all of the types in the pattern are enums which we know
158
126
/// won't be expanded in the future
159
127
fn pat_in_candidate_enum < ' a > ( cx : & LateContext < ' a > , ty : Ty < ' a > , pat : & Pat < ' _ > ) -> bool {
0 commit comments