@@ -1217,7 +1217,6 @@ pub fn prohibit_assoc_item_constraint(
12171217 // otherwise suggest the removal of the binding.
12181218 if let Some ( ( def_id, segment, _) ) = segment
12191219 && segment. args ( ) . parenthesized == hir:: GenericArgsParentheses :: No
1220- && let hir:: AssocItemConstraintKind :: Equality { term } = constraint. kind
12211220 {
12221221 // Suggests removal of the offending binding
12231222 let suggest_removal = |e : & mut Diag < ' _ > | {
@@ -1286,20 +1285,74 @@ pub fn prohibit_assoc_item_constraint(
12861285 // Check if the type has a generic param with the same name
12871286 // as the assoc type name in the associated item binding.
12881287 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 ) ;
12911289
12921290 // Now emit the appropriate suggestion
12931291 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+ }
12971304 }
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+ }
13011355 }
1302- _ => suggest_removal ( & mut err) ,
13031356 }
13041357 } else {
13051358 suggest_removal ( & mut err) ;
0 commit comments