@@ -2167,8 +2167,77 @@ fn missing_items_err(
21672167 err. emit ( ) ;
21682168}
21692169
2170+ /// Resugar `ty::GenericPredicates` in a way suitable to be used in structured suggestions.
2171+ fn bounds_from_generic_predicates (
2172+ tcx : TyCtxt < ' _ > ,
2173+ predicates : ty:: GenericPredicates < ' _ > ,
2174+ ) -> ( String , String ) {
2175+ let mut types: FxHashMap < Ty < ' _ > , Vec < DefId > > = FxHashMap :: default ( ) ;
2176+ let mut projections = vec ! [ ] ;
2177+ for ( predicate, _) in predicates. predicates {
2178+ debug ! ( "predicate {:?}" , predicate) ;
2179+ match predicate {
2180+ ty:: Predicate :: Trait ( trait_predicate, _) => {
2181+ let entry = types. entry ( trait_predicate. skip_binder ( ) . self_ty ( ) ) . or_default ( ) ;
2182+ let def_id = trait_predicate. skip_binder ( ) . def_id ( ) ;
2183+ if Some ( def_id) != tcx. lang_items ( ) . sized_trait ( ) {
2184+ // Type params are `Sized` by default, do not add that restriction to the list
2185+ // if it is a positive requirement.
2186+ entry. push ( trait_predicate. skip_binder ( ) . def_id ( ) ) ;
2187+ }
2188+ }
2189+ ty:: Predicate :: Projection ( projection_pred) => {
2190+ projections. push ( projection_pred) ;
2191+ }
2192+ _ => { }
2193+ }
2194+ }
2195+ let generics = if types. is_empty ( ) {
2196+ "" . to_string ( )
2197+ } else {
2198+ format ! (
2199+ "<{}>" ,
2200+ types
2201+ . keys( )
2202+ . filter_map( |t| match t. kind {
2203+ ty:: Param ( _) => Some ( t. to_string( ) ) ,
2204+ // Avoid suggesting the following:
2205+ // fn foo<T, <T as Trait>::Bar>(_: T) where T: Trait, <T as Trait>::Bar: Other {}
2206+ _ => None ,
2207+ } )
2208+ . collect:: <Vec <_>>( )
2209+ . join( ", " )
2210+ )
2211+ } ;
2212+ let mut where_clauses = vec ! [ ] ;
2213+ for ( ty, bounds) in types {
2214+ for bound in & bounds {
2215+ where_clauses. push ( format ! ( "{}: {}" , ty, tcx. def_path_str( * bound) ) ) ;
2216+ }
2217+ }
2218+ for projection in & projections {
2219+ let p = projection. skip_binder ( ) ;
2220+ // FIXME: this is not currently supported syntax, we should be looking at the `types` and
2221+ // insert the associated types where they correspond, but for now let's be "lazy" and
2222+ // propose this instead of the following valid resugaring:
2223+ // `T: Trait, Trait::Assoc = K` → `T: Trait<Assoc = K>`
2224+ where_clauses. push ( format ! ( "{} = {}" , tcx. def_path_str( p. projection_ty. item_def_id) , p. ty) ) ;
2225+ }
2226+ let where_clauses = if where_clauses. is_empty ( ) {
2227+ String :: new ( )
2228+ } else {
2229+ format ! ( " where {}" , where_clauses. join( ", " ) )
2230+ } ;
2231+ ( generics, where_clauses)
2232+ }
2233+
21702234/// Return placeholder code for the given function.
2171- fn fn_sig_suggestion ( sig : & ty:: FnSig < ' _ > , ident : Ident ) -> String {
2235+ fn fn_sig_suggestion (
2236+ tcx : TyCtxt < ' _ > ,
2237+ sig : & ty:: FnSig < ' _ > ,
2238+ ident : Ident ,
2239+ predicates : ty:: GenericPredicates < ' _ > ,
2240+ ) -> String {
21722241 let args = sig
21732242 . inputs ( )
21742243 . iter ( )
@@ -2198,12 +2267,17 @@ fn fn_sig_suggestion(sig: &ty::FnSig<'_>, ident: Ident) -> String {
21982267 let output = if !output. is_unit ( ) { format ! ( " -> {:?}" , output) } else { String :: new ( ) } ;
21992268
22002269 let unsafety = sig. unsafety . prefix_str ( ) ;
2270+ let ( generics, where_clauses) = bounds_from_generic_predicates ( tcx, predicates) ;
2271+
22012272 // FIXME: this is not entirely correct, as the lifetimes from borrowed params will
22022273 // not be present in the `fn` definition, not will we account for renamed
22032274 // lifetimes between the `impl` and the `trait`, but this should be good enough to
22042275 // fill in a significant portion of the missing code, and other subsequent
22052276 // suggestions can help the user fix the code.
2206- format ! ( "{}fn {}({}){} {{ unimplemented!() }}" , unsafety, ident, args, output)
2277+ format ! (
2278+ "{}fn {}{}({}){}{} {{ todo!() }}" ,
2279+ unsafety, ident, generics, args, output, where_clauses
2280+ )
22072281}
22082282
22092283/// Return placeholder code for the given associated item.
@@ -2216,7 +2290,12 @@ fn suggestion_signature(assoc: &ty::AssocItem, tcx: TyCtxt<'_>) -> String {
22162290 // late-bound regions, and we don't want method signatures to show up
22172291 // `as for<'r> fn(&'r MyType)`. Pretty-printing handles late-bound
22182292 // regions just fine, showing `fn(&MyType)`.
2219- fn_sig_suggestion ( tcx. fn_sig ( assoc. def_id ) . skip_binder ( ) , assoc. ident )
2293+ fn_sig_suggestion (
2294+ tcx,
2295+ tcx. fn_sig ( assoc. def_id ) . skip_binder ( ) ,
2296+ assoc. ident ,
2297+ tcx. predicates_of ( assoc. def_id ) ,
2298+ )
22202299 }
22212300 ty:: AssocKind :: Type => format ! ( "type {} = Type;" , assoc. ident) ,
22222301 // FIXME(type_alias_impl_trait): we should print bounds here too.
0 commit comments