@@ -15,6 +15,7 @@ use rustc_hir::{
1515use rustc_lint:: { LateContext , LateLintPass } ;
1616use rustc_session:: { declare_tool_lint, impl_lint_pass} ;
1717use rustc_span:: { BytePos , Span } ;
18+ use std:: collections:: hash_map:: Entry ;
1819
1920declare_clippy_lint ! {
2021 /// ### What it does
@@ -255,7 +256,7 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
255256 then {
256257 return Some (
257258 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) ) )
259260 }
260261 }
261262 None
@@ -295,8 +296,13 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
295296 }
296297}
297298
298- #[ derive( PartialEq , Eq , Hash , Debug ) ]
299+ #[ derive( Clone , PartialEq , Eq , Hash , Debug ) ]
299300struct ComparableTraitRef ( Res , Vec < Res > ) ;
301+ impl Default for ComparableTraitRef {
302+ fn default ( ) -> Self {
303+ Self ( Res :: Err , Vec :: new ( ) )
304+ }
305+ }
300306
301307fn get_trait_info_from_bound < ' a > ( bound : & ' a GenericBound < ' _ > ) -> Option < ( Res , & ' a [ PathSegment < ' a > ] , Span ) > {
302308 if let GenericBound :: Trait ( t, tbm) = bound {
@@ -339,7 +345,7 @@ fn into_comparable_trait_ref(trait_ref: &TraitRef<'_>) -> ComparableTraitRef {
339345 )
340346}
341347
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 ) > {
343349 let mut map = FxHashMap :: default ( ) ;
344350 let mut repeated_res = false ;
345351
@@ -351,23 +357,33 @@ fn rollup_traits(cx: &LateContext<'_>, bounds: &[GenericBound<'_>], msg: &str) -
351357 }
352358 } ;
353359
360+ let mut i = 0usize ;
354361 for bound in bounds. iter ( ) . filter_map ( only_comparable_trait_refs) {
355362 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+ } ,
358369 }
359370 }
360371
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+
361378 if_chain ! {
362379 if repeated_res;
363380 if let [ first_trait, .., last_trait] = bounds;
364381 then {
365382 let all_trait_span = first_trait. span( ) . to( last_trait. span( ) ) ;
366383
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) )
369386 . collect:: <Vec <_>>( ) ;
370- traits. sort_unstable( ) ;
371387 let traits = traits. join( " + " ) ;
372388
373389 span_lint_and_sugg(
@@ -382,5 +398,5 @@ fn rollup_traits(cx: &LateContext<'_>, bounds: &[GenericBound<'_>], msg: &str) -
382398 }
383399 }
384400
385- map
401+ comparable_bounds
386402}
0 commit comments