@@ -4,7 +4,7 @@ use clippy_utils::{SpanlessEq, SpanlessHash};
44use  core:: hash:: { Hash ,  Hasher } ; 
55use  if_chain:: if_chain; 
66use  itertools:: Itertools ; 
7- use  rustc_data_structures:: fx:: FxHashMap ; 
7+ use  rustc_data_structures:: fx:: { FxHashMap ,   FxHashSet } ; 
88use  rustc_data_structures:: unhash:: UnhashMap ; 
99use  rustc_errors:: Applicability ; 
1010use  rustc_hir:: def:: Res ; 
@@ -103,7 +103,6 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds {
103103    fn  check_generics ( & mut  self ,  cx :  & LateContext < ' tcx > ,  gen :  & ' tcx  Generics < ' _ > )  { 
104104        self . check_type_repetition ( cx,  gen) ; 
105105        check_trait_bound_duplication ( cx,  gen) ; 
106-         check_bounds_or_where_duplication ( cx,  gen) ; 
107106    } 
108107
109108    fn  check_item ( & mut  self ,  cx :  & LateContext < ' tcx > ,  item :  & ' tcx  Item < ' tcx > )  { 
@@ -234,35 +233,61 @@ impl TraitBounds {
234233} 
235234
236235fn  check_trait_bound_duplication ( cx :  & LateContext < ' _ > ,  gen :  & ' _  Generics < ' _ > )  { 
237-     if  gen. span . from_expansion ( )  || gen . params . is_empty ( )  || gen . predicates . is_empty ( )   { 
236+     if  gen. span . from_expansion ( )  { 
238237        return ; 
239238    } 
240239
241-     let  mut  map = FxHashMap :: < _ ,  Vec < _ > > :: default ( ) ; 
242-     for  predicate in  gen. predicates  { 
240+     // Explanation: 
241+     // fn bad_foo<T: Clone + Default, Z: Copy>(arg0: T, arg1: Z) 
242+     // where T: Clone + Default, { unimplemented!(); } 
243+     //       ^^^^^^^^^^^^^^^^^^ 
244+     //       | 
245+     // collects each of these where clauses into a set keyed by generic name and comparable trait 
246+     // eg. (T, Clone) 
247+     let  where_predicates = gen
248+         . predicates 
249+         . iter ( ) 
250+         . filter_map ( |pred| { 
251+             if_chain !  { 
252+                 if  pred. in_where_clause( ) ; 
253+                 if  let  WherePredicate :: BoundPredicate ( bound_predicate)  = pred; 
254+                 if  let  TyKind :: Path ( QPath :: Resolved ( _,  path) )  =  bound_predicate. bounded_ty. kind; 
255+                 then { 
256+                     return  Some ( 
257+                         rollup_traits( cx,  bound_predicate. bounds,  "these where clauses contain repeated elements" ) 
258+                         . into_keys( ) . map( |trait_ref| ( path. res,  trait_ref) ) ) 
259+                 } 
260+             } 
261+             None 
262+         } ) 
263+         . flatten ( ) 
264+         . collect :: < FxHashSet < _ > > ( ) ; 
265+ 
266+     // Explanation: 
267+     // fn bad_foo<T: Clone + Default, Z: Copy>(arg0: T, arg1: Z) ... 
268+     //            ^^^^^^^^^^^^^^^^^^  ^^^^^^^ 
269+     //            | 
270+     // compare trait bounds keyed by generic name and comparable trait to collected where 
271+     // predicates eg. (T, Clone) 
272+     for  predicate in  gen. predicates . iter ( ) . filter ( |pred| !pred. in_where_clause ( ) )  { 
243273        if_chain !  { 
244-             if  let  WherePredicate :: BoundPredicate ( ref  bound_predicate)  = predicate; 
274+             if  let  WherePredicate :: BoundPredicate ( bound_predicate)  = predicate; 
245275            if  bound_predicate. origin != PredicateOrigin :: ImplTrait ; 
246276            if  !bound_predicate. span. from_expansion( ) ; 
247-             if  let  TyKind :: Path ( QPath :: Resolved ( _,  Path  {  segments,  .. } ) )  = bound_predicate. bounded_ty. kind; 
248-             if  let  Some ( segment)  = segments. first( ) ; 
277+             if  let  TyKind :: Path ( QPath :: Resolved ( _,  path) )  =  bound_predicate. bounded_ty. kind; 
249278            then { 
250-                 for  ( res_where,  _,  span_where)  in bound_predicate. bounds. iter( ) . filter_map( get_trait_info_from_bound)  { 
251-                     let  trait_resolutions_direct = map. entry( segment. ident) . or_default( ) ; 
252-                     if  let  Some ( ( _,  span_direct) )  = trait_resolutions_direct
253-                                                 . iter( ) 
254-                                                 . find( |( res_direct,  _) | * res_direct == res_where)  { 
279+                 let  traits = rollup_traits( cx,  bound_predicate. bounds,  "these bounds contain repeated elements" ) ; 
280+                 for  ( trait_ref,  span)  in traits { 
281+                     let  key = ( path. res,  trait_ref) ; 
282+                     if  where_predicates. contains( & key)  { 
255283                        span_lint_and_help( 
256284                            cx, 
257285                            TRAIT_DUPLICATION_IN_BOUNDS , 
258-                             * span_direct , 
286+                             span , 
259287                            "this trait bound is already specified in the where clause" , 
260288                            None , 
261289                            "consider removing this trait bound" , 
262-                         ) ; 
263-                     } 
264-                     else { 
265-                         trait_resolutions_direct. push( ( res_where,  span_where) ) ; 
290+                             ) ; 
266291                    } 
267292                } 
268293            } 
@@ -273,23 +298,6 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
273298#[ derive( PartialEq ,  Eq ,  Hash ,  Debug ) ]  
274299struct  ComparableTraitRef ( Res ,  Vec < Res > ) ; 
275300
276- fn  check_bounds_or_where_duplication ( cx :  & LateContext < ' _ > ,  gen :  & ' _  Generics < ' _ > )  { 
277-     if  gen. span . from_expansion ( )  { 
278-         return ; 
279-     } 
280- 
281-     for  predicate in  gen. predicates  { 
282-         if  let  WherePredicate :: BoundPredicate ( ref  bound_predicate)  = predicate { 
283-             let  msg = if  predicate. in_where_clause ( )  { 
284-                 "these where clauses contain repeated elements" 
285-             }  else  { 
286-                 "these bounds contain repeated elements" 
287-             } ; 
288-             rollup_traits ( cx,  bound_predicate. bounds ,  msg) ; 
289-         } 
290-     } 
291- } 
292- 
293301fn  get_trait_info_from_bound < ' a > ( bound :  & ' a  GenericBound < ' _ > )  -> Option < ( Res ,  & ' a  [ PathSegment < ' a > ] ,  Span ) >  { 
294302    if  let  GenericBound :: Trait ( t,  tbm)  = bound { 
295303        let  trait_path = t. trait_ref . path ; 
@@ -331,7 +339,7 @@ fn into_comparable_trait_ref(trait_ref: &TraitRef<'_>) -> ComparableTraitRef {
331339    ) 
332340} 
333341
334- fn  rollup_traits ( cx :  & LateContext < ' _ > ,  bounds :  & [ GenericBound < ' _ > ] ,  msg :  & str )  { 
342+ fn  rollup_traits ( cx :  & LateContext < ' _ > ,  bounds :  & [ GenericBound < ' _ > ] ,  msg :  & str )  ->  FxHashMap < ComparableTraitRef ,   Span >   { 
335343    let  mut  map = FxHashMap :: default ( ) ; 
336344    let  mut  repeated_res = false ; 
337345
@@ -373,4 +381,6 @@ fn rollup_traits(cx: &LateContext<'_>, bounds: &[GenericBound<'_>], msg: &str) {
373381            ) ; 
374382        } 
375383    } 
384+ 
385+     map
376386} 
0 commit comments