@@ -140,70 +140,45 @@ fn check_opt_like<'a>(
140
140
ty : Ty < ' a > ,
141
141
els : Option < & Expr < ' _ > > ,
142
142
) {
143
- // list of candidate `Enum`s we know will never get any more members
144
- let candidates = & [
145
- ( & paths:: COW , "Borrowed" ) ,
146
- ( & paths:: COW , "Cow::Borrowed" ) ,
147
- ( & paths:: COW , "Cow::Owned" ) ,
148
- ( & paths:: COW , "Owned" ) ,
149
- ( & paths:: OPTION , "None" ) ,
150
- ( & paths:: RESULT , "Err" ) ,
151
- ( & paths:: RESULT , "Ok" ) ,
152
- ] ;
153
-
154
- // We want to suggest to exclude an arm that contains only wildcards or forms the exhaustive
155
- // match with the second branch, without enum variants in matches.
156
- if !contains_only_wilds ( arms[ 1 ] . pat ) && !form_exhaustive_matches ( arms[ 0 ] . pat , arms[ 1 ] . pat ) {
157
- return ;
143
+ // We don't want to lint if the second arm contains an enum which could
144
+ // have more variants in the future.
145
+ if form_exhaustive_matches ( cx, ty, arms[ 0 ] . pat , arms[ 1 ] . pat ) {
146
+ report_single_pattern ( cx, ex, arms, expr, els) ;
158
147
}
148
+ }
159
149
150
+ /// Returns `true` if all of the types in the pattern are enums which we know
151
+ /// won't be expanded in the future
152
+ fn pat_in_candidate_enum < ' a > ( cx : & LateContext < ' a > , ty : Ty < ' a > , pat : & Pat < ' _ > ) -> bool {
160
153
let mut paths_and_types = Vec :: new ( ) ;
161
- if ! collect_pat_paths ( & mut paths_and_types, cx, arms [ 1 ] . pat , ty) {
162
- return ;
163
- }
154
+ collect_pat_paths ( & mut paths_and_types, cx, pat, ty) ;
155
+ paths_and_types . iter ( ) . all ( |ty| in_candidate_enum ( cx , * ty ) )
156
+ }
164
157
165
- let in_candidate_enum = |path_info : & ( String , Ty < ' _ > ) | -> bool {
166
- let ( path, ty) = path_info;
167
- for & ( ty_path, pat_path) in candidates {
168
- if path == pat_path && match_type ( cx, * ty, ty_path) {
169
- return true ;
170
- }
158
+ /// Returns `true` if the given type is an enum we know won't be expanded in the future
159
+ fn in_candidate_enum < ' a > ( cx : & LateContext < ' a > , ty : Ty < ' _ > ) -> bool {
160
+ // list of candidate `Enum`s we know will never get any more members
161
+ let candidates = [ & paths:: COW , & paths:: OPTION , & paths:: RESULT ] ;
162
+
163
+ for candidate_ty in candidates {
164
+ if match_type ( cx, ty, candidate_ty) {
165
+ return true ;
171
166
}
172
- false
173
- } ;
174
- if paths_and_types. iter ( ) . all ( in_candidate_enum) {
175
- report_single_pattern ( cx, ex, arms, expr, els) ;
176
167
}
168
+ false
177
169
}
178
170
179
- /// Collects paths and their types from the given patterns. Returns true if the given pattern could
180
- /// be simplified, false otherwise.
181
- fn collect_pat_paths < ' a > ( acc : & mut Vec < ( String , Ty < ' a > ) > , cx : & LateContext < ' a > , pat : & Pat < ' _ > , ty : Ty < ' a > ) -> bool {
171
+ /// Collects types from the given pattern
172
+ fn collect_pat_paths < ' a > ( acc : & mut Vec < Ty < ' a > > , cx : & LateContext < ' a > , pat : & Pat < ' _ > , ty : Ty < ' a > ) {
182
173
match pat. kind {
183
- PatKind :: Wild => true ,
184
- PatKind :: Tuple ( inner, _) => inner. iter ( ) . all ( |p| {
174
+ PatKind :: Tuple ( inner, _) => inner. iter ( ) . for_each ( |p| {
185
175
let p_ty = cx. typeck_results ( ) . pat_ty ( p) ;
186
- collect_pat_paths ( acc, cx, p, p_ty)
176
+ collect_pat_paths ( acc, cx, p, p_ty) ;
187
177
} ) ,
188
- PatKind :: TupleStruct ( ref path, ..) => {
189
- let path = rustc_hir_pretty:: to_string ( rustc_hir_pretty:: NO_ANN , |s| {
190
- s. print_qpath ( path, false ) ;
191
- } ) ;
192
- acc. push ( ( path, ty) ) ;
193
- true
194
- } ,
195
- PatKind :: Binding ( BindingAnnotation :: Unannotated , .., ident, None ) => {
196
- acc. push ( ( ident. to_string ( ) , ty) ) ;
197
- true
178
+ PatKind :: TupleStruct ( ..) | PatKind :: Binding ( BindingAnnotation :: Unannotated , .., None ) | PatKind :: Path ( _) => {
179
+ acc. push ( ty) ;
198
180
} ,
199
- PatKind :: Path ( ref path) => {
200
- let path = rustc_hir_pretty:: to_string ( rustc_hir_pretty:: NO_ANN , |s| {
201
- s. print_qpath ( path, false ) ;
202
- } ) ;
203
- acc. push ( ( path, ty) ) ;
204
- true
205
- } ,
206
- _ => false ,
181
+ _ => { } ,
207
182
}
208
183
}
209
184
@@ -218,7 +193,7 @@ fn contains_only_wilds(pat: &Pat<'_>) -> bool {
218
193
219
194
/// Returns true if the given patterns forms only exhaustive matches that don't contain enum
220
195
/// patterns without a wildcard.
221
- fn form_exhaustive_matches ( left : & Pat < ' _ > , right : & Pat < ' _ > ) -> bool {
196
+ fn form_exhaustive_matches < ' a > ( cx : & LateContext < ' a > , ty : Ty < ' a > , left : & Pat < ' _ > , right : & Pat < ' _ > ) -> bool {
222
197
match ( & left. kind , & right. kind ) {
223
198
( PatKind :: Wild , _) | ( _, PatKind :: Wild ) => true ,
224
199
( PatKind :: Tuple ( left_in, left_pos) , PatKind :: Tuple ( right_in, right_pos) ) => {
@@ -264,6 +239,10 @@ fn form_exhaustive_matches(left: &Pat<'_>, right: &Pat<'_>) -> bool {
264
239
}
265
240
true
266
241
} ,
242
+ ( PatKind :: TupleStruct ( ..) , PatKind :: Path ( _) ) => pat_in_candidate_enum ( cx, ty, right) ,
243
+ ( PatKind :: TupleStruct ( ..) , PatKind :: TupleStruct ( _, inner, _) ) => {
244
+ pat_in_candidate_enum ( cx, ty, right) && inner. iter ( ) . all ( contains_only_wilds)
245
+ } ,
267
246
_ => false ,
268
247
}
269
248
}
0 commit comments