@@ -149,7 +149,7 @@ fn check(cx: &LateContext<'_>, decl: &FnDecl<'_>) {
149
149
&& let predicates = cx. tcx . super_predicates_of ( trait_def_id) . predicates
150
150
&& !predicates. is_empty ( ) // If the trait has no supertrait, there is nothing to add.
151
151
{
152
- Some ( ( bound. span ( ) , path. args . map_or ( [ ] . as_slice ( ) , |a| a . args ) , predicates, trait_def_id) )
152
+ Some ( ( bound. span ( ) , path, predicates, trait_def_id) )
153
153
} else {
154
154
None
155
155
}
@@ -162,10 +162,14 @@ fn check(cx: &LateContext<'_>, decl: &FnDecl<'_>) {
162
162
if let GenericBound :: Trait ( poly_trait, TraitBoundModifier :: None ) = bound
163
163
&& let [ .., path] = poly_trait. trait_ref . path . segments
164
164
&& let implied_args = path. args . map_or ( [ ] . as_slice ( ) , |a| a. args )
165
+ && let implied_bindings = path. args . map_or ( [ ] . as_slice ( ) , |a| a. bindings )
165
166
&& let Some ( def_id) = poly_trait. trait_ref . path . res . opt_def_id ( )
166
- && let Some ( implied_by_span) = implied_bounds
167
+ && let Some ( ( implied_by_span, implied_by_args , implied_by_bindings ) ) = implied_bounds
167
168
. iter ( )
168
- . find_map ( |& ( span, implied_by_args, preds, implied_by_def_id) | {
169
+ . find_map ( |& ( span, implied_by_path, preds, implied_by_def_id) | {
170
+ let implied_by_args = implied_by_path. args . map_or ( [ ] . as_slice ( ) , |a| a. args ) ;
171
+ let implied_by_bindings = implied_by_path. args . map_or ( [ ] . as_slice ( ) , |a| a. bindings ) ;
172
+
169
173
preds. iter ( ) . find_map ( |( clause, _) | {
170
174
if let ClauseKind :: Trait ( tr) = clause. kind ( ) . skip_binder ( )
171
175
&& tr. def_id ( ) == def_id
@@ -178,7 +182,7 @@ fn check(cx: &LateContext<'_>, decl: &FnDecl<'_>) {
178
182
def_id,
179
183
)
180
184
{
181
- Some ( span)
185
+ Some ( ( span, implied_by_args , implied_by_bindings ) )
182
186
} else {
183
187
None
184
188
}
@@ -192,21 +196,72 @@ fn check(cx: &LateContext<'_>, decl: &FnDecl<'_>) {
192
196
& format ! ( "this bound is already specified as the supertrait of `{implied_by}`" ) ,
193
197
|diag| {
194
198
// If we suggest removing a bound, we may also need extend the span
195
- // to include the `+` token, so we don't end up with something like `impl + B`
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 + `
196
201
197
202
let implied_span_extended = if let Some ( next_bound) = opaque_ty. bounds . get ( index + 1 ) {
198
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 ( ) )
199
208
} else {
200
209
poly_trait. span
201
210
} ;
202
211
203
- diag. span_suggestion_with_style (
204
- implied_span_extended,
205
- "try removing this bound" ,
206
- "" ,
207
- Applicability :: MachineApplicable ,
208
- SuggestionStyle :: ShowAlways
209
- ) ;
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 ) ;
210
265
}
211
266
) ;
212
267
}
0 commit comments