@@ -15,6 +15,7 @@ use rustc_hir::{
15
15
use rustc_lint:: { LateContext , LateLintPass } ;
16
16
use rustc_session:: { declare_tool_lint, impl_lint_pass} ;
17
17
use rustc_span:: { BytePos , Span } ;
18
+ use std:: collections:: hash_map:: Entry ;
18
19
19
20
declare_clippy_lint ! {
20
21
/// ### What it does
@@ -255,7 +256,7 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
255
256
then {
256
257
return Some (
257
258
rollup_traits( cx, bound_predicate. bounds, "these where clauses contain repeated elements" )
258
- . into_keys ( ) . map( |trait_ref| ( path. res, trait_ref) ) )
259
+ . into_iter ( ) . map( |( trait_ref, _ ) | ( path. res, trait_ref) ) )
259
260
}
260
261
}
261
262
None
@@ -295,8 +296,13 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
295
296
}
296
297
}
297
298
298
- #[ derive( PartialEq , Eq , Hash , Debug ) ]
299
+ #[ derive( Clone , PartialEq , Eq , Hash , Debug ) ]
299
300
struct ComparableTraitRef ( Res , Vec < Res > ) ;
301
+ impl Default for ComparableTraitRef {
302
+ fn default ( ) -> Self {
303
+ Self ( Res :: Err , Vec :: new ( ) )
304
+ }
305
+ }
300
306
301
307
fn get_trait_info_from_bound < ' a > ( bound : & ' a GenericBound < ' _ > ) -> Option < ( Res , & ' a [ PathSegment < ' a > ] , Span ) > {
302
308
if let GenericBound :: Trait ( t, tbm) = bound {
@@ -339,7 +345,7 @@ fn into_comparable_trait_ref(trait_ref: &TraitRef<'_>) -> ComparableTraitRef {
339
345
)
340
346
}
341
347
342
- fn rollup_traits ( cx : & LateContext < ' _ > , bounds : & [ GenericBound < ' _ > ] , msg : & str ) -> FxHashMap < ComparableTraitRef , Span > {
348
+ fn rollup_traits ( cx : & LateContext < ' _ > , bounds : & [ GenericBound < ' _ > ] , msg : & str ) -> Vec < ( ComparableTraitRef , Span ) > {
343
349
let mut map = FxHashMap :: default ( ) ;
344
350
let mut repeated_res = false ;
345
351
@@ -351,23 +357,33 @@ fn rollup_traits(cx: &LateContext<'_>, bounds: &[GenericBound<'_>], msg: &str) -
351
357
}
352
358
} ;
353
359
360
+ let mut i = 0usize ;
354
361
for bound in bounds. iter ( ) . filter_map ( only_comparable_trait_refs) {
355
362
let ( comparable_bound, span_direct) = bound;
356
- if map. insert ( comparable_bound, span_direct) . is_some ( ) {
357
- repeated_res = true ;
363
+ match map. entry ( comparable_bound) {
364
+ Entry :: Occupied ( _) => repeated_res = true ,
365
+ Entry :: Vacant ( e) => {
366
+ e. insert ( ( span_direct, i) ) ;
367
+ i += 1 ;
368
+ } ,
358
369
}
359
370
}
360
371
372
+ // Put bounds in source order
373
+ let mut comparable_bounds = vec ! [ Default :: default ( ) ; map. len( ) ] ;
374
+ for ( k, ( v, i) ) in map {
375
+ comparable_bounds[ i] = ( k, v) ;
376
+ }
377
+
361
378
if_chain ! {
362
379
if repeated_res;
363
380
if let [ first_trait, .., last_trait] = bounds;
364
381
then {
365
382
let all_trait_span = first_trait. span( ) . to( last_trait. span( ) ) ;
366
383
367
- let mut traits = map . values ( )
368
- . filter_map( |span| snippet_opt( cx, * span) )
384
+ let traits = comparable_bounds . iter ( )
385
+ . filter_map( |& ( _ , span) | snippet_opt( cx, span) )
369
386
. collect:: <Vec <_>>( ) ;
370
- traits. sort_unstable( ) ;
371
387
let traits = traits. join( " + " ) ;
372
388
373
389
span_lint_and_sugg(
@@ -382,5 +398,5 @@ fn rollup_traits(cx: &LateContext<'_>, bounds: &[GenericBound<'_>], msg: &str) -
382
398
}
383
399
}
384
400
385
- map
401
+ comparable_bounds
386
402
}
0 commit comments