@@ -2167,8 +2167,77 @@ fn missing_items_err(
2167
2167
err. emit ( ) ;
2168
2168
}
2169
2169
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
+
2170
2234
/// 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 {
2172
2241
let args = sig
2173
2242
. inputs ( )
2174
2243
. iter ( )
@@ -2198,12 +2267,17 @@ fn fn_sig_suggestion(sig: &ty::FnSig<'_>, ident: Ident) -> String {
2198
2267
let output = if !output. is_unit ( ) { format ! ( " -> {:?}" , output) } else { String :: new ( ) } ;
2199
2268
2200
2269
let unsafety = sig. unsafety . prefix_str ( ) ;
2270
+ let ( generics, where_clauses) = bounds_from_generic_predicates ( tcx, predicates) ;
2271
+
2201
2272
// FIXME: this is not entirely correct, as the lifetimes from borrowed params will
2202
2273
// not be present in the `fn` definition, not will we account for renamed
2203
2274
// lifetimes between the `impl` and the `trait`, but this should be good enough to
2204
2275
// fill in a significant portion of the missing code, and other subsequent
2205
2276
// 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
+ )
2207
2281
}
2208
2282
2209
2283
/// Return placeholder code for the given associated item.
@@ -2216,7 +2290,12 @@ fn suggestion_signature(assoc: &ty::AssocItem, tcx: TyCtxt<'_>) -> String {
2216
2290
// late-bound regions, and we don't want method signatures to show up
2217
2291
// `as for<'r> fn(&'r MyType)`. Pretty-printing handles late-bound
2218
2292
// 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
+ )
2220
2299
}
2221
2300
ty:: AssocKind :: Type => format ! ( "type {} = Type;" , assoc. ident) ,
2222
2301
// FIXME(type_alias_impl_trait): we should print bounds here too.
0 commit comments