1
1
use clippy_utils:: diagnostics:: span_lint_and_then;
2
2
use clippy_utils:: source:: snippet;
3
3
use clippy_utils:: { path_to_local, search_same, SpanlessEq , SpanlessHash } ;
4
+ use core:: iter;
5
+ use rustc_arena:: DroplessArena ;
4
6
use rustc_ast:: ast:: LitKind ;
5
7
use rustc_hir:: def_id:: DefId ;
6
8
use rustc_hir:: { Arm , Expr , ExprKind , HirId , HirIdMap , HirIdSet , Pat , PatKind , RangeEnd } ;
7
9
use rustc_lint:: LateContext ;
10
+ use rustc_middle:: ty;
8
11
use rustc_span:: Symbol ;
9
12
use std:: collections:: hash_map:: Entry ;
10
13
@@ -17,7 +20,8 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) {
17
20
h. finish ( )
18
21
} ;
19
22
20
- let resolved_pats: Vec < _ > = arms. iter ( ) . map ( |a| ResolvedPat :: from_pat ( cx, a. pat ) ) . collect ( ) ;
23
+ let arena = DroplessArena :: default ( ) ;
24
+ let resolved_pats: Vec < _ > = arms. iter ( ) . map ( |a| ResolvedPat :: from_pat ( cx, & arena, a. pat ) ) . collect ( ) ;
21
25
22
26
// The furthast forwards a pattern can move without semantic changes
23
27
let forwards_blocking_idxs: Vec < _ > = resolved_pats
@@ -128,21 +132,22 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) {
128
132
}
129
133
}
130
134
131
- #[ derive( Debug ) ]
132
- enum ResolvedPat < ' hir > {
135
+ #[ derive( Clone , Copy ) ]
136
+ enum ResolvedPat < ' hir , ' arena > {
133
137
Wild ,
134
- Struct ( Option < DefId > , Vec < ( Symbol , ResolvedPat < ' hir > ) > ) ,
135
- Sequence ( Option < DefId > , Vec < ResolvedPat < ' hir > > , Option < usize > ) ,
136
- Or ( Vec < ResolvedPat < ' hir > > ) ,
138
+ Struct ( Option < DefId > , & ' arena [ ( Symbol , Self ) ] ) ,
139
+ Tuple ( Option < DefId > , & ' arena [ Self ] ) ,
140
+ Or ( & ' arena [ Self ] ) ,
137
141
Path ( Option < DefId > ) ,
138
142
LitStr ( Symbol ) ,
139
143
LitBytes ( & ' hir [ u8 ] ) ,
140
144
LitInt ( u128 ) ,
141
145
LitBool ( bool ) ,
142
146
Range ( PatRange ) ,
147
+ Slice ( & ' arena [ Self ] , & ' arena [ Self ] , bool ) ,
143
148
}
144
149
145
- #[ derive( Debug ) ]
150
+ #[ derive( Clone , Copy ) ]
146
151
struct PatRange {
147
152
start : u128 ,
148
153
end : u128 ,
@@ -177,28 +182,66 @@ impl PatRange {
177
182
}
178
183
}
179
184
180
- impl < ' hir > ResolvedPat < ' hir > {
181
- fn from_pat ( cx : & LateContext < ' _ > , pat : & ' hir Pat < ' _ > ) -> Self {
185
+ #[ allow( clippy:: similar_names) ]
186
+ impl < ' hir , ' arena > ResolvedPat < ' hir , ' arena > {
187
+ #[ allow( clippy:: too_many_lines) ]
188
+ fn from_pat ( cx : & LateContext < ' _ > , arena : & ' arena DroplessArena , pat : & ' hir Pat < ' _ > ) -> Self {
182
189
match pat. kind {
183
190
PatKind :: Wild | PatKind :: Binding ( .., None ) => Self :: Wild ,
184
- PatKind :: Binding ( .., Some ( pat) ) | PatKind :: Box ( pat) | PatKind :: Ref ( pat, _) => Self :: from_pat ( cx, pat) ,
191
+ PatKind :: Binding ( .., Some ( pat) ) | PatKind :: Box ( pat) | PatKind :: Ref ( pat, _) => {
192
+ Self :: from_pat ( cx, arena, pat)
193
+ } ,
185
194
PatKind :: Struct ( ref path, fields, _) => {
186
- let mut fields: Vec < _ > = fields
187
- . iter ( )
188
- . map ( |f| ( f. ident . name , Self :: from_pat ( cx, f. pat ) ) )
189
- . collect ( ) ;
195
+ let fields =
196
+ arena. alloc_from_iter ( fields. iter ( ) . map ( |f| ( f. ident . name , Self :: from_pat ( cx, arena, f. pat ) ) ) ) ;
190
197
fields. sort_by_key ( |& ( name, _) | name) ;
191
198
Self :: Struct ( cx. qpath_res ( path, pat. hir_id ) . opt_def_id ( ) , fields)
192
199
} ,
193
- PatKind :: TupleStruct ( ref path, pats, wild_idx) => Self :: Sequence (
194
- cx. qpath_res ( path, pat. hir_id ) . opt_def_id ( ) ,
195
- pats. iter ( ) . map ( |pat| Self :: from_pat ( cx, pat) ) . collect ( ) ,
196
- wild_idx,
197
- ) ,
198
- PatKind :: Or ( pats) => Self :: Or ( pats. iter ( ) . map ( |pat| Self :: from_pat ( cx, pat) ) . collect ( ) ) ,
200
+ PatKind :: TupleStruct ( ref path, pats, wild_idx) => {
201
+ let adt = match cx. typeck_results ( ) . pat_ty ( pat) . ty_adt_def ( ) {
202
+ Some ( x) => x,
203
+ None => return Self :: Wild ,
204
+ } ;
205
+ let ( var_id, variant) = if adt. is_enum ( ) {
206
+ match cx. qpath_res ( path, pat. hir_id ) . opt_def_id ( ) {
207
+ Some ( x) => ( Some ( x) , adt. variant_with_ctor_id ( x) ) ,
208
+ None => return Self :: Wild ,
209
+ }
210
+ } else {
211
+ ( None , adt. non_enum_variant ( ) )
212
+ } ;
213
+ let ( front, back) = match wild_idx {
214
+ Some ( i) => pats. split_at ( i) ,
215
+ None => ( pats, [ ] . as_slice ( ) ) ,
216
+ } ;
217
+ let pats = arena. alloc_from_iter (
218
+ front
219
+ . iter ( )
220
+ . map ( |pat| Self :: from_pat ( cx, arena, pat) )
221
+ . chain ( iter:: repeat_with ( || Self :: Wild ) . take ( variant. fields . len ( ) - pats. len ( ) ) )
222
+ . chain ( back. iter ( ) . map ( |pat| Self :: from_pat ( cx, arena, pat) ) ) ,
223
+ ) ;
224
+ Self :: Tuple ( var_id, pats)
225
+ } ,
226
+ PatKind :: Or ( pats) => Self :: Or ( arena. alloc_from_iter ( pats. iter ( ) . map ( |pat| Self :: from_pat ( cx, arena, pat) ) ) ) ,
199
227
PatKind :: Path ( ref path) => Self :: Path ( cx. qpath_res ( path, pat. hir_id ) . opt_def_id ( ) ) ,
200
228
PatKind :: Tuple ( pats, wild_idx) => {
201
- Self :: Sequence ( None , pats. iter ( ) . map ( |pat| Self :: from_pat ( cx, pat) ) . collect ( ) , wild_idx)
229
+ let field_count = match cx. typeck_results ( ) . pat_ty ( pat) . kind ( ) {
230
+ ty:: Tuple ( subs) => subs. len ( ) ,
231
+ _ => return Self :: Wild ,
232
+ } ;
233
+ let ( front, back) = match wild_idx {
234
+ Some ( i) => pats. split_at ( i) ,
235
+ None => ( pats, [ ] . as_slice ( ) ) ,
236
+ } ;
237
+ let pats = arena. alloc_from_iter (
238
+ front
239
+ . iter ( )
240
+ . map ( |pat| Self :: from_pat ( cx, arena, pat) )
241
+ . chain ( iter:: repeat_with ( || Self :: Wild ) . take ( field_count - pats. len ( ) ) )
242
+ . chain ( back. iter ( ) . map ( |pat| Self :: from_pat ( cx, arena, pat) ) ) ,
243
+ ) ;
244
+ Self :: Tuple ( None , pats)
202
245
} ,
203
246
PatKind :: Lit ( e) => match & e. kind {
204
247
ExprKind :: Lit ( lit) => match lit. node {
@@ -239,23 +282,22 @@ impl<'hir> ResolvedPat<'hir> {
239
282
} ;
240
283
Self :: Range ( PatRange { start, end, bounds } )
241
284
} ,
242
- PatKind :: Slice ( pats, wild, pats2) => Self :: Sequence (
243
- None ,
244
- pats. iter ( )
245
- . chain ( pats2. iter ( ) )
246
- . map ( |pat| Self :: from_pat ( cx, pat) )
247
- . collect ( ) ,
248
- wild. map ( |_| pats. len ( ) ) ,
285
+ PatKind :: Slice ( front, wild_pat, back) => Self :: Slice (
286
+ arena. alloc_from_iter ( front. iter ( ) . map ( |pat| Self :: from_pat ( cx, arena, pat) ) ) ,
287
+ arena. alloc_from_iter ( back. iter ( ) . map ( |pat| Self :: from_pat ( cx, arena, pat) ) ) ,
288
+ wild_pat. is_some ( ) ,
249
289
) ,
250
290
}
251
291
}
252
292
253
293
/// Checks if two patterns overlap in the values they can match assuming they are for the same
254
294
/// type.
255
295
fn can_also_match ( & self , other : & Self ) -> bool {
256
- match ( self , other) {
296
+ match ( * self , * other) {
257
297
( Self :: Wild , _) | ( _, Self :: Wild ) => true ,
258
- ( Self :: Or ( pats) , other) | ( other, Self :: Or ( pats) ) => pats. iter ( ) . any ( |pat| pat. can_also_match ( other) ) ,
298
+ ( Self :: Or ( pats) , ref other) | ( ref other, Self :: Or ( pats) ) => {
299
+ pats. iter ( ) . any ( |pat| pat. can_also_match ( other) )
300
+ } ,
259
301
( Self :: Struct ( lpath, lfields) , Self :: Struct ( rpath, rfields) ) => {
260
302
if lpath != rpath {
261
303
return false ;
@@ -287,39 +329,24 @@ impl<'hir> ResolvedPat<'hir> {
287
329
}
288
330
true
289
331
} ,
290
- ( Self :: Sequence ( lpath, lpats, lwild_idx ) , Self :: Sequence ( rpath, rpats, rwild_idx ) ) => {
332
+ ( Self :: Tuple ( lpath, lpats) , Self :: Tuple ( rpath, rpats) ) => {
291
333
if lpath != rpath {
292
334
return false ;
293
335
}
294
-
295
- let ( lpats_start, lpats_end) = lwild_idx
296
- . or ( * rwild_idx)
297
- . map_or ( ( & * * lpats, [ ] . as_slice ( ) ) , |idx| lpats. split_at ( idx) ) ;
298
- let ( rpats_start, rpats_end) = rwild_idx
299
- . or ( * lwild_idx)
300
- . map_or ( ( & * * rpats, [ ] . as_slice ( ) ) , |idx| rpats. split_at ( idx) ) ;
301
-
302
- lpats_start
303
- . iter ( )
304
- . zip ( rpats_start. iter ( ) )
305
- . all ( |( lpat, rpat) | lpat. can_also_match ( rpat) )
306
- // `lpats_end` and `rpats_end` lengths may be disjointed, so start from the end and ignore any
307
- // extras.
308
- && lpats_end
336
+ lpats
309
337
. iter ( )
310
- . rev ( )
311
- . zip ( rpats_end. iter ( ) . rev ( ) )
338
+ . zip ( rpats. iter ( ) )
312
339
. all ( |( lpat, rpat) | lpat. can_also_match ( rpat) )
313
340
} ,
314
341
( Self :: Path ( x) , Self :: Path ( y) ) => x == y,
315
342
( Self :: LitStr ( x) , Self :: LitStr ( y) ) => x == y,
316
343
( Self :: LitBytes ( x) , Self :: LitBytes ( y) ) => x == y,
317
344
( Self :: LitInt ( x) , Self :: LitInt ( y) ) => x == y,
318
345
( Self :: LitBool ( x) , Self :: LitBool ( y) ) => x == y,
319
- ( Self :: Range ( x) , Self :: Range ( y) ) => x. overlaps ( y) ,
320
- ( Self :: Range ( range) , Self :: LitInt ( x) ) | ( Self :: LitInt ( x) , Self :: Range ( range) ) => range. contains ( * x) ,
346
+ ( Self :: Range ( ref x) , Self :: Range ( ref y) ) => x. overlaps ( y) ,
347
+ ( Self :: Range ( ref range) , Self :: LitInt ( x) ) | ( Self :: LitInt ( x) , Self :: Range ( ref range) ) => range. contains ( x) ,
321
348
322
- // Todo: Lit* with Path, Range with Path, LitBytes with Sequence
349
+ // Todo: Lit* with Path, Range with Path, LitBytes with Slice, Slice with Slice
323
350
_ => true ,
324
351
}
325
352
}
0 commit comments