@@ -329,41 +329,52 @@ fn bounds_from_generic_predicates<'tcx>(
329329 _ => { }
330330 }
331331 }
332- let generics = if types. is_empty ( ) {
333- "" . to_string ( )
334- } else {
335- format ! (
336- "<{}>" ,
337- types
338- . keys( )
339- . filter_map( |t| match t. kind( ) {
340- ty:: Param ( _) => Some ( t. to_string( ) ) ,
341- // Avoid suggesting the following:
342- // fn foo<T, <T as Trait>::Bar>(_: T) where T: Trait, <T as Trait>::Bar: Other {}
343- _ => None ,
344- } )
345- . collect:: <Vec <_>>( )
346- . join( ", " )
347- )
348- } ;
332+
349333 let mut where_clauses = vec ! [ ] ;
334+ let mut types_str = vec ! [ ] ;
350335 for ( ty, bounds) in types {
351- where_clauses
352- . extend ( bounds. into_iter ( ) . map ( |bound| format ! ( "{}: {}" , ty, tcx. def_path_str( bound) ) ) ) ;
353- }
354- for projection in & projections {
355- let p = projection. skip_binder ( ) ;
356- // FIXME: this is not currently supported syntax, we should be looking at the `types` and
357- // insert the associated types where they correspond, but for now let's be "lazy" and
358- // propose this instead of the following valid resugaring:
359- // `T: Trait, Trait::Assoc = K` → `T: Trait<Assoc = K>`
360- where_clauses. push ( format ! ( "{} = {}" , tcx. def_path_str( p. projection_ty. def_id) , p. term) ) ;
336+ if let ty:: Param ( _) = ty. kind ( ) {
337+ let mut bounds_str = vec ! [ ] ;
338+ for bound in bounds {
339+ let mut projections_str = vec ! [ ] ;
340+ for projection in & projections {
341+ let p = projection. skip_binder ( ) ;
342+ let alias_ty = p. projection_ty ;
343+ if bound == tcx. parent ( alias_ty. def_id ) && alias_ty. self_ty ( ) == ty {
344+ let name = tcx. item_name ( alias_ty. def_id ) ;
345+ projections_str. push ( format ! ( "{} = {}" , name, p. term) ) ;
346+ }
347+ }
348+ let bound_def_path = tcx. def_path_str ( bound) ;
349+ if projections_str. is_empty ( ) {
350+ where_clauses. push ( format ! ( "{}: {}" , ty, bound_def_path) ) ;
351+ } else {
352+ bounds_str. push ( format ! ( "{}<{}>" , bound_def_path, projections_str. join( ", " ) ) ) ;
353+ }
354+ }
355+ if bounds_str. is_empty ( ) {
356+ types_str. push ( ty. to_string ( ) ) ;
357+ } else {
358+ types_str. push ( format ! ( "{}: {}" , ty, bounds_str. join( " + " ) ) ) ;
359+ }
360+ } else {
361+ // Avoid suggesting the following:
362+ // fn foo<T, <T as Trait>::Bar>(_: T) where T: Trait, <T as Trait>::Bar: Other {}
363+ where_clauses. extend (
364+ bounds. into_iter ( ) . map ( |bound| format ! ( "{}: {}" , ty, tcx. def_path_str( bound) ) ) ,
365+ ) ;
366+ }
361367 }
368+
369+ let generics =
370+ if types_str. is_empty ( ) { "" . to_string ( ) } else { format ! ( "<{}>" , types_str. join( ", " ) ) } ;
371+
362372 let where_clauses = if where_clauses. is_empty ( ) {
363- String :: new ( )
373+ "" . to_string ( )
364374 } else {
365375 format ! ( " where {}" , where_clauses. join( ", " ) )
366376 } ;
377+
367378 ( generics, where_clauses)
368379}
369380
0 commit comments