@@ -1217,7 +1217,6 @@ pub fn prohibit_assoc_item_constraint(
1217
1217
// otherwise suggest the removal of the binding.
1218
1218
if let Some ( ( def_id, segment, _) ) = segment
1219
1219
&& segment. args ( ) . parenthesized == hir:: GenericArgsParentheses :: No
1220
- && let hir:: AssocItemConstraintKind :: Equality { term } = constraint. kind
1221
1220
{
1222
1221
// Suggests removal of the offending binding
1223
1222
let suggest_removal = |e : & mut Diag < ' _ > | {
@@ -1286,20 +1285,74 @@ pub fn prohibit_assoc_item_constraint(
1286
1285
// Check if the type has a generic param with the same name
1287
1286
// as the assoc type name in the associated item binding.
1288
1287
let generics = tcx. generics_of ( def_id) ;
1289
- let matching_param =
1290
- generics. own_params . iter ( ) . find ( |p| p. name . as_str ( ) == constraint. ident . as_str ( ) ) ;
1288
+ let matching_param = generics. own_params . iter ( ) . find ( |p| p. name == constraint. ident . name ) ;
1291
1289
1292
1290
// Now emit the appropriate suggestion
1293
1291
if let Some ( matching_param) = matching_param {
1294
- match ( & matching_param. kind , term) {
1295
- ( GenericParamDefKind :: Type { .. } , hir:: Term :: Ty ( ty) ) => {
1296
- suggest_direct_use ( & mut err, ty. span ) ;
1292
+ match constraint. kind {
1293
+ hir:: AssocItemConstraintKind :: Equality { term } => {
1294
+ match ( & matching_param. kind , term) {
1295
+ ( GenericParamDefKind :: Type { .. } , hir:: Term :: Ty ( ty) ) => {
1296
+ suggest_direct_use ( & mut err, ty. span ) ;
1297
+ }
1298
+ ( GenericParamDefKind :: Const { .. } , hir:: Term :: Const ( c) ) => {
1299
+ let span = tcx. hir ( ) . span ( c. hir_id ) ;
1300
+ suggest_direct_use ( & mut err, span) ;
1301
+ }
1302
+ _ => suggest_removal ( & mut err) ,
1303
+ }
1297
1304
}
1298
- ( GenericParamDefKind :: Const { .. } , hir:: Term :: Const ( c) ) => {
1299
- let span = tcx. hir ( ) . span ( c. hir_id ) ;
1300
- suggest_direct_use ( & mut err, span) ;
1305
+ hir:: AssocItemConstraintKind :: Bound { bounds } => {
1306
+ // Suggest `impl<T: Bound> Trait<T> for Foo` when finding
1307
+ // `impl Trait<T: Bound> for Foo`
1308
+
1309
+ // Get the parent impl block based on the binding we have
1310
+ // and the trait DefId
1311
+ let impl_block = tcx
1312
+ . hir ( )
1313
+ . parent_iter ( constraint. hir_id )
1314
+ . find_map ( |( _, node) | node. impl_block_of_trait ( def_id) ) ;
1315
+
1316
+ let type_with_constraints =
1317
+ tcx. sess . source_map ( ) . span_to_snippet ( constraint. span ) ;
1318
+
1319
+ if let Some ( impl_block) = impl_block
1320
+ && let Ok ( type_with_constraints) = type_with_constraints
1321
+ {
1322
+ // Filter out the lifetime parameters because
1323
+ // they should be declared before the type parameter
1324
+ let lifetimes: String = bounds
1325
+ . iter ( )
1326
+ . filter_map ( |bound| {
1327
+ if let hir:: GenericBound :: Outlives ( lifetime) = bound {
1328
+ Some ( format ! ( "{lifetime}, " ) )
1329
+ } else {
1330
+ None
1331
+ }
1332
+ } )
1333
+ . collect ( ) ;
1334
+ // Figure out a span and suggestion string based on
1335
+ // whether there are any existing parameters
1336
+ let param_decl = if let Some ( param_span) =
1337
+ impl_block. generics . span_for_param_suggestion ( )
1338
+ {
1339
+ ( param_span, format ! ( ", {lifetimes}{type_with_constraints}" ) )
1340
+ } else {
1341
+ (
1342
+ impl_block. generics . span . shrink_to_lo ( ) ,
1343
+ format ! ( "<{lifetimes}{type_with_constraints}>" ) ,
1344
+ )
1345
+ } ;
1346
+ let suggestions =
1347
+ vec ! [ param_decl, ( constraint. span, format!( "{}" , matching_param. name) ) ] ;
1348
+
1349
+ err. multipart_suggestion_verbose (
1350
+ format ! ( "declare the type parameter right after the `impl` keyword" ) ,
1351
+ suggestions,
1352
+ Applicability :: MaybeIncorrect ,
1353
+ ) ;
1354
+ }
1301
1355
}
1302
- _ => suggest_removal ( & mut err) ,
1303
1356
}
1304
1357
} else {
1305
1358
suggest_removal ( & mut err) ;
0 commit comments