@@ -57,6 +57,7 @@ use rustc_trait_selection::traits::misc::can_type_implement_copy;
5757use crate :: nonstandard_style:: { method_context, MethodLateContext } ;
5858
5959use std:: fmt:: Write ;
60+ use std:: hash:: { Hash , Hasher } ;
6061use tracing:: { debug, trace} ;
6162
6263// hardwired lints from librustc_middle
@@ -3174,61 +3175,82 @@ declare_lint_pass!(TraitDuplicationInBounds => [TRAIT_DUPLICATION_IN_BOUNDS]);
31743175
31753176impl < ' tcx > LateLintPass < ' tcx > for TraitDuplicationInBounds {
31763177 fn check_generics ( & mut self , cx : & LateContext < ' tcx > , gen : & ' tcx hir:: Generics < ' _ > ) {
3177- fn get_trait_res_span_from_bound ( bound : & hir:: GenericBound < ' _ > ) -> Option < ( Res , Span ) > {
3178- if let hir:: GenericBound :: Trait ( t, _) = bound {
3179- Some ( ( t. trait_ref . path . res , t. span ) )
3180- } else {
3181- None
3178+ struct TraitRes {
3179+ res : Res ,
3180+ span : Span ,
3181+ }
3182+
3183+ impl TraitRes {
3184+ fn from_bound ( bound : & hir:: GenericBound < ' _ > ) -> Option < Self > {
3185+ if let hir:: GenericBound :: Trait ( t, _) = bound {
3186+ Some ( Self { res : t. trait_ref . path . res , span : t. span } )
3187+ } else {
3188+ None
3189+ }
31823190 }
31833191 }
3184- if gen. span . from_expansion ( )
3185- || gen. params . is_empty ( )
3186- || gen. where_clause . predicates . is_empty ( )
3187- {
3192+
3193+ impl PartialEq for TraitRes {
3194+ fn eq ( & self , other : & Self ) -> bool {
3195+ self . res == other. res
3196+ }
3197+ }
3198+
3199+ impl Hash for TraitRes {
3200+ fn hash < H : Hasher > ( & self , state : & mut H ) {
3201+ self . res . hash ( state)
3202+ }
3203+ }
3204+
3205+ impl Eq for TraitRes { }
3206+
3207+ if gen. span . from_expansion ( ) {
31883208 return ;
31893209 }
31903210
3191- let mut map = FxHashMap :: default ( ) ;
3211+ let mut trait_resolutions = FxHashMap :: default ( ) ;
31923212 for param in gen. params {
31933213 if let hir:: ParamName :: Plain ( ref ident) = param. name {
3194- let res = param
3195- . bounds
3196- . iter ( )
3197- . filter_map ( get_trait_res_span_from_bound)
3198- . collect :: < Vec < _ > > ( ) ;
3199- map. insert ( * ident, res) ;
3214+ let mut uniq = FxHashSet :: default ( ) ;
3215+
3216+ for res in param. bounds . iter ( ) . filter_map ( TraitRes :: from_bound) {
3217+ let span = res. span . clone ( ) ;
3218+ if !uniq. insert ( res) {
3219+ cx. struct_span_lint ( TRAIT_DUPLICATION_IN_BOUNDS , span, |lint| {
3220+ lint. build ( "this trait bound has already been specified" )
3221+ . help ( "consider removing this trait bound" )
3222+ . emit ( )
3223+ } ) ;
3224+ }
3225+ }
3226+
3227+ trait_resolutions. insert ( * ident, uniq) ;
32003228 }
32013229 }
32023230
32033231 for predicate in gen. where_clause . predicates {
32043232 if let hir:: WherePredicate :: BoundPredicate ( ref bound_predicate) = predicate {
3205- if !bound_predicate. span . from_expansion ( ) {
3206- if let hir:: TyKind :: Path ( hir:: QPath :: Resolved ( _, hir:: Path { segments, .. } ) ) =
3207- bound_predicate. bounded_ty . kind
3208- {
3209- if let Some ( segment) = segments. first ( ) {
3210- if let Some ( trait_resolutions_direct) = map. get ( & segment. ident ) {
3211- for ( res_where, _) in bound_predicate
3212- . bounds
3213- . iter ( )
3214- . filter_map ( get_trait_res_span_from_bound)
3215- {
3216- if let Some ( ( _, span_direct) ) = trait_resolutions_direct
3217- . iter ( )
3218- . find ( |( res_direct, _) | * res_direct == res_where)
3219- {
3220- cx. struct_span_lint (
3221- TRAIT_DUPLICATION_IN_BOUNDS ,
3222- * span_direct,
3223- |lint| {
3224- lint. build (
3225- "this trait bound is already specified in the where clause"
3226- )
3227- . help ( "consider removing this trait bound" )
3228- . emit ( )
3229- } ,
3230- ) ;
3231- }
3233+ if let hir:: TyKind :: Path ( hir:: QPath :: Resolved ( _, hir:: Path { segments, .. } ) ) =
3234+ bound_predicate. bounded_ty . kind
3235+ {
3236+ if let Some ( segment) = segments. first ( ) {
3237+ if let Some ( trait_resolutions) = trait_resolutions. get_mut ( & segment. ident ) {
3238+ for res in
3239+ bound_predicate. bounds . iter ( ) . filter_map ( TraitRes :: from_bound)
3240+ {
3241+ let span = res. span . clone ( ) ;
3242+ if !trait_resolutions. insert ( res) {
3243+ cx. struct_span_lint (
3244+ TRAIT_DUPLICATION_IN_BOUNDS ,
3245+ span,
3246+ |lint| {
3247+ lint. build (
3248+ "this trait bound has already been specified" ,
3249+ )
3250+ . help ( "consider removing this trait bound" )
3251+ . emit ( )
3252+ } ,
3253+ ) ;
32323254 }
32333255 }
32343256 }
0 commit comments