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