@@ -9,8 +9,8 @@ use rustc_data_structures::unhash::UnhashMap;
9
9
use rustc_errors:: Applicability ;
10
10
use rustc_hir:: def:: Res ;
11
11
use rustc_hir:: {
12
- GenericBound , Generics , Item , ItemKind , Node , Path , PathSegment , PredicateOrigin , QPath , TraitBoundModifier ,
13
- TraitItem , Ty , TyKind , WherePredicate ,
12
+ GenericArg , GenericBound , Generics , Item , ItemKind , Node , Path , PathSegment , PredicateOrigin , QPath ,
13
+ TraitBoundModifier , TraitItem , TraitRef , Ty , TyKind , WherePredicate ,
14
14
} ;
15
15
use rustc_lint:: { LateContext , LateLintPass } ;
16
16
use rustc_session:: { declare_tool_lint, impl_lint_pass} ;
@@ -271,61 +271,22 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
271
271
}
272
272
}
273
273
274
- fn check_bounds_or_where_duplication ( cx : & LateContext < ' _ > , gen : & ' _ Generics < ' _ > ) {
275
- fn rollup_traits ( cx : & LateContext < ' _ > , bounds : & [ GenericBound < ' _ > ] , msg : & str ) {
276
- let mut map = FxHashMap :: default ( ) ;
277
- let mut repeated_spans = false ;
278
- for bound in bounds. iter ( ) . filter_map ( get_trait_info_from_bound) {
279
- let ( definition, _, span_direct) = bound;
280
- if map. insert ( definition, span_direct) . is_some ( ) {
281
- repeated_spans = true ;
282
- }
283
- }
274
+ #[ derive( PartialEq , Eq , Hash , Debug ) ]
275
+ struct ComparableTraitRef ( Res , Vec < Res > ) ;
284
276
285
- if_chain ! {
286
- if repeated_spans;
287
- if let Some ( first_trait) = bounds. get( 0 ) ;
288
- if let Some ( last_trait) = bounds. iter( ) . last( ) ;
289
- then {
290
- let all_trait_span = first_trait. span( ) . to( last_trait. span( ) ) ;
291
-
292
- let mut traits = map. values( )
293
- . filter_map( |span| snippet_opt( cx, * span) )
294
- . collect:: <Vec <_>>( ) ;
295
- traits. sort_unstable( ) ;
296
- let traits = traits. join( " + " ) ;
297
-
298
- span_lint_and_sugg(
299
- cx,
300
- REPEATED_WHERE_CLAUSE_OR_TRAIT_BOUND ,
301
- all_trait_span,
302
- msg,
303
- "try" ,
304
- traits,
305
- Applicability :: MachineApplicable
306
- ) ;
307
- }
308
- }
309
- }
310
-
311
- if gen. span . from_expansion ( ) || ( gen. params . is_empty ( ) && gen. where_clause . predicates . is_empty ( ) ) {
277
+ fn check_bounds_or_where_duplication ( cx : & LateContext < ' _ > , gen : & ' _ Generics < ' _ > ) {
278
+ if gen. span . from_expansion ( ) {
312
279
return ;
313
280
}
314
281
315
- for param in gen. params {
316
- if let ParamName :: Plain ( _) = param. name {
317
- // other alternatives are errors and elided which won't have duplicates
318
- rollup_traits ( cx, param. bounds , "this trait bound contains repeated elements" ) ;
319
- }
320
- }
321
-
322
- for predicate in gen. where_clause . predicates {
282
+ for predicate in gen. predicates {
323
283
if let WherePredicate :: BoundPredicate ( ref bound_predicate) = predicate {
324
- rollup_traits (
325
- cx,
326
- bound_predicate. bounds ,
327
- "this where clause contains repeated elements" ,
328
- ) ;
284
+ let msg = if predicate. in_where_clause ( ) {
285
+ "these where clauses contain repeated elements"
286
+ } else {
287
+ "these bounds contain repeated elements"
288
+ } ;
289
+ rollup_traits ( cx, bound_predicate. bounds , msg) ;
329
290
}
330
291
}
331
292
}
@@ -346,3 +307,68 @@ fn get_trait_info_from_bound<'a>(bound: &'a GenericBound<'_>) -> Option<(Res, &'
346
307
None
347
308
}
348
309
}
310
+
311
+ // FIXME: ComparableTraitRef does not support nested bounds needed for associated_type_bounds
312
+ fn into_comparable_trait_ref ( trait_ref : & TraitRef < ' _ > ) -> ComparableTraitRef {
313
+ ComparableTraitRef (
314
+ trait_ref. path . res ,
315
+ trait_ref
316
+ . path
317
+ . segments
318
+ . iter ( )
319
+ . filter_map ( |segment| {
320
+ // get trait bound type arguments
321
+ Some ( segment. args ?. args . iter ( ) . filter_map ( |arg| {
322
+ if_chain ! {
323
+ if let GenericArg :: Type ( ty) = arg;
324
+ if let TyKind :: Path ( QPath :: Resolved ( _, path) ) = ty. kind;
325
+ then { return Some ( path. res) }
326
+ }
327
+ None
328
+ } ) )
329
+ } )
330
+ . flatten ( )
331
+ . collect ( ) ,
332
+ )
333
+ }
334
+
335
+ fn rollup_traits ( cx : & LateContext < ' _ > , bounds : & [ GenericBound < ' _ > ] , msg : & str ) {
336
+ let mut map = FxHashMap :: default ( ) ;
337
+ let mut repeated_res = false ;
338
+ for bound in bounds. iter ( ) . filter_map ( |bound| {
339
+ if let GenericBound :: Trait ( t, _) = bound {
340
+ Some ( ( into_comparable_trait_ref ( & t. trait_ref ) , t. span ) )
341
+ } else {
342
+ None
343
+ }
344
+ } ) {
345
+ let ( comparable_bound, span_direct) = bound;
346
+ if map. insert ( comparable_bound, span_direct) . is_some ( ) {
347
+ repeated_res = true ;
348
+ }
349
+ }
350
+
351
+ if_chain ! {
352
+ if repeated_res;
353
+ if let [ first_trait, .., last_trait] = bounds;
354
+ then {
355
+ let all_trait_span = first_trait. span( ) . to( last_trait. span( ) ) ;
356
+
357
+ let mut traits = map. values( )
358
+ . filter_map( |span| snippet_opt( cx, * span) )
359
+ . collect:: <Vec <_>>( ) ;
360
+ traits. sort_unstable( ) ;
361
+ let traits = traits. join( " + " ) ;
362
+
363
+ span_lint_and_sugg(
364
+ cx,
365
+ REPEATED_WHERE_CLAUSES_OR_TRAIT_BOUNDS ,
366
+ all_trait_span,
367
+ msg,
368
+ "try" ,
369
+ traits,
370
+ Applicability :: MachineApplicable
371
+ ) ;
372
+ }
373
+ }
374
+ }
0 commit comments