@@ -2157,8 +2157,77 @@ fn missing_items_err(
2157
2157
err. emit ( ) ;
2158
2158
}
2159
2159
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
+
2160
2224
/// 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 {
2162
2231
let args = sig
2163
2232
. inputs ( )
2164
2233
. iter ( )
@@ -2188,12 +2257,17 @@ fn fn_sig_suggestion(sig: &ty::FnSig<'_>, ident: Ident) -> String {
2188
2257
let output = if !output. is_unit ( ) { format ! ( " -> {:?}" , output) } else { String :: new ( ) } ;
2189
2258
2190
2259
let unsafety = sig. unsafety . prefix_str ( ) ;
2260
+ let ( generics, where_clauses) = bounds_from_generic_predicates ( tcx, predicates) ;
2261
+
2191
2262
// FIXME: this is not entirely correct, as the lifetimes from borrowed params will
2192
2263
// not be present in the `fn` definition, not will we account for renamed
2193
2264
// lifetimes between the `impl` and the `trait`, but this should be good enough to
2194
2265
// fill in a significant portion of the missing code, and other subsequent
2195
2266
// 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
+ )
2197
2271
}
2198
2272
2199
2273
/// Return placeholder code for the given associated item.
@@ -2206,7 +2280,12 @@ fn suggestion_signature(assoc: &ty::AssocItem, tcx: TyCtxt<'_>) -> String {
2206
2280
// late-bound regions, and we don't want method signatures to show up
2207
2281
// `as for<'r> fn(&'r MyType)`. Pretty-printing handles late-bound
2208
2282
// 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
+ )
2210
2289
}
2211
2290
ty:: AssocKind :: Type => format ! ( "type {} = Type;" , assoc. ident) ,
2212
2291
// FIXME(type_alias_impl_trait): we should print bounds here too.
0 commit comments