]> git.lizzy.rs Git - rust.git/commitdiff
Improve html::render::cache::get_real_types code
authorGuillaume Gomez <guillaume1.gomez@gmail.com>
Thu, 28 Jan 2021 15:23:41 +0000 (16:23 +0100)
committerGuillaume Gomez <guillaume1.gomez@gmail.com>
Fri, 5 Feb 2021 16:23:54 +0000 (17:23 +0100)
src/librustdoc/clean/types.rs
src/librustdoc/html/render/cache.rs

index efa7fcc6838ea3bcd9908e5bf1742297a25a3f5d..ca8ee8ac82d23e9a8d8ca73d96661b944e7304ca 100644 (file)
@@ -1408,14 +1408,14 @@ impl Type {
         }
     }
 
-    crate fn generics(&self) -> Option<Vec<Type>> {
+    crate fn generics(&self) -> Option<Vec<&Type>> {
         match *self {
             ResolvedPath { ref path, .. } => path.segments.last().and_then(|seg| {
                 if let GenericArgs::AngleBracketed { ref args, .. } = seg.args {
                     Some(
                         args.iter()
                             .filter_map(|arg| match arg {
-                                GenericArg::Type(ty) => Some(ty.clone()),
+                                GenericArg::Type(ty) => Some(ty),
                                 _ => None,
                             })
                             .collect(),
index e47692063bd78c24f3052d83970998dc32925ba1..821f1cc71a3d8079e16f83196de9d857ad5c2d9b 100644 (file)
@@ -70,8 +70,6 @@
     let mut crate_items = Vec::with_capacity(cache.search_index.len());
     let mut crate_paths = vec![];
 
-    // For now we don't get the primitive types in the search index.
-    let empty_cache = Cache::default();
     // Attach all orphan items to the type's definition if the type
     // has since been learned.
     for &(did, ref item) in &cache.orphan_impl_items {
@@ -83,7 +81,7 @@
                 desc: item.doc_value().map_or_else(String::new, |s| short_markdown_summary(&s)),
                 parent: Some(did),
                 parent_idx: None,
-                search_type: get_index_search_type(&item, cache),
+                search_type: get_index_search_type(&item, cache, tcx),
             });
             for alias in item.attrs.get_doc_aliases() {
                 cache
@@ -248,3 +246,127 @@ fn get_generics(clean_type: &clean::Type, cache: &Cache) -> Option<Vec<Generic>>
         if r.is_empty() { None } else { Some(r) }
     })
 }
+
+/// The point of this function is to replace bounds with types.
+///
+/// i.e. `[T, U]` when you have the following bounds: `T: Display, U: Option<T>` will return
+/// `[Display, Option]` (we just returns the list of the types, we don't care about the
+/// wrapped types in here).
+crate fn get_real_types<'tcx>(
+    generics: &Generics,
+    arg: &Type,
+    tcx: TyCtxt<'tcx>,
+    recurse: i32,
+    cache: &Cache,
+    res: &mut FxHashSet<(Type, TypeKind)>,
+) -> usize {
+    fn insert(res: &mut FxHashSet<(Type, TypeKind)>, tcx: TyCtxt<'_>, ty: Type) -> usize {
+        if let Some(kind) = ty.def_id().map(|did| tcx.def_kind(did).into()) {
+            res.insert((ty, kind));
+            1
+        } else if ty.is_primitive() {
+            // This is a primitive, let's store it as such.
+            res.insert((ty, TypeKind::Primitive));
+            1
+        } else {
+            0
+        }
+    }
+
+    if recurse >= 10 {
+        // FIXME: remove this whole recurse thing when the recursion bug is fixed
+        return 0;
+    }
+    let mut nb_added = 0;
+
+    if arg.is_full_generic() {
+        let arg_s = Symbol::intern(&arg.print(cache).to_string());
+        if let Some(where_pred) = generics.where_predicates.iter().find(|g| match g {
+            WherePredicate::BoundPredicate { ty, .. } => ty.def_id() == arg.def_id(),
+            _ => false,
+        }) {
+            let bounds = where_pred.get_bounds().unwrap_or_else(|| &[]);
+            for bound in bounds.iter() {
+                if let GenericBound::TraitBound(poly_trait, _) = bound {
+                    for x in poly_trait.generic_params.iter() {
+                        if !x.is_type() {
+                            continue;
+                        }
+                        if let Some(ty) = x.get_type() {
+                            let adds = get_real_types(generics, &ty, tcx, recurse + 1, cache, res);
+                            nb_added += adds;
+                            if adds == 0 && !ty.is_full_generic() {
+                                nb_added += insert(res, tcx, ty);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        if let Some(bound) = generics.params.iter().find(|g| g.is_type() && g.name == arg_s) {
+            for bound in bound.get_bounds().unwrap_or_else(|| &[]) {
+                if let Some(ty) = bound.get_trait_type() {
+                    let adds = get_real_types(generics, &ty, tcx, recurse + 1, cache, res);
+                    nb_added += adds;
+                    if adds == 0 && !ty.is_full_generic() {
+                        nb_added += insert(res, tcx, ty);
+                    }
+                }
+            }
+        }
+    } else {
+        nb_added += insert(res, tcx, arg.clone());
+        if let Some(gens) = arg.generics() {
+            for gen in gens.iter() {
+                if gen.is_full_generic() {
+                    nb_added += get_real_types(generics, gen, tcx, recurse + 1, cache, res);
+                } else {
+                    nb_added += insert(res, tcx, (*gen).clone());
+                }
+            }
+        }
+    }
+    nb_added
+}
+
+/// Return the full list of types when bounds have been resolved.
+///
+/// i.e. `fn foo<A: Display, B: Option<A>>(x: u32, y: B)` will return
+/// `[u32, Display, Option]`.
+crate fn get_all_types<'tcx>(
+    generics: &Generics,
+    decl: &FnDecl,
+    tcx: TyCtxt<'tcx>,
+    cache: &Cache,
+) -> (Vec<(Type, TypeKind)>, Vec<(Type, TypeKind)>) {
+    let mut all_types = FxHashSet::default();
+    for arg in decl.inputs.values.iter() {
+        if arg.type_.is_self_type() {
+            continue;
+        }
+        let mut args = FxHashSet::default();
+        get_real_types(generics, &arg.type_, tcx, 0, cache, &mut args);
+        if !args.is_empty() {
+            all_types.extend(args);
+        } else {
+            if let Some(kind) = arg.type_.def_id().map(|did| tcx.def_kind(did).into()) {
+                all_types.insert((arg.type_.clone(), kind));
+            }
+        }
+    }
+
+    let ret_types = match decl.output {
+        FnRetTy::Return(ref return_type) => {
+            let mut ret = FxHashSet::default();
+            get_real_types(generics, &return_type, tcx, 0, cache, &mut ret);
+            if ret.is_empty() {
+                if let Some(kind) = return_type.def_id().map(|did| tcx.def_kind(did).into()) {
+                    ret.insert((return_type.clone(), kind));
+                }
+            }
+            ret.into_iter().collect()
+        }
+        _ => Vec::new(),
+    };
+    (all_types.into_iter().collect(), ret_types)
+}