11use clippy_utils:: diagnostics:: span_lint_and_then;
22use clippy_utils:: source:: snippet;
33use rustc_errors:: { Applicability , SuggestionStyle } ;
4- use rustc_hir:: def_id:: LocalDefId ;
4+ use rustc_hir:: def_id:: { DefId , LocalDefId } ;
55use rustc_hir:: intravisit:: FnKind ;
66use rustc_hir:: {
77 Body , FnDecl , FnRetTy , GenericArg , GenericBound , ImplItem , ImplItemKind , ItemKind , TraitBoundModifier , TraitItem ,
88 TraitItemKind , TyKind ,
99} ;
1010use rustc_hir_analysis:: hir_ty_to_ty;
1111use rustc_lint:: { LateContext , LateLintPass } ;
12- use rustc_middle:: ty:: { self , ClauseKind , TyCtxt } ;
12+ use rustc_middle:: ty:: { self , ClauseKind , Generics , Ty , TyCtxt } ;
1313use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
1414use rustc_span:: Span ;
1515
@@ -45,52 +45,80 @@ declare_clippy_lint! {
4545 /// ```
4646 #[ clippy:: version = "1.73.0" ]
4747 pub IMPLIED_BOUNDS_IN_IMPLS ,
48- complexity ,
48+ nursery ,
4949 "specifying bounds that are implied by other bounds in `impl Trait` type"
5050}
5151declare_lint_pass ! ( ImpliedBoundsInImpls => [ IMPLIED_BOUNDS_IN_IMPLS ] ) ;
5252
53- /// This function tries to, for all type parameters in a supertype predicate `GenericTrait<U>`,
54- /// check if the substituted type in the implied-by bound matches with what's subtituted in the
55- /// implied type.
53+ /// Tries to "resolve" a type.
54+ /// The index passed to this function must start with `Self=0`, i.e. it must be a valid
55+ /// type parameter index.
56+ /// If the index is out of bounds, it means that the generic parameter has a default type.
57+ fn try_resolve_type < ' tcx > (
58+ tcx : TyCtxt < ' tcx > ,
59+ args : & ' tcx [ GenericArg < ' tcx > ] ,
60+ generics : & ' tcx Generics ,
61+ index : usize ,
62+ ) -> Option < Ty < ' tcx > > {
63+ match args. get ( index - 1 ) {
64+ Some ( GenericArg :: Type ( ty) ) => Some ( hir_ty_to_ty ( tcx, ty) ) ,
65+ Some ( _) => None ,
66+ None => Some ( tcx. type_of ( generics. params [ index] . def_id ) . skip_binder ( ) ) ,
67+ }
68+ }
69+
70+ /// This function tries to, for all generic type parameters in a supertrait predicate `trait ...<U>:
71+ /// GenericTrait<U>`, check if the substituted type in the implied-by bound matches with what's
72+ /// subtituted in the implied bound.
5673///
5774/// Consider this example.
5875/// ```rust,ignore
5976/// trait GenericTrait<T> {}
6077/// trait GenericSubTrait<T, U, V>: GenericTrait<U> {}
61- /// ^ trait_predicate_args: [Self#0, U#2]
78+ /// ^^^^^^^^^^^^^^^ trait_predicate_args: [Self#0, U#2]
79+ /// (the Self#0 is implicit: `<Self as GenericTrait<U>>`)
6280/// impl GenericTrait<i32> for () {}
6381/// impl GenericSubTrait<(), i32, ()> for () {}
64- /// impl GenericSubTrait<(), [u8; 8] , ()> for () {}
82+ /// impl GenericSubTrait<(), i64 , ()> for () {}
6583///
66- /// fn f() -> impl GenericTrait<i32> + GenericSubTrait<(), [u8; 8], ()> {
67- /// ^^^ implied_args ^^^^^^^^^^^^^^^ implied_by_args
68- /// (we are interested in `[u8; 8]` specifically, as that
69- /// is what `U` in `GenericTrait<U>` is substituted with)
70- /// ()
84+ /// fn f() -> impl GenericTrait<i32> + GenericSubTrait<(), i64, ()> {
85+ /// ^^^ implied_args ^^^^^^^^^^^ implied_by_args
86+ /// (we are interested in `i64` specifically, as that
87+ /// is what `U` in `GenericTrait<U>` is substituted with)
7188/// }
7289/// ```
73- /// Here i32 != [u8; 8], so this will return false.
74- fn is_same_generics (
75- tcx : TyCtxt < ' _ > ,
76- trait_predicate_args : & [ ty:: GenericArg < ' _ > ] ,
77- implied_by_args : & [ GenericArg < ' _ > ] ,
78- implied_args : & [ GenericArg < ' _ > ] ,
90+ /// Here i32 != i64, so this will return false.
91+ fn is_same_generics < ' tcx > (
92+ tcx : TyCtxt < ' tcx > ,
93+ trait_predicate_args : & ' tcx [ ty:: GenericArg < ' tcx > ] ,
94+ implied_by_args : & ' tcx [ GenericArg < ' tcx > ] ,
95+ implied_args : & ' tcx [ GenericArg < ' tcx > ] ,
96+ implied_by_def_id : DefId ,
97+ implied_def_id : DefId ,
7998) -> bool {
99+ // Get the generics of the two traits to be able to get default generic parameter.
100+ let implied_by_generics = tcx. generics_of ( implied_by_def_id) ;
101+ let implied_generics = tcx. generics_of ( implied_def_id) ;
102+
80103 trait_predicate_args
81104 . iter ( )
82105 . enumerate ( )
83106 . skip ( 1 ) // skip `Self` implicit arg
84107 . all ( |( arg_index, arg) | {
85- if let Some ( ty) = arg. as_type ( )
86- && let & ty:: Param ( ty:: ParamTy { index, .. } ) = ty. kind ( )
87- // Since `trait_predicate_args` and type params in traits start with `Self=0`
88- // and generic argument lists `GenericTrait<i32>` don't have `Self`,
89- // we need to subtract 1 from the index.
90- && let GenericArg :: Type ( ty_a) = implied_by_args[ index as usize - 1 ]
91- && let GenericArg :: Type ( ty_b) = implied_args[ arg_index - 1 ]
92- {
93- hir_ty_to_ty ( tcx, ty_a) == hir_ty_to_ty ( tcx, ty_b)
108+ if let Some ( ty) = arg. as_type ( ) {
109+ if let & ty:: Param ( ty:: ParamTy { index, .. } ) = ty. kind ( )
110+ // `index == 0` means that it's referring to `Self`,
111+ // in which case we don't try to substitute it
112+ && index != 0
113+ && let Some ( ty_a) = try_resolve_type ( tcx, implied_by_args, implied_by_generics, index as usize )
114+ && let Some ( ty_b) = try_resolve_type ( tcx, implied_args, implied_generics, arg_index)
115+ {
116+ ty_a == ty_b
117+ } else if let Some ( ty_b) = try_resolve_type ( tcx, implied_args, implied_generics, arg_index) {
118+ ty == ty_b
119+ } else {
120+ false
121+ }
94122 } else {
95123 false
96124 }
@@ -121,7 +149,7 @@ fn check(cx: &LateContext<'_>, decl: &FnDecl<'_>) {
121149 && let predicates = cx. tcx . super_predicates_of ( trait_def_id) . predicates
122150 && !predicates. is_empty ( ) // If the trait has no supertrait, there is nothing to add.
123151 {
124- Some ( ( bound. span ( ) , path. args . map_or ( [ ] . as_slice ( ) , |a| a. args ) , predicates) )
152+ Some ( ( bound. span ( ) , path. args . map_or ( [ ] . as_slice ( ) , |a| a. args ) , predicates, trait_def_id ) )
125153 } else {
126154 None
127155 }
@@ -135,18 +163,27 @@ fn check(cx: &LateContext<'_>, decl: &FnDecl<'_>) {
135163 && let [ .., path] = poly_trait. trait_ref . path . segments
136164 && let implied_args = path. args . map_or ( [ ] . as_slice ( ) , |a| a. args )
137165 && let Some ( def_id) = poly_trait. trait_ref . path . res . opt_def_id ( )
138- && let Some ( implied_by_span) = implied_bounds. iter ( ) . find_map ( |& ( span, implied_by_args, preds) | {
139- preds. iter ( ) . find_map ( |( clause, _) | {
140- if let ClauseKind :: Trait ( tr) = clause. kind ( ) . skip_binder ( )
141- && tr. def_id ( ) == def_id
142- && is_same_generics ( cx. tcx , tr. trait_ref . args , implied_by_args, implied_args)
143- {
144- Some ( span)
145- } else {
146- None
147- }
166+ && let Some ( implied_by_span) = implied_bounds
167+ . iter ( )
168+ . find_map ( |& ( span, implied_by_args, preds, implied_by_def_id) | {
169+ preds. iter ( ) . find_map ( |( clause, _) | {
170+ if let ClauseKind :: Trait ( tr) = clause. kind ( ) . skip_binder ( )
171+ && tr. def_id ( ) == def_id
172+ && is_same_generics (
173+ cx. tcx ,
174+ tr. trait_ref . args ,
175+ implied_by_args,
176+ implied_args,
177+ implied_by_def_id,
178+ def_id,
179+ )
180+ {
181+ Some ( span)
182+ } else {
183+ None
184+ }
185+ } )
148186 } )
149- } )
150187 {
151188 let implied_by = snippet ( cx, implied_by_span, ".." ) ;
152189 span_lint_and_then (
0 commit comments