11use clippy_utils:: diagnostics:: span_lint_and_then;
22use clippy_utils:: source:: snippet;
33use clippy_utils:: { path_to_local, search_same, SpanlessEq , SpanlessHash } ;
4+ use core:: iter;
5+ use rustc_arena:: DroplessArena ;
46use rustc_ast:: ast:: LitKind ;
57use rustc_hir:: def_id:: DefId ;
68use rustc_hir:: { Arm , Expr , ExprKind , HirId , HirIdMap , HirIdSet , Pat , PatKind , RangeEnd } ;
79use rustc_lint:: LateContext ;
10+ use rustc_middle:: ty;
811use rustc_span:: Symbol ;
912use std:: collections:: hash_map:: Entry ;
1013
@@ -17,7 +20,8 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) {
1720 h. finish ( )
1821 } ;
1922
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 ( ) ;
2125
2226 // The furthast forwards a pattern can move without semantic changes
2327 let forwards_blocking_idxs: Vec < _ > = resolved_pats
@@ -128,21 +132,22 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) {
128132 }
129133}
130134
131- #[ derive( Debug ) ]
132- enum ResolvedPat < ' hir > {
135+ #[ derive( Clone , Copy ) ]
136+ enum ResolvedPat < ' hir , ' arena > {
133137 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 ] ) ,
137141 Path ( Option < DefId > ) ,
138142 LitStr ( Symbol ) ,
139143 LitBytes ( & ' hir [ u8 ] ) ,
140144 LitInt ( u128 ) ,
141145 LitBool ( bool ) ,
142146 Range ( PatRange ) ,
147+ Slice ( & ' arena [ Self ] , & ' arena [ Self ] , bool ) ,
143148}
144149
145- #[ derive( Debug ) ]
150+ #[ derive( Clone , Copy ) ]
146151struct PatRange {
147152 start : u128 ,
148153 end : u128 ,
@@ -177,28 +182,66 @@ impl PatRange {
177182 }
178183}
179184
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 {
182189 match pat. kind {
183190 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+ } ,
185194 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 ) ) ) ) ;
190197 fields. sort_by_key ( |& ( name, _) | name) ;
191198 Self :: Struct ( cx. qpath_res ( path, pat. hir_id ) . opt_def_id ( ) , fields)
192199 } ,
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) ) ) ) ,
199227 PatKind :: Path ( ref path) => Self :: Path ( cx. qpath_res ( path, pat. hir_id ) . opt_def_id ( ) ) ,
200228 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)
202245 } ,
203246 PatKind :: Lit ( e) => match & e. kind {
204247 ExprKind :: Lit ( lit) => match lit. node {
@@ -239,23 +282,22 @@ impl<'hir> ResolvedPat<'hir> {
239282 } ;
240283 Self :: Range ( PatRange { start, end, bounds } )
241284 } ,
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 ( ) ,
249289 ) ,
250290 }
251291 }
252292
253293 /// Checks if two patterns overlap in the values they can match assuming they are for the same
254294 /// type.
255295 fn can_also_match ( & self , other : & Self ) -> bool {
256- match ( self , other) {
296+ match ( * self , * other) {
257297 ( 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+ } ,
259301 ( Self :: Struct ( lpath, lfields) , Self :: Struct ( rpath, rfields) ) => {
260302 if lpath != rpath {
261303 return false ;
@@ -287,39 +329,24 @@ impl<'hir> ResolvedPat<'hir> {
287329 }
288330 true
289331 } ,
290- ( Self :: Sequence ( lpath, lpats, lwild_idx ) , Self :: Sequence ( rpath, rpats, rwild_idx ) ) => {
332+ ( Self :: Tuple ( lpath, lpats) , Self :: Tuple ( rpath, rpats) ) => {
291333 if lpath != rpath {
292334 return false ;
293335 }
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
309337 . iter ( )
310- . rev ( )
311- . zip ( rpats_end. iter ( ) . rev ( ) )
338+ . zip ( rpats. iter ( ) )
312339 . all ( |( lpat, rpat) | lpat. can_also_match ( rpat) )
313340 } ,
314341 ( Self :: Path ( x) , Self :: Path ( y) ) => x == y,
315342 ( Self :: LitStr ( x) , Self :: LitStr ( y) ) => x == y,
316343 ( Self :: LitBytes ( x) , Self :: LitBytes ( y) ) => x == y,
317344 ( Self :: LitInt ( x) , Self :: LitInt ( y) ) => x == y,
318345 ( 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) ,
321348
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
323350 _ => true ,
324351 }
325352 }
0 commit comments