@@ -50,6 +50,93 @@ declare_clippy_lint! {
5050}
5151declare_lint_pass ! ( ImpliedBoundsInImpls => [ IMPLIED_BOUNDS_IN_IMPLS ] ) ;
5252
53+ #[ allow( clippy:: too_many_arguments) ]
54+ fn emit_lint (
55+ cx : & LateContext < ' _ > ,
56+ poly_trait : & rustc_hir:: PolyTraitRef < ' _ > ,
57+ opaque_ty : & rustc_hir:: OpaqueTy < ' _ > ,
58+ index : usize ,
59+ implied_bindings : & [ rustc_hir:: TypeBinding < ' _ > ] ,
60+ implied_by_bindings : & [ rustc_hir:: TypeBinding < ' _ > ] ,
61+ implied_by_args : & [ GenericArg < ' _ > ] ,
62+ implied_by_span : Span ,
63+ ) {
64+ let implied_by = snippet ( cx, implied_by_span, ".." ) ;
65+
66+ span_lint_and_then (
67+ cx,
68+ IMPLIED_BOUNDS_IN_IMPLS ,
69+ poly_trait. span ,
70+ & format ! ( "this bound is already specified as the supertrait of `{implied_by}`" ) ,
71+ |diag| {
72+ // If we suggest removing a bound, we may also need extend the span
73+ // to include the `+` token that is ahead or behind,
74+ // so we don't end up with something like `impl + B` or `impl A + `
75+
76+ let implied_span_extended = if let Some ( next_bound) = opaque_ty. bounds . get ( index + 1 ) {
77+ poly_trait. span . to ( next_bound. span ( ) . shrink_to_lo ( ) )
78+ } else if index > 0
79+ && let Some ( prev_bound) = opaque_ty. bounds . get ( index - 1 )
80+ {
81+ prev_bound. span ( ) . shrink_to_hi ( ) . to ( poly_trait. span . shrink_to_hi ( ) )
82+ } else {
83+ poly_trait. span
84+ } ;
85+
86+ let mut sugg = vec ! [ ( implied_span_extended, String :: new( ) ) ] ;
87+
88+ // We also might need to include associated type binding that were specified in the implied bound,
89+ // but omitted in the implied-by bound:
90+ // `fn f() -> impl Deref<Target = u8> + DerefMut`
91+ // If we're going to suggest removing `Deref<..>`, we'll need to put `<Target = u8>` on `DerefMut`
92+ let omitted_assoc_tys: Vec < _ > = implied_bindings
93+ . iter ( )
94+ . filter ( |binding| !implied_by_bindings. iter ( ) . any ( |b| b. ident == binding. ident ) )
95+ . collect ( ) ;
96+
97+ if !omitted_assoc_tys. is_empty ( ) {
98+ // `<>` needs to be added if there aren't yet any generic arguments or bindings
99+ let needs_angle_brackets = implied_by_args. is_empty ( ) && implied_by_bindings. is_empty ( ) ;
100+ let insert_span = match ( implied_by_args, implied_by_bindings) {
101+ ( [ .., arg] , [ .., binding] ) => arg. span ( ) . max ( binding. span ) . shrink_to_hi ( ) ,
102+ ( [ .., arg] , [ ] ) => arg. span ( ) . shrink_to_hi ( ) ,
103+ ( [ ] , [ .., binding] ) => binding. span . shrink_to_hi ( ) ,
104+ ( [ ] , [ ] ) => implied_by_span. shrink_to_hi ( ) ,
105+ } ;
106+
107+ let mut associated_tys_sugg = if needs_angle_brackets {
108+ "<" . to_owned ( )
109+ } else {
110+ // If angle brackets aren't needed (i.e., there are already generic arguments or bindings),
111+ // we need to add a comma:
112+ // `impl A<B, C >`
113+ // ^ if we insert `Assoc=i32` without a comma here, that'd be invalid syntax:
114+ // `impl A<B, C Assoc=i32>`
115+ ", " . to_owned ( )
116+ } ;
117+
118+ for ( index, binding) in omitted_assoc_tys. into_iter ( ) . enumerate ( ) {
119+ if index > 0 {
120+ associated_tys_sugg += ", " ;
121+ }
122+ associated_tys_sugg += & snippet ( cx, binding. span , ".." ) ;
123+ }
124+ if needs_angle_brackets {
125+ associated_tys_sugg += ">" ;
126+ }
127+ sugg. push ( ( insert_span, associated_tys_sugg) ) ;
128+ }
129+
130+ diag. multipart_suggestion_with_style (
131+ "try removing this bound" ,
132+ sugg,
133+ Applicability :: MachineApplicable ,
134+ SuggestionStyle :: ShowAlways ,
135+ ) ;
136+ } ,
137+ ) ;
138+ }
139+
53140/// Tries to "resolve" a type.
54141/// The index passed to this function must start with `Self=0`, i.e. it must be a valid
55142/// type parameter index.
@@ -189,80 +276,15 @@ fn check(cx: &LateContext<'_>, decl: &FnDecl<'_>) {
189276 } )
190277 } )
191278 {
192- let implied_by = snippet ( cx, implied_by_span, ".." ) ;
193- span_lint_and_then (
194- cx, IMPLIED_BOUNDS_IN_IMPLS ,
195- poly_trait. span ,
196- & format ! ( "this bound is already specified as the supertrait of `{implied_by}`" ) ,
197- |diag| {
198- // If we suggest removing a bound, we may also need extend the span
199- // to include the `+` token that is ahead or behind,
200- // so we don't end up with something like `impl + B` or `impl A + `
201-
202- let implied_span_extended = if let Some ( next_bound) = opaque_ty. bounds . get ( index + 1 ) {
203- poly_trait. span . to ( next_bound. span ( ) . shrink_to_lo ( ) )
204- } else if index > 0
205- && let Some ( prev_bound) = opaque_ty. bounds . get ( index - 1 )
206- {
207- prev_bound. span ( ) . shrink_to_hi ( ) . to ( poly_trait. span . shrink_to_hi ( ) )
208- } else {
209- poly_trait. span
210- } ;
211-
212- let mut sugg = vec ! [
213- ( implied_span_extended, String :: new( ) ) ,
214- ] ;
215-
216- // We also might need to include associated type binding that were specified in the implied bound,
217- // but omitted in the implied-by bound:
218- // `fn f() -> impl Deref<Target = u8> + DerefMut`
219- // If we're going to suggest removing `Deref<..>`, we'll need to put `<Target = u8>` on `DerefMut`
220- let omitted_assoc_tys: Vec < _ > = implied_bindings
221- . iter ( )
222- . filter ( |binding| {
223- implied_by_bindings
224- . iter ( )
225- // TODO: is checking idents enough for stuff like `<Target: Sized> == <Target = u8>`
226- . find ( |b| b. ident == binding. ident )
227- . is_none ( )
228- } )
229- . collect ( ) ;
230-
231- if !omitted_assoc_tys. is_empty ( ) {
232- // `<>` needs to be added if there aren't yet any generic arguments or bindings
233- let needs_angle_brackets = implied_by_args. is_empty ( ) && implied_by_bindings. is_empty ( ) ;
234- let insert_span = match ( implied_by_args, implied_by_bindings) {
235- ( [ .., arg] , [ .., binding] ) => arg. span ( ) . max ( binding. span ) . shrink_to_hi ( ) ,
236- ( [ .., arg] , [ ] ) => arg. span ( ) . shrink_to_hi ( ) ,
237- ( [ ] , [ .., binding] ) => binding. span . shrink_to_hi ( ) ,
238- ( [ ] , [ ] ) => implied_by_span. shrink_to_hi ( ) ,
239- } ;
240-
241- let mut associated_tys_sugg = if needs_angle_brackets {
242- "<" . to_owned ( )
243- } else {
244- // If angle brackets aren't needed (i.e., there are already generic arguments or bindings),
245- // we need to add a comma:
246- // `impl A<B, C >`
247- // ^ if we insert `Assoc=i32` without a comma here, that'd be invalid syntax:
248- // `impl A<B, C Assoc=i32>`
249- ", " . to_owned ( )
250- } ;
251-
252- for ( index, binding) in omitted_assoc_tys. into_iter ( ) . enumerate ( ) {
253- if index > 0 {
254- associated_tys_sugg += ", " ;
255- }
256- associated_tys_sugg += & snippet ( cx, binding. span , ".." ) ;
257- }
258- if needs_angle_brackets {
259- associated_tys_sugg += ">" ;
260- }
261- sugg. push ( ( insert_span, associated_tys_sugg) ) ;
262- }
263-
264- diag. multipart_suggestion_with_style ( "try removing this bound" , sugg, Applicability :: MachineApplicable , SuggestionStyle :: ShowAlways ) ;
265- }
279+ emit_lint (
280+ cx,
281+ poly_trait,
282+ opaque_ty,
283+ index,
284+ implied_bindings,
285+ implied_by_bindings,
286+ implied_by_args,
287+ implied_by_span
266288 ) ;
267289 }
268290 }
0 commit comments