1
1
use std:: collections:: hash_map:: Entry ;
2
2
use std:: collections:: BTreeMap ;
3
3
4
- use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
4
+ use rustc_data_structures:: fx:: FxHashMap ;
5
5
use rustc_middle:: ty:: TyCtxt ;
6
6
use rustc_span:: symbol:: Symbol ;
7
7
use serde:: ser:: { Serialize , SerializeStruct , Serializer } ;
@@ -192,32 +192,24 @@ crate fn get_index_search_type<'tcx>(
192
192
item : & clean:: Item ,
193
193
tcx : TyCtxt < ' tcx > ,
194
194
) -> Option < IndexItemFunctionType > {
195
- let ( all_types , ret_types ) = match * item. kind {
195
+ let ( mut inputs , mut output ) = match * item. kind {
196
196
clean:: FunctionItem ( ref f) => get_all_types ( & f. generics , & f. decl , tcx) ,
197
197
clean:: MethodItem ( ref m, _) => get_all_types ( & m. generics , & m. decl , tcx) ,
198
198
clean:: TyMethodItem ( ref m) => get_all_types ( & m. generics , & m. decl , tcx) ,
199
199
_ => return None ,
200
200
} ;
201
201
202
- let inputs = all_types
203
- . iter ( )
204
- . map ( |( ty, kind) | TypeWithKind :: from ( ( get_index_type ( ty) , * kind) ) )
205
- . filter ( |a| a. ty . name . is_some ( ) )
206
- . collect ( ) ;
207
- let output = ret_types
208
- . iter ( )
209
- . map ( |( ty, kind) | TypeWithKind :: from ( ( get_index_type ( ty) , * kind) ) )
210
- . filter ( |a| a. ty . name . is_some ( ) )
211
- . collect :: < Vec < _ > > ( ) ;
202
+ inputs. retain ( |a| a. ty . name . is_some ( ) ) ;
203
+ output. retain ( |a| a. ty . name . is_some ( ) ) ;
212
204
let output = if output. is_empty ( ) { None } else { Some ( output) } ;
213
205
214
206
Some ( IndexItemFunctionType { inputs, output } )
215
207
}
216
208
217
- fn get_index_type ( clean_type : & clean:: Type ) -> RenderType {
209
+ fn get_index_type ( clean_type : & clean:: Type , generics : Vec < TypeWithKind > ) -> RenderType {
218
210
RenderType {
219
211
name : get_index_type_name ( clean_type, true ) . map ( |s| s. as_str ( ) . to_ascii_lowercase ( ) ) ,
220
- generics : get_generics ( clean_type ) ,
212
+ generics : if generics . is_empty ( ) { None } else { Some ( generics ) } ,
221
213
}
222
214
}
223
215
@@ -246,23 +238,6 @@ fn get_index_type_name(clean_type: &clean::Type, accept_generic: bool) -> Option
246
238
}
247
239
}
248
240
249
- /// Return a list of generic parameters for use in the search index.
250
- ///
251
- /// This function replaces bounds with types, so that `T where T: Debug` just becomes `Debug`.
252
- /// It does return duplicates, and that's intentional, since search queries like `Result<usize, usize>`
253
- /// are supposed to match only results where both parameters are `usize`.
254
- fn get_generics ( clean_type : & clean:: Type ) -> Option < Vec < String > > {
255
- clean_type. generics ( ) . and_then ( |types| {
256
- let r = types
257
- . iter ( )
258
- . filter_map ( |t| {
259
- get_index_type_name ( t, false ) . map ( |name| name. as_str ( ) . to_ascii_lowercase ( ) )
260
- } )
261
- . collect :: < Vec < _ > > ( ) ;
262
- if r. is_empty ( ) { None } else { Some ( r) }
263
- } )
264
- }
265
-
266
241
/// The point of this function is to replace bounds with types.
267
242
///
268
243
/// i.e. `[T, U]` when you have the following bounds: `T: Display, U: Option<T>` will return
@@ -272,27 +247,77 @@ crate fn get_real_types<'tcx>(
272
247
generics : & Generics ,
273
248
arg : & Type ,
274
249
tcx : TyCtxt < ' tcx > ,
275
- recurse : i32 ,
276
- res : & mut FxHashSet < ( Type , ItemType ) > ,
277
- ) -> usize {
278
- fn insert ( res : & mut FxHashSet < ( Type , ItemType ) > , tcx : TyCtxt < ' _ > , ty : Type ) -> usize {
279
- if let Some ( kind) = ty. def_id_no_primitives ( ) . map ( |did| tcx. def_kind ( did) . into ( ) ) {
280
- res. insert ( ( ty, kind) ) ;
281
- 1
250
+ recurse : usize ,
251
+ res : & mut Vec < TypeWithKind > ,
252
+ ) {
253
+ fn insert_ty (
254
+ res : & mut Vec < TypeWithKind > ,
255
+ tcx : TyCtxt < ' _ > ,
256
+ ty : Type ,
257
+ mut generics : Vec < TypeWithKind > ,
258
+ ) {
259
+ let is_full_generic = ty. is_full_generic ( ) ;
260
+
261
+ if is_full_generic && generics. len ( ) == 1 {
262
+ // In this case, no need to go through an intermediate state if the generics
263
+ // contains only one element.
264
+ //
265
+ // For example:
266
+ //
267
+ // fn foo<T: Display>(r: Option<T>) {}
268
+ //
269
+ // In this case, it would contain:
270
+ //
271
+ // ```
272
+ // [{
273
+ // name: "option",
274
+ // generics: [{
275
+ // name: "",
276
+ // generics: [
277
+ // name: "Display",
278
+ // generics: []
279
+ // }]
280
+ // }]
281
+ // }]
282
+ // ```
283
+ //
284
+ // After removing the intermediate (unnecessary) full generic, it'll become:
285
+ //
286
+ // ```
287
+ // [{
288
+ // name: "option",
289
+ // generics: [{
290
+ // name: "Display",
291
+ // generics: []
292
+ // }]
293
+ // }]
294
+ // ```
295
+ //
296
+ // To be noted that it can work if there is ONLY ONE generic, otherwise we still
297
+ // need to keep it as is!
298
+ res. push ( generics. pop ( ) . unwrap ( ) ) ;
299
+ return ;
300
+ }
301
+ let mut index_ty = get_index_type ( & ty, generics) ;
302
+ if index_ty. name . as_ref ( ) . map ( |s| s. is_empty ( ) ) . unwrap_or ( true ) {
303
+ return ;
304
+ }
305
+ if is_full_generic {
306
+ // We remove the name of the full generic because we have no use for it.
307
+ index_ty. name = Some ( String :: new ( ) ) ;
308
+ res. push ( TypeWithKind :: from ( ( index_ty, ItemType :: Generic ) ) ) ;
309
+ } else if let Some ( kind) = ty. def_id_no_primitives ( ) . map ( |did| tcx. def_kind ( did) . into ( ) ) {
310
+ res. push ( TypeWithKind :: from ( ( index_ty, kind) ) ) ;
282
311
} else if ty. is_primitive ( ) {
283
312
// This is a primitive, let's store it as such.
284
- res. insert ( ( ty, ItemType :: Primitive ) ) ;
285
- 1
286
- } else {
287
- 0
313
+ res. push ( TypeWithKind :: from ( ( index_ty, ItemType :: Primitive ) ) ) ;
288
314
}
289
315
}
290
316
291
317
if recurse >= 10 {
292
318
// FIXME: remove this whole recurse thing when the recursion bug is fixed
293
- return 0 ;
319
+ return ;
294
320
}
295
- let mut nb_added = 0 ;
296
321
297
322
if let Type :: Generic ( arg_s) = * arg {
298
323
if let Some ( where_pred) = generics. where_predicates . iter ( ) . find ( |g| match g {
@@ -301,6 +326,7 @@ crate fn get_real_types<'tcx>(
301
326
}
302
327
_ => false ,
303
328
} ) {
329
+ let mut ty_generics = Vec :: new ( ) ;
304
330
let bounds = where_pred. get_bounds ( ) . unwrap_or_else ( || & [ ] ) ;
305
331
for bound in bounds. iter ( ) {
306
332
if let GenericBound :: TraitBound ( poly_trait, _) = bound {
@@ -309,41 +335,32 @@ crate fn get_real_types<'tcx>(
309
335
continue ;
310
336
}
311
337
if let Some ( ty) = x. get_type ( ) {
312
- let adds = get_real_types ( generics, & ty, tcx, recurse + 1 , res) ;
313
- nb_added += adds;
314
- if adds == 0 && !ty. is_full_generic ( ) {
315
- nb_added += insert ( res, tcx, ty) ;
316
- }
338
+ get_real_types ( generics, & ty, tcx, recurse + 1 , & mut ty_generics) ;
317
339
}
318
340
}
319
341
}
320
342
}
343
+ insert_ty ( res, tcx, arg. clone ( ) , ty_generics) ;
321
344
}
322
345
if let Some ( bound) = generics. params . iter ( ) . find ( |g| g. is_type ( ) && g. name == arg_s) {
346
+ let mut ty_generics = Vec :: new ( ) ;
323
347
for bound in bound. get_bounds ( ) . unwrap_or ( & [ ] ) {
324
348
if let Some ( path) = bound. get_trait_path ( ) {
325
349
let ty = Type :: ResolvedPath { did : path. def_id ( ) , path } ;
326
- let adds = get_real_types ( generics, & ty, tcx, recurse + 1 , res) ;
327
- nb_added += adds;
328
- if adds == 0 && !ty. is_full_generic ( ) {
329
- nb_added += insert ( res, tcx, ty) ;
330
- }
350
+ get_real_types ( generics, & ty, tcx, recurse + 1 , & mut ty_generics) ;
331
351
}
332
352
}
353
+ insert_ty ( res, tcx, arg. clone ( ) , ty_generics) ;
333
354
}
334
355
} else {
335
- nb_added += insert ( res, tcx, arg. clone ( ) ) ;
336
- if let Some ( gens) = arg. generics ( ) {
337
- for gen in gens. iter ( ) {
338
- if gen. is_full_generic ( ) {
339
- nb_added += get_real_types ( generics, gen, tcx, recurse + 1 , res) ;
340
- } else {
341
- nb_added += insert ( res, tcx, ( * gen) . clone ( ) ) ;
342
- }
356
+ let mut ty_generics = Vec :: new ( ) ;
357
+ if let Some ( arg_generics) = arg. generics ( ) {
358
+ for gen in arg_generics. iter ( ) {
359
+ get_real_types ( generics, gen, tcx, recurse + 1 , & mut ty_generics) ;
343
360
}
344
361
}
362
+ insert_ty ( res, tcx, arg. clone ( ) , ty_generics) ;
345
363
}
346
- nb_added
347
364
}
348
365
349
366
/// Return the full list of types when bounds have been resolved.
@@ -354,38 +371,41 @@ crate fn get_all_types<'tcx>(
354
371
generics : & Generics ,
355
372
decl : & FnDecl ,
356
373
tcx : TyCtxt < ' tcx > ,
357
- ) -> ( Vec < ( Type , ItemType ) > , Vec < ( Type , ItemType ) > ) {
358
- let mut all_types = FxHashSet :: default ( ) ;
374
+ ) -> ( Vec < TypeWithKind > , Vec < TypeWithKind > ) {
375
+ let mut all_types = Vec :: new ( ) ;
359
376
for arg in decl. inputs . values . iter ( ) {
360
377
if arg. type_ . is_self_type ( ) {
361
378
continue ;
362
379
}
363
- let mut args = FxHashSet :: default ( ) ;
380
+ // FIXME: performance wise, it'd be much better to move `args` declaration outside of the
381
+ // loop and replace this line with `args.clear()`.
382
+ let mut args = Vec :: new ( ) ;
364
383
get_real_types ( generics, & arg. type_ , tcx, 0 , & mut args) ;
365
384
if !args. is_empty ( ) {
385
+ // FIXME: once back to performance improvements, replace this line with:
386
+ // `all_types.extend(args.drain(..));`.
366
387
all_types. extend ( args) ;
367
388
} else {
368
389
if let Some ( kind) = arg. type_ . def_id_no_primitives ( ) . map ( |did| tcx. def_kind ( did) . into ( ) )
369
390
{
370
- all_types. insert ( ( arg. type_ . clone ( ) , kind) ) ;
391
+ all_types. push ( TypeWithKind :: from ( ( get_index_type ( & arg. type_ , vec ! [ ] ) , kind) ) ) ;
371
392
}
372
393
}
373
394
}
374
395
375
- let ret_types = match decl. output {
396
+ let mut ret_types = Vec :: new ( ) ;
397
+ match decl. output {
376
398
FnRetTy :: Return ( ref return_type) => {
377
- let mut ret = FxHashSet :: default ( ) ;
378
- get_real_types ( generics, return_type, tcx, 0 , & mut ret) ;
379
- if ret. is_empty ( ) {
399
+ get_real_types ( generics, return_type, tcx, 0 , & mut ret_types) ;
400
+ if ret_types. is_empty ( ) {
380
401
if let Some ( kind) =
381
402
return_type. def_id_no_primitives ( ) . map ( |did| tcx. def_kind ( did) . into ( ) )
382
403
{
383
- ret . insert ( ( return_type . clone ( ) , kind) ) ;
404
+ ret_types . push ( TypeWithKind :: from ( ( get_index_type ( return_type , vec ! [ ] ) , kind) ) ) ;
384
405
}
385
406
}
386
- ret. into_iter ( ) . collect ( )
387
407
}
388
- _ => Vec :: new ( ) ,
408
+ _ => { }
389
409
} ;
390
- ( all_types. into_iter ( ) . collect ( ) , ret_types)
410
+ ( all_types, ret_types)
391
411
}
0 commit comments