@@ -2157,8 +2157,77 @@ fn missing_items_err(
21572157 err. emit ( ) ;
21582158}
21592159
2160+ /// Resugar `ty::GenericPredicates` in a way suitable to be used in structured suggestions.
2161+ fn bounds_from_generic_predicates (
2162+ tcx : TyCtxt < ' _ > ,
2163+ predicates : ty:: GenericPredicates < ' _ > ,
2164+ ) -> ( String , String ) {
2165+ let mut types: FxHashMap < Ty < ' _ > , Vec < DefId > > = FxHashMap :: default ( ) ;
2166+ let mut projections = vec ! [ ] ;
2167+ for ( predicate, _) in predicates. predicates {
2168+ debug ! ( "predicate {:?}" , predicate) ;
2169+ match predicate {
2170+ ty:: Predicate :: Trait ( trait_predicate, _) => {
2171+ let entry = types. entry ( trait_predicate. skip_binder ( ) . self_ty ( ) ) . or_default ( ) ;
2172+ let def_id = trait_predicate. skip_binder ( ) . def_id ( ) ;
2173+ if Some ( def_id) != tcx. lang_items ( ) . sized_trait ( ) {
2174+ // Type params are `Sized` by default, do not add that restriction to the list
2175+ // if it is a positive requirement.
2176+ entry. push ( trait_predicate. skip_binder ( ) . def_id ( ) ) ;
2177+ }
2178+ }
2179+ ty:: Predicate :: Projection ( projection_pred) => {
2180+ projections. push ( projection_pred) ;
2181+ }
2182+ _ => { }
2183+ }
2184+ }
2185+ let generics = if types. is_empty ( ) {
2186+ "" . to_string ( )
2187+ } else {
2188+ format ! (
2189+ "<{}>" ,
2190+ types
2191+ . keys( )
2192+ . filter_map( |t| match t. kind {
2193+ ty:: Param ( _) => Some ( t. to_string( ) ) ,
2194+ // Avoid suggesting the following:
2195+ // fn foo<T, <T as Trait>::Bar>(_: T) where T: Trait, <T as Trait>::Bar: Other {}
2196+ _ => None ,
2197+ } )
2198+ . collect:: <Vec <_>>( )
2199+ . join( ", " )
2200+ )
2201+ } ;
2202+ let mut where_clauses = vec ! [ ] ;
2203+ for ( ty, bounds) in types {
2204+ for bound in & bounds {
2205+ where_clauses. push ( format ! ( "{}: {}" , ty, tcx. def_path_str( * bound) ) ) ;
2206+ }
2207+ }
2208+ for projection in & projections {
2209+ let p = projection. skip_binder ( ) ;
2210+ // FIXME: this is not currently supported syntax, we should be looking at the `types` and
2211+ // insert the associated types where they correspond, but for now lets be "lazy" and
2212+ // propose this instead of the following valid resugaring:
2213+ // `T: Trait, Trait::Assoc = K` → `T: Trait<Assoc = K>`
2214+ where_clauses. push ( format ! ( "{} = {}" , tcx. def_path_str( p. projection_ty. item_def_id) , p. ty) ) ;
2215+ }
2216+ let where_clauses = if where_clauses. is_empty ( ) {
2217+ String :: new ( )
2218+ } else {
2219+ format ! ( " where {}" , where_clauses. join( ", " ) )
2220+ } ;
2221+ ( generics, where_clauses)
2222+ }
2223+
21602224/// Return placeholder code for the given function.
2161- fn fn_sig_suggestion ( sig : & ty:: FnSig < ' _ > , ident : Ident ) -> String {
2225+ fn fn_sig_suggestion (
2226+ tcx : TyCtxt < ' _ > ,
2227+ sig : & ty:: FnSig < ' _ > ,
2228+ ident : Ident ,
2229+ predicates : ty:: GenericPredicates < ' _ > ,
2230+ ) -> String {
21622231 let args = sig
21632232 . inputs ( )
21642233 . iter ( )
@@ -2188,12 +2257,17 @@ fn fn_sig_suggestion(sig: &ty::FnSig<'_>, ident: Ident) -> String {
21882257 let output = if !output. is_unit ( ) { format ! ( " -> {:?}" , output) } else { String :: new ( ) } ;
21892258
21902259 let unsafety = sig. unsafety . prefix_str ( ) ;
2260+ let ( generics, where_clauses) = bounds_from_generic_predicates ( tcx, predicates) ;
2261+
21912262 // FIXME: this is not entirely correct, as the lifetimes from borrowed params will
21922263 // not be present in the `fn` definition, not will we account for renamed
21932264 // lifetimes between the `impl` and the `trait`, but this should be good enough to
21942265 // fill in a significant portion of the missing code, and other subsequent
21952266 // suggestions can help the user fix the code.
2196- format ! ( "{}fn {}({}){} {{ unimplemented!() }}" , unsafety, ident, args, output)
2267+ format ! (
2268+ "{}fn {}{}({}){}{} {{ unimplemented!() }}" ,
2269+ unsafety, ident, generics, args, output, where_clauses
2270+ )
21972271}
21982272
21992273/// Return placeholder code for the given associated item.
@@ -2206,7 +2280,12 @@ fn suggestion_signature(assoc: &ty::AssocItem, tcx: TyCtxt<'_>) -> String {
22062280 // late-bound regions, and we don't want method signatures to show up
22072281 // `as for<'r> fn(&'r MyType)`. Pretty-printing handles late-bound
22082282 // regions just fine, showing `fn(&MyType)`.
2209- fn_sig_suggestion ( tcx. fn_sig ( assoc. def_id ) . skip_binder ( ) , assoc. ident )
2283+ fn_sig_suggestion (
2284+ tcx,
2285+ tcx. fn_sig ( assoc. def_id ) . skip_binder ( ) ,
2286+ assoc. ident ,
2287+ tcx. predicates_of ( assoc. def_id ) ,
2288+ )
22102289 }
22112290 ty:: AssocKind :: Type => format ! ( "type {} = Type;" , assoc. ident) ,
22122291 // FIXME(type_alias_impl_trait): we should print bounds here too.
0 commit comments