@@ -2,16 +2,14 @@ use clippy_utils::diagnostics::span_lint_and_then;
22use clippy_utils:: source:: snippet;
33use rustc_errors:: { Applicability , SuggestionStyle } ;
44use rustc_hir:: def_id:: DefId ;
5- use rustc_hir:: intravisit:: FnKind ;
65use rustc_hir:: {
7- Body , FnDecl , FnRetTy , GenericArg , GenericBound , ImplItem , ImplItemKind , ItemKind , OpaqueTy , TraitBoundModifier ,
8- TraitItem , TraitItemKind , TyKind , TypeBinding ,
6+ GenericArg , GenericBound , GenericBounds , ItemKind , PredicateOrigin , TraitBoundModifier , TyKind , TypeBinding ,
7+ WherePredicate ,
98} ;
109use rustc_hir_analysis:: hir_ty_to_ty;
1110use rustc_lint:: { LateContext , LateLintPass } ;
1211use rustc_middle:: ty:: { self , ClauseKind , Generics , Ty , TyCtxt } ;
1312use rustc_session:: declare_lint_pass;
14- use rustc_span:: def_id:: LocalDefId ;
1513use rustc_span:: Span ;
1614
1715declare_clippy_lint ! {
@@ -54,7 +52,7 @@ declare_lint_pass!(ImpliedBoundsInImpls => [IMPLIED_BOUNDS_IN_IMPLS]);
5452fn emit_lint (
5553 cx : & LateContext < ' _ > ,
5654 poly_trait : & rustc_hir:: PolyTraitRef < ' _ > ,
57- opaque_ty : & rustc_hir :: OpaqueTy < ' _ > ,
55+ bounds : GenericBounds < ' _ > ,
5856 index : usize ,
5957 // The bindings that were implied, used for suggestion purposes since removing a bound with associated types
6058 // means we might need to then move it to a different bound
@@ -73,10 +71,10 @@ fn emit_lint(
7371 // to include the `+` token that is ahead or behind,
7472 // so we don't end up with something like `impl + B` or `impl A + `
7573
76- let implied_span_extended = if let Some ( next_bound) = opaque_ty . bounds . get ( index + 1 ) {
74+ let implied_span_extended = if let Some ( next_bound) = bounds. get ( index + 1 ) {
7775 poly_trait. span . to ( next_bound. span ( ) . shrink_to_lo ( ) )
7876 } else if index > 0
79- && let Some ( prev_bound) = opaque_ty . bounds . get ( index - 1 )
77+ && let Some ( prev_bound) = bounds. get ( index - 1 )
8078 {
8179 prev_bound. span ( ) . shrink_to_hi ( ) . to ( poly_trait. span . shrink_to_hi ( ) )
8280 } else {
@@ -240,9 +238,8 @@ struct ImplTraitBound<'tcx> {
240238/// For `impl Deref + DerefMut + Eq` this returns `[Deref, PartialEq]`.
241239/// The `Deref` comes from `DerefMut` because `trait DerefMut: Deref {}`, and `PartialEq` comes from
242240/// `Eq`.
243- fn collect_supertrait_bounds < ' tcx > ( cx : & LateContext < ' tcx > , opaque_ty : & OpaqueTy < ' tcx > ) -> Vec < ImplTraitBound < ' tcx > > {
244- opaque_ty
245- . bounds
241+ fn collect_supertrait_bounds < ' tcx > ( cx : & LateContext < ' tcx > , bounds : GenericBounds < ' tcx > ) -> Vec < ImplTraitBound < ' tcx > > {
242+ bounds
246243 . iter ( )
247244 . filter_map ( |bound| {
248245 if let GenericBound :: Trait ( poly_trait, TraitBoundModifier :: None ) = bound
@@ -295,64 +292,62 @@ fn find_bound_in_supertraits<'a, 'tcx>(
295292 } )
296293}
297294
298- fn check ( cx : & LateContext < ' _ > , decl : & FnDecl < ' _ > ) {
299- if let FnRetTy :: Return ( ty) = decl. output
300- && let TyKind :: OpaqueDef ( item_id, ..) = ty. kind
301- && let item = cx. tcx . hir ( ) . item ( item_id)
302- && let ItemKind :: OpaqueTy ( opaque_ty) = item. kind
295+ fn check < ' tcx > ( cx : & LateContext < ' tcx > , bounds : GenericBounds < ' tcx > ) {
296+ if bounds. len ( ) == 1 {
303297 // Very often there is only a single bound, e.g. `impl Deref<..>`, in which case
304- // we can avoid doing a bunch of stuff unnecessarily.
305- && opaque_ty . bounds . len ( ) > 1
306- {
307- let supertraits = collect_supertrait_bounds ( cx , opaque_ty ) ;
298+ // we can avoid doing a bunch of stuff unnecessarily; there will trivially be
299+ // no duplicate bounds
300+ return ;
301+ }
308302
309- // Lint all bounds in the `impl Trait` type that we've previously also seen in the set of
310- // supertraits of each of the bounds.
311- // This involves some extra logic when generic arguments are present, since
312- // simply comparing trait `DefId`s won't be enough. We also need to compare the generics.
313- for ( index, bound) in opaque_ty. bounds . iter ( ) . enumerate ( ) {
314- if let GenericBound :: Trait ( poly_trait, TraitBoundModifier :: None ) = bound
315- && let [ .., path] = poly_trait. trait_ref . path . segments
316- && let implied_args = path. args . map_or ( [ ] . as_slice ( ) , |a| a. args )
317- && let implied_bindings = path. args . map_or ( [ ] . as_slice ( ) , |a| a. bindings )
318- && let Some ( def_id) = poly_trait. trait_ref . path . res . opt_def_id ( )
319- && let Some ( bound) = find_bound_in_supertraits ( cx, def_id, implied_args, & supertraits)
320- // If the implied bound has a type binding that also exists in the implied-by trait,
321- // then we shouldn't lint. See #11880 for an example.
322- && let assocs = cx. tcx . associated_items ( bound. trait_def_id )
323- && !implied_bindings. iter ( ) . any ( |binding| {
324- assocs
325- . filter_by_name_unhygienic ( binding. ident . name )
326- . next ( )
327- . is_some_and ( |assoc| assoc. kind == ty:: AssocKind :: Type )
328- } )
329- {
330- emit_lint ( cx, poly_trait, opaque_ty, index, implied_bindings, bound) ;
331- }
303+ let supertraits = collect_supertrait_bounds ( cx, bounds) ;
304+
305+ // Lint all bounds in the `impl Trait` type that we've previously also seen in the set of
306+ // supertraits of each of the bounds.
307+ // This involves some extra logic when generic arguments are present, since
308+ // simply comparing trait `DefId`s won't be enough. We also need to compare the generics.
309+ for ( index, bound) in bounds. iter ( ) . enumerate ( ) {
310+ if let GenericBound :: Trait ( poly_trait, TraitBoundModifier :: None ) = bound
311+ && let [ .., path] = poly_trait. trait_ref . path . segments
312+ && let implied_args = path. args . map_or ( [ ] . as_slice ( ) , |a| a. args )
313+ && let implied_bindings = path. args . map_or ( [ ] . as_slice ( ) , |a| a. bindings )
314+ && let Some ( def_id) = poly_trait. trait_ref . path . res . opt_def_id ( )
315+ && let Some ( bound) = find_bound_in_supertraits ( cx, def_id, implied_args, & supertraits)
316+ // If the implied bound has a type binding that also exists in the implied-by trait,
317+ // then we shouldn't lint. See #11880 for an example.
318+ && let assocs = cx. tcx . associated_items ( bound. trait_def_id )
319+ && !implied_bindings. iter ( ) . any ( |binding| {
320+ assocs
321+ . filter_by_name_unhygienic ( binding. ident . name )
322+ . next ( )
323+ . is_some_and ( |assoc| assoc. kind == ty:: AssocKind :: Type )
324+ } )
325+ {
326+ emit_lint ( cx, poly_trait, bounds, index, implied_bindings, bound) ;
332327 }
333328 }
334329}
335330
336- impl LateLintPass < ' _ > for ImpliedBoundsInImpls {
337- fn check_fn (
338- & mut self ,
339- cx : & LateContext < ' _ > ,
340- _: FnKind < ' _ > ,
341- decl : & FnDecl < ' _ > ,
342- _: & Body < ' _ > ,
343- _: Span ,
344- _: LocalDefId ,
345- ) {
346- check ( cx, decl) ;
347- }
348- fn check_trait_item ( & mut self , cx : & LateContext < ' _ > , item : & TraitItem < ' _ > ) {
349- if let TraitItemKind :: Fn ( sig, ..) = & item. kind {
350- check ( cx, sig. decl ) ;
331+ impl < ' tcx > LateLintPass < ' tcx > for ImpliedBoundsInImpls {
332+ fn check_generics ( & mut self , cx : & LateContext < ' tcx > , generics : & rustc_hir:: Generics < ' tcx > ) {
333+ for predicate in generics. predicates {
334+ if let WherePredicate :: BoundPredicate ( predicate) = predicate
335+ // In theory, the origin doesn't really matter,
336+ // we *could* also lint on explicit where clauses written out by the user,
337+ // not just impl trait desugared ones, but that contradicts with the lint name...
338+ && let PredicateOrigin :: ImplTrait = predicate. origin
339+ {
340+ check ( cx, predicate. bounds ) ;
341+ }
351342 }
352343 }
353- fn check_impl_item ( & mut self , cx : & LateContext < ' _ > , item : & ImplItem < ' _ > ) {
354- if let ImplItemKind :: Fn ( sig, ..) = & item. kind {
355- check ( cx, sig. decl ) ;
344+
345+ fn check_ty ( & mut self , cx : & LateContext < ' _ > , ty : & rustc_hir:: Ty < ' _ > ) {
346+ if let TyKind :: OpaqueDef ( item_id, ..) = ty. kind
347+ && let item = cx. tcx . hir ( ) . item ( item_id)
348+ && let ItemKind :: OpaqueTy ( opaque_ty) = item. kind
349+ {
350+ check ( cx, opaque_ty. bounds ) ;
356351 }
357352 }
358353}
0 commit comments