Skip to content

Commit 8e0d1ce

Browse files
Improve html::render::cache::get_real_types code
1 parent 4810910 commit 8e0d1ce

File tree

2 files changed

+127
-5
lines changed

2 files changed

+127
-5
lines changed

src/librustdoc/clean/types.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1408,14 +1408,14 @@ impl Type {
14081408
}
14091409
}
14101410

1411-
crate fn generics(&self) -> Option<Vec<Type>> {
1411+
crate fn generics(&self) -> Option<Vec<&Type>> {
14121412
match *self {
14131413
ResolvedPath { ref path, .. } => path.segments.last().and_then(|seg| {
14141414
if let GenericArgs::AngleBracketed { ref args, .. } = seg.args {
14151415
Some(
14161416
args.iter()
14171417
.filter_map(|arg| match arg {
1418-
GenericArg::Type(ty) => Some(ty.clone()),
1418+
GenericArg::Type(ty) => Some(ty),
14191419
_ => None,
14201420
})
14211421
.collect(),

src/librustdoc/html/render/cache.rs

+125-3
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,6 @@ crate fn build_index<'tcx>(krate: &clean::Crate, cache: &mut Cache, tcx: TyCtxt<
7070
let mut crate_items = Vec::with_capacity(cache.search_index.len());
7171
let mut crate_paths = vec![];
7272

73-
// For now we don't get the primitive types in the search index.
74-
let empty_cache = Cache::default();
7573
// Attach all orphan items to the type's definition if the type
7674
// has since been learned.
7775
for &(did, ref item) in &cache.orphan_impl_items {
@@ -83,7 +81,7 @@ crate fn build_index<'tcx>(krate: &clean::Crate, cache: &mut Cache, tcx: TyCtxt<
8381
desc: item.doc_value().map_or_else(String::new, |s| short_markdown_summary(&s)),
8482
parent: Some(did),
8583
parent_idx: None,
86-
search_type: get_index_search_type(&item, cache),
84+
search_type: get_index_search_type(&item, cache, tcx),
8785
});
8886
for alias in item.attrs.get_doc_aliases() {
8987
cache
@@ -248,3 +246,127 @@ fn get_generics(clean_type: &clean::Type, cache: &Cache) -> Option<Vec<Generic>>
248246
if r.is_empty() { None } else { Some(r) }
249247
})
250248
}
249+
250+
/// The point of this function is to replace bounds with types.
251+
///
252+
/// i.e. `[T, U]` when you have the following bounds: `T: Display, U: Option<T>` will return
253+
/// `[Display, Option]` (we just returns the list of the types, we don't care about the
254+
/// wrapped types in here).
255+
crate fn get_real_types<'tcx>(
256+
generics: &Generics,
257+
arg: &Type,
258+
tcx: TyCtxt<'tcx>,
259+
recurse: i32,
260+
cache: &Cache,
261+
res: &mut FxHashSet<(Type, TypeKind)>,
262+
) -> usize {
263+
fn insert(res: &mut FxHashSet<(Type, TypeKind)>, tcx: TyCtxt<'_>, ty: Type) -> usize {
264+
if let Some(kind) = ty.def_id().map(|did| tcx.def_kind(did).into()) {
265+
res.insert((ty, kind));
266+
1
267+
} else if ty.is_primitive() {
268+
// This is a primitive, let's store it as such.
269+
res.insert((ty, TypeKind::Primitive));
270+
1
271+
} else {
272+
0
273+
}
274+
}
275+
276+
if recurse >= 10 {
277+
// FIXME: remove this whole recurse thing when the recursion bug is fixed
278+
return 0;
279+
}
280+
let mut nb_added = 0;
281+
282+
if arg.is_full_generic() {
283+
let arg_s = Symbol::intern(&arg.print(cache).to_string());
284+
if let Some(where_pred) = generics.where_predicates.iter().find(|g| match g {
285+
WherePredicate::BoundPredicate { ty, .. } => ty.def_id() == arg.def_id(),
286+
_ => false,
287+
}) {
288+
let bounds = where_pred.get_bounds().unwrap_or_else(|| &[]);
289+
for bound in bounds.iter() {
290+
if let GenericBound::TraitBound(poly_trait, _) = bound {
291+
for x in poly_trait.generic_params.iter() {
292+
if !x.is_type() {
293+
continue;
294+
}
295+
if let Some(ty) = x.get_type() {
296+
let adds = get_real_types(generics, &ty, tcx, recurse + 1, cache, res);
297+
nb_added += adds;
298+
if adds == 0 && !ty.is_full_generic() {
299+
nb_added += insert(res, tcx, ty);
300+
}
301+
}
302+
}
303+
}
304+
}
305+
}
306+
if let Some(bound) = generics.params.iter().find(|g| g.is_type() && g.name == arg_s) {
307+
for bound in bound.get_bounds().unwrap_or_else(|| &[]) {
308+
if let Some(ty) = bound.get_trait_type() {
309+
let adds = get_real_types(generics, &ty, tcx, recurse + 1, cache, res);
310+
nb_added += adds;
311+
if adds == 0 && !ty.is_full_generic() {
312+
nb_added += insert(res, tcx, ty);
313+
}
314+
}
315+
}
316+
}
317+
} else {
318+
nb_added += insert(res, tcx, arg.clone());
319+
if let Some(gens) = arg.generics() {
320+
for gen in gens.iter() {
321+
if gen.is_full_generic() {
322+
nb_added += get_real_types(generics, gen, tcx, recurse + 1, cache, res);
323+
} else {
324+
nb_added += insert(res, tcx, (*gen).clone());
325+
}
326+
}
327+
}
328+
}
329+
nb_added
330+
}
331+
332+
/// Return the full list of types when bounds have been resolved.
333+
///
334+
/// i.e. `fn foo<A: Display, B: Option<A>>(x: u32, y: B)` will return
335+
/// `[u32, Display, Option]`.
336+
crate fn get_all_types<'tcx>(
337+
generics: &Generics,
338+
decl: &FnDecl,
339+
tcx: TyCtxt<'tcx>,
340+
cache: &Cache,
341+
) -> (Vec<(Type, TypeKind)>, Vec<(Type, TypeKind)>) {
342+
let mut all_types = FxHashSet::default();
343+
for arg in decl.inputs.values.iter() {
344+
if arg.type_.is_self_type() {
345+
continue;
346+
}
347+
let mut args = FxHashSet::default();
348+
get_real_types(generics, &arg.type_, tcx, 0, cache, &mut args);
349+
if !args.is_empty() {
350+
all_types.extend(args);
351+
} else {
352+
if let Some(kind) = arg.type_.def_id().map(|did| tcx.def_kind(did).into()) {
353+
all_types.insert((arg.type_.clone(), kind));
354+
}
355+
}
356+
}
357+
358+
let ret_types = match decl.output {
359+
FnRetTy::Return(ref return_type) => {
360+
let mut ret = FxHashSet::default();
361+
get_real_types(generics, &return_type, tcx, 0, cache, &mut ret);
362+
if ret.is_empty() {
363+
if let Some(kind) = return_type.def_id().map(|did| tcx.def_kind(did).into()) {
364+
ret.insert((return_type.clone(), kind));
365+
}
366+
}
367+
ret.into_iter().collect()
368+
}
369+
_ => Vec::new(),
370+
};
371+
(all_types.into_iter().collect(), ret_types)
372+
}

0 commit comments

Comments
 (0)