diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 2588c00f2cffd..cdff37cbd51f4 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -217,13 +217,10 @@ fn build_external_function(cx: &DocContext<'_>, did: DefId) -> clean::Function { let (generics, decl) = clean::enter_impl_trait(cx, || { ((cx.tcx.generics_of(did), predicates).clean(cx), (did, sig).clean(cx)) }); - let (all_types, ret_types) = clean::get_all_types(&generics, &decl, cx); clean::Function { decl, generics, header: hir::FnHeader { unsafety: sig.unsafety(), abi: sig.abi(), constness, asyncness }, - all_types, - ret_types, } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 03454bb8b7ff0..331bb2a73f962 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -928,8 +928,7 @@ impl<'a> Clean for (&'a hir::FnSig<'a>, &'a hir::Generics<'a>, hir::Bo fn clean(&self, cx: &DocContext<'_>) -> Function { let (generics, decl) = enter_impl_trait(cx, || (self.1.clean(cx), (&*self.0.decl, self.2).clean(cx))); - let (all_types, ret_types) = get_all_types(&generics, &decl, cx); - Function { decl, generics, header: self.0.header, all_types, ret_types } + Function { decl, generics, header: self.0.header } } } @@ -1043,21 +1042,7 @@ impl Clean for hir::PolyTraitRef<'_> { impl Clean for hir::def::DefKind { fn clean(&self, _: &DocContext<'_>) -> TypeKind { - match *self { - hir::def::DefKind::Mod => TypeKind::Module, - hir::def::DefKind::Struct => TypeKind::Struct, - hir::def::DefKind::Union => TypeKind::Union, - hir::def::DefKind::Enum => TypeKind::Enum, - hir::def::DefKind::Trait => TypeKind::Trait, - hir::def::DefKind::TyAlias => TypeKind::Typedef, - hir::def::DefKind::ForeignTy => TypeKind::Foreign, - hir::def::DefKind::TraitAlias => TypeKind::TraitAlias, - hir::def::DefKind::Fn => TypeKind::Function, - hir::def::DefKind::Const => TypeKind::Const, - hir::def::DefKind::Static => TypeKind::Static, - hir::def::DefKind::Macro(_) => TypeKind::Macro, - _ => TypeKind::Foreign, - } + (*self).into() } } @@ -1082,9 +1067,7 @@ impl Clean for hir::TraitItem<'_> { let (generics, decl) = enter_impl_trait(cx, || { (self.generics.clean(cx), (&*sig.decl, &names[..]).clean(cx)) }); - let (all_types, ret_types) = get_all_types(&generics, &decl, cx); - let mut t = - Function { header: sig.header, decl, generics, all_types, ret_types }; + let mut t = Function { header: sig.header, decl, generics }; if t.header.constness == hir::Constness::Const && is_unstable_const_fn(cx.tcx, local_did).is_some() { @@ -1196,7 +1179,6 @@ impl Clean for ty::AssocItem { ty::ImplContainer(_) => true, ty::TraitContainer(_) => self.defaultness.has_value(), }; - let (all_types, ret_types) = get_all_types(&generics, &decl, cx); if provided { let constness = if is_min_const_fn(cx.tcx, self.def_id) { hir::Constness::Const @@ -1218,8 +1200,6 @@ impl Clean for ty::AssocItem { constness, asyncness, }, - all_types, - ret_types, }, defaultness, ) @@ -1233,8 +1213,6 @@ impl Clean for ty::AssocItem { constness: hir::Constness::NotConst, asyncness: hir::IsAsync::NotAsync, }, - all_types, - ret_types, }) } } @@ -2274,7 +2252,6 @@ impl Clean for (&hir::ForeignItem<'_>, Option) { let (generics, decl) = enter_impl_trait(cx, || { (generics.clean(cx), (&**decl, &names[..]).clean(cx)) }); - let (all_types, ret_types) = get_all_types(&generics, &decl, cx); ForeignFunctionItem(Function { decl, generics, @@ -2284,8 +2261,6 @@ impl Clean for (&hir::ForeignItem<'_>, Option) { constness: hir::Constness::NotConst, asyncness: hir::IsAsync::NotAsync, }, - all_types, - ret_types, }) } hir::ForeignItemKind::Static(ref ty, mutability) => ForeignStaticItem(Static { diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index e509ec3f0213f..754f1c2eeeb21 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1087,8 +1087,6 @@ crate struct Function { crate decl: FnDecl, crate generics: Generics, crate header: hir::FnHeader, - crate all_types: Vec<(Type, TypeKind)>, - crate ret_types: Vec<(Type, TypeKind)>, } #[derive(Clone, PartialEq, Eq, Debug, Hash)] @@ -1304,6 +1302,43 @@ crate enum TypeKind { Primitive, } +impl From for TypeKind { + fn from(other: hir::def::DefKind) -> Self { + match other { + hir::def::DefKind::Enum => Self::Enum, + hir::def::DefKind::Fn => Self::Function, + hir::def::DefKind::Mod => Self::Module, + hir::def::DefKind::Const => Self::Const, + hir::def::DefKind::Static => Self::Static, + hir::def::DefKind::Struct => Self::Struct, + hir::def::DefKind::Union => Self::Union, + hir::def::DefKind::Trait => Self::Trait, + hir::def::DefKind::TyAlias => Self::Typedef, + hir::def::DefKind::TraitAlias => Self::TraitAlias, + hir::def::DefKind::Macro(_) => Self::Macro, + hir::def::DefKind::ForeignTy + | hir::def::DefKind::Variant + | hir::def::DefKind::AssocTy + | hir::def::DefKind::TyParam + | hir::def::DefKind::ConstParam + | hir::def::DefKind::Ctor(..) + | hir::def::DefKind::AssocFn + | hir::def::DefKind::AssocConst + | hir::def::DefKind::ExternCrate + | hir::def::DefKind::Use + | hir::def::DefKind::ForeignMod + | hir::def::DefKind::AnonConst + | hir::def::DefKind::OpaqueTy + | hir::def::DefKind::Field + | hir::def::DefKind::LifetimeParam + | hir::def::DefKind::GlobalAsm + | hir::def::DefKind::Impl + | hir::def::DefKind::Closure + | hir::def::DefKind::Generator => Self::Foreign, + } + } +} + crate trait GetDefId { /// Use this method to get the [`DefId`] of a [`clean`] AST node. /// This will return [`None`] when called on a primitive [`clean::Type`]. @@ -1367,14 +1402,14 @@ impl Type { } } - crate fn generics(&self) -> Option> { + crate fn generics(&self) -> Option> { 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(), diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index e380d4672d055..2c829c49953ff 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -1,10 +1,9 @@ use crate::clean::auto_trait::AutoTraitFinder; use crate::clean::blanket_impl::BlanketImplFinder; use crate::clean::{ - inline, Clean, Crate, ExternalCrate, FnDecl, FnRetTy, Generic, GenericArg, GenericArgs, - GenericBound, Generics, GetDefId, ImportSource, Item, ItemKind, Lifetime, MacroKind, Path, - PathSegment, Primitive, PrimitiveType, ResolvedPath, Type, TypeBinding, TypeKind, - WherePredicate, + inline, Clean, Crate, ExternalCrate, Generic, GenericArg, GenericArgs, ImportSource, Item, + ItemKind, Lifetime, MacroKind, Path, PathSegment, Primitive, PrimitiveType, ResolvedPath, Type, + TypeBinding, TypeKind, }; use crate::core::DocContext; @@ -160,125 +159,6 @@ pub(super) fn external_path( } } -/// 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` 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( - generics: &Generics, - arg: &Type, - cx: &DocContext<'_>, - recurse: i32, -) -> FxHashSet<(Type, TypeKind)> { - fn insert(res: &mut FxHashSet<(Type, TypeKind)>, cx: &DocContext<'_>, ty: Type) { - if let Some(kind) = ty.def_id().map(|did| cx.tcx.def_kind(did).clean(cx)) { - res.insert((ty, kind)); - } else if ty.is_primitive() { - // This is a primitive, let's store it as such. - res.insert((ty, TypeKind::Primitive)); - } - } - let mut res = FxHashSet::default(); - if recurse >= 10 { - // FIXME: remove this whole recurse thing when the recursion bug is fixed - return res; - } - - if arg.is_full_generic() { - let arg_s = Symbol::intern(&arg.print(&cx.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, cx, recurse + 1); - if !adds.is_empty() { - res.extend(adds); - } else if !ty.is_full_generic() { - insert(&mut res, cx, 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, cx, recurse + 1); - if !adds.is_empty() { - res.extend(adds); - } else if !ty.is_full_generic() { - insert(&mut res, cx, ty); - } - } - } - } - } else { - insert(&mut res, cx, arg.clone()); - if let Some(gens) = arg.generics() { - for gen in gens.iter() { - if gen.is_full_generic() { - let adds = get_real_types(generics, gen, cx, recurse + 1); - if !adds.is_empty() { - res.extend(adds); - } - } else { - insert(&mut res, cx, gen.clone()); - } - } - } - } - res -} - -/// Return the full list of types when bounds have been resolved. -/// -/// i.e. `fn foo>(x: u32, y: B)` will return -/// `[u32, Display, Option]`. -crate fn get_all_types( - generics: &Generics, - decl: &FnDecl, - cx: &DocContext<'_>, -) -> (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 args = get_real_types(generics, &arg.type_, cx, 0); - if !args.is_empty() { - all_types.extend(args); - } else { - if let Some(kind) = arg.type_.def_id().map(|did| cx.tcx.def_kind(did).clean(cx)) { - all_types.insert((arg.type_.clone(), kind)); - } - } - } - - let ret_types = match decl.output { - FnRetTy::Return(ref return_type) => { - let mut ret = get_real_types(generics, &return_type, cx, 0); - if ret.is_empty() { - if let Some(kind) = return_type.def_id().map(|did| cx.tcx.def_kind(did).clean(cx)) { - ret.insert((return_type.clone(), kind)); - } - } - ret.into_iter().collect() - } - _ => Vec::new(), - }; - (all_types.into_iter().collect(), ret_types) -} - crate fn strip_type(ty: Type) -> Type { match ty { Type::ResolvedPath { path, param_names, did, is_generic } => { diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index c506f5a37b15b..ce1204c7be19c 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -5,6 +5,7 @@ use std::path::{Path, PathBuf}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX}; use rustc_middle::middle::privacy::AccessLevels; +use rustc_middle::ty::TyCtxt; use rustc_span::source_map::FileName; use rustc_span::Symbol; @@ -121,13 +122,21 @@ crate struct Cache { crate aliases: BTreeMap>, } +/// This struct is used to wrap the `cache` and `tcx` in order to run `DocFolder`. +struct CacheBuilder<'a, 'tcx> { + cache: &'a mut Cache, + empty_cache: Cache, + tcx: TyCtxt<'tcx>, +} + impl Cache { - crate fn from_krate( + crate fn from_krate<'tcx>( render_info: RenderInfo, document_private: bool, extern_html_root_urls: &BTreeMap, dst: &Path, mut krate: clean::Crate, + tcx: TyCtxt<'tcx>, ) -> (clean::Crate, Cache) { // Crawl the crate to build various caches used for the output let RenderInfo { @@ -194,7 +203,8 @@ impl Cache { cache.stack.push(krate.name.to_string()); - krate = cache.fold_crate(krate); + krate = CacheBuilder { tcx, cache: &mut cache, empty_cache: Cache::default() } + .fold_crate(krate); for (trait_did, dids, impl_) in cache.orphan_trait_impls.drain(..) { if cache.traits.contains_key(&trait_did) { @@ -208,7 +218,7 @@ impl Cache { } } -impl DocFolder for Cache { +impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> { fn fold_item(&mut self, item: clean::Item) -> Option { if item.def_id.is_local() { debug!("folding {} \"{:?}\", id {:?}", item.type_(), item.name, item.def_id); @@ -218,17 +228,17 @@ impl DocFolder for Cache { // we don't want it or its children in the search index. let orig_stripped_mod = match *item.kind { clean::StrippedItem(box clean::ModuleItem(..)) => { - mem::replace(&mut self.stripped_mod, true) + mem::replace(&mut self.cache.stripped_mod, true) } - _ => self.stripped_mod, + _ => self.cache.stripped_mod, }; // If the impl is from a masked crate or references something from a // masked crate then remove it completely. if let clean::ImplItem(ref i) = *item.kind { - if self.masked_crates.contains(&item.def_id.krate) - || i.trait_.def_id().map_or(false, |d| self.masked_crates.contains(&d.krate)) - || i.for_.def_id().map_or(false, |d| self.masked_crates.contains(&d.krate)) + if self.cache.masked_crates.contains(&item.def_id.krate) + || i.trait_.def_id().map_or(false, |d| self.cache.masked_crates.contains(&d.krate)) + || i.for_.def_id().map_or(false, |d| self.cache.masked_crates.contains(&d.krate)) { return None; } @@ -237,14 +247,15 @@ impl DocFolder for Cache { // Propagate a trait method's documentation to all implementors of the // trait. if let clean::TraitItem(ref t) = *item.kind { - self.traits.entry(item.def_id).or_insert_with(|| t.clone()); + self.cache.traits.entry(item.def_id).or_insert_with(|| t.clone()); } // Collect all the implementors of traits. if let clean::ImplItem(ref i) = *item.kind { if let Some(did) = i.trait_.def_id() { if i.blanket_impl.is_none() { - self.implementors + self.cache + .implementors .entry(did) .or_default() .push(Impl { impl_item: item.clone() }); @@ -257,7 +268,7 @@ impl DocFolder for Cache { let (parent, is_inherent_impl_item) = match *item.kind { clean::StrippedItem(..) => ((None, None), false), clean::AssocConstItem(..) | clean::TypedefItem(_, true) - if self.parent_is_trait_impl => + if self.cache.parent_is_trait_impl => { // skip associated items in trait impls ((None, None), false) @@ -267,18 +278,18 @@ impl DocFolder for Cache { | clean::StructFieldItem(..) | clean::VariantItem(..) => ( ( - Some(*self.parent_stack.last().expect("parent_stack is empty")), - Some(&self.stack[..self.stack.len() - 1]), + Some(*self.cache.parent_stack.last().expect("parent_stack is empty")), + Some(&self.cache.stack[..self.cache.stack.len() - 1]), ), false, ), clean::MethodItem(..) | clean::AssocConstItem(..) => { - if self.parent_stack.is_empty() { + if self.cache.parent_stack.is_empty() { ((None, None), false) } else { - let last = self.parent_stack.last().expect("parent_stack is empty 2"); + let last = self.cache.parent_stack.last().expect("parent_stack is empty 2"); let did = *last; - let path = match self.paths.get(&did) { + let path = match self.cache.paths.get(&did) { // The current stack not necessarily has correlation // for where the type was defined. On the other // hand, `paths` always has the right @@ -290,24 +301,24 @@ impl DocFolder for Cache { | ItemType::Union | ItemType::Enum, )) => Some(&fqp[..fqp.len() - 1]), - Some(..) => Some(&*self.stack), + Some(..) => Some(&*self.cache.stack), None => None, }; ((Some(*last), path), true) } } - _ => ((None, Some(&*self.stack)), false), + _ => ((None, Some(&*self.cache.stack)), false), }; match parent { - (parent, Some(path)) if is_inherent_impl_item || !self.stripped_mod => { + (parent, Some(path)) if is_inherent_impl_item || !self.cache.stripped_mod => { debug_assert!(!item.is_stripped()); // A crate has a module at its root, containing all items, // which should not be indexed. The crate-item itself is // inserted later on when serializing the search-index. if item.def_id.index != CRATE_DEF_INDEX { - self.search_index.push(IndexItem { + self.cache.search_index.push(IndexItem { ty: item.type_(), name: s.to_string(), path: path.join("::"), @@ -316,21 +327,22 @@ impl DocFolder for Cache { .map_or_else(String::new, |x| short_markdown_summary(&x.as_str())), parent, parent_idx: None, - search_type: get_index_search_type(&item, None), + search_type: get_index_search_type(&item, &self.empty_cache, self.tcx), }); for alias in item.attrs.get_doc_aliases() { - self.aliases + self.cache + .aliases .entry(alias.to_lowercase()) .or_insert(Vec::new()) - .push(self.search_index.len() - 1); + .push(self.cache.search_index.len() - 1); } } } (Some(parent), None) if is_inherent_impl_item => { // We have a parent, but we don't know where they're // defined yet. Wait for later to index this item. - self.orphan_impl_items.push((parent, item.clone())); + self.cache.orphan_impl_items.push((parent, item.clone())); } _ => {} } @@ -339,7 +351,7 @@ impl DocFolder for Cache { // Keep track of the fully qualified path for this item. let pushed = match item.name { Some(n) if !n.is_empty() => { - self.stack.push(n.to_string()); + self.cache.stack.push(n.to_string()); true } _ => false, @@ -361,7 +373,7 @@ impl DocFolder for Cache { | clean::MacroItem(..) | clean::ProcMacroItem(..) | clean::VariantItem(..) - if !self.stripped_mod => + if !self.cache.stripped_mod => { // Re-exported items mean that the same id can show up twice // in the rustdoc ast that we're looking at. We know, @@ -369,21 +381,21 @@ impl DocFolder for Cache { // `public_items` map, so we can skip inserting into the // paths map if there was already an entry present and we're // not a public item. - if !self.paths.contains_key(&item.def_id) - || self.access_levels.is_public(item.def_id) + if !self.cache.paths.contains_key(&item.def_id) + || self.cache.access_levels.is_public(item.def_id) { - self.paths.insert(item.def_id, (self.stack.clone(), item.type_())); + self.cache.paths.insert(item.def_id, (self.cache.stack.clone(), item.type_())); } } clean::PrimitiveItem(..) => { - self.paths.insert(item.def_id, (self.stack.clone(), item.type_())); + self.cache.paths.insert(item.def_id, (self.cache.stack.clone(), item.type_())); } _ => {} } // Maintain the parent stack - let orig_parent_is_trait_impl = self.parent_is_trait_impl; + let orig_parent_is_trait_impl = self.cache.parent_is_trait_impl; let parent_pushed = match *item.kind { clean::TraitItem(..) | clean::EnumItem(..) @@ -391,24 +403,24 @@ impl DocFolder for Cache { | clean::StructItem(..) | clean::UnionItem(..) | clean::VariantItem(..) => { - self.parent_stack.push(item.def_id); - self.parent_is_trait_impl = false; + self.cache.parent_stack.push(item.def_id); + self.cache.parent_is_trait_impl = false; true } clean::ImplItem(ref i) => { - self.parent_is_trait_impl = i.trait_.is_some(); + self.cache.parent_is_trait_impl = i.trait_.is_some(); match i.for_ { clean::ResolvedPath { did, .. } => { - self.parent_stack.push(did); + self.cache.parent_stack.push(did); true } ref t => { let prim_did = t .primitive_type() - .and_then(|t| self.primitive_locations.get(&t).cloned()); + .and_then(|t| self.cache.primitive_locations.get(&t).cloned()); match prim_did { Some(did) => { - self.parent_stack.push(did); + self.cache.parent_stack.push(did); true } None => false, @@ -433,8 +445,9 @@ impl DocFolder for Cache { dids.insert(did); } ref t => { - let did = - t.primitive_type().and_then(|t| self.primitive_locations.get(&t).cloned()); + let did = t + .primitive_type() + .and_then(|t| self.cache.primitive_locations.get(&t).cloned()); if let Some(did) = did { dids.insert(did); @@ -450,13 +463,13 @@ impl DocFolder for Cache { } } let impl_item = Impl { impl_item: item }; - if impl_item.trait_did().map_or(true, |d| self.traits.contains_key(&d)) { + if impl_item.trait_did().map_or(true, |d| self.cache.traits.contains_key(&d)) { for did in dids { - self.impls.entry(did).or_insert(vec![]).push(impl_item.clone()); + self.cache.impls.entry(did).or_insert(vec![]).push(impl_item.clone()); } } else { let trait_did = impl_item.trait_did().expect("no trait did"); - self.orphan_trait_impls.push((trait_did, dids, impl_item)); + self.cache.orphan_trait_impls.push((trait_did, dids, impl_item)); } None } else { @@ -464,13 +477,13 @@ impl DocFolder for Cache { }; if pushed { - self.stack.pop().expect("stack already empty"); + self.cache.stack.pop().expect("stack already empty"); } if parent_pushed { - self.parent_stack.pop().expect("parent stack already empty"); + self.cache.parent_stack.pop().expect("parent stack already empty"); } - self.stripped_mod = orig_stripped_mod; - self.parent_is_trait_impl = orig_parent_is_trait_impl; + self.cache.stripped_mod = orig_stripped_mod; + self.cache.parent_is_trait_impl = orig_parent_is_trait_impl; ret } } diff --git a/src/librustdoc/formats/renderer.rs b/src/librustdoc/formats/renderer.rs index 6ecc4695dc8fb..6437ba45511a1 100644 --- a/src/librustdoc/formats/renderer.rs +++ b/src/librustdoc/formats/renderer.rs @@ -61,6 +61,7 @@ crate fn run_format<'tcx, T: FormatRenderer<'tcx>>( &options.extern_html_root_urls, &options.output, krate, + tcx, ) }); let prof = &tcx.sess.prof; diff --git a/src/librustdoc/html/render/cache.rs b/src/librustdoc/html/render/cache.rs index 4dd7110f331d6..a21cf5266fe1f 100644 --- a/src/librustdoc/html/render/cache.rs +++ b/src/librustdoc/html/render/cache.rs @@ -1,11 +1,14 @@ use std::collections::BTreeMap; use std::path::Path; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_middle::ty::TyCtxt; use rustc_span::symbol::{sym, Symbol}; use serde::Serialize; -use crate::clean::types::GetDefId; +use crate::clean::types::{ + FnDecl, FnRetTy, GenericBound, Generics, GetDefId, Type, TypeKind, WherePredicate, +}; use crate::clean::{self, AttributesExt}; use crate::formats::cache::Cache; use crate::formats::item_type::ItemType; @@ -62,7 +65,7 @@ crate fn extern_location( } /// Builds the search index from the collected metadata -crate fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String { +crate fn build_index<'tcx>(krate: &clean::Crate, cache: &mut Cache, tcx: TyCtxt<'tcx>) -> String { let mut defid_to_pathid = FxHashMap::default(); let mut crate_items = Vec::with_capacity(cache.search_index.len()); let mut crate_paths = vec![]; @@ -78,7 +81,7 @@ crate fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String { 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, Some(cache)), + search_type: get_index_search_type(&item, cache, tcx), }); for alias in item.attrs.get_doc_aliases() { cache @@ -164,14 +167,15 @@ crate fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String { ) } -crate fn get_index_search_type( +crate fn get_index_search_type<'tcx>( item: &clean::Item, - cache: Option<&Cache>, + cache: &Cache, + tcx: TyCtxt<'tcx>, ) -> Option { let (all_types, ret_types) = match *item.kind { - clean::FunctionItem(ref f) => (&f.all_types, &f.ret_types), - clean::MethodItem(ref m, _) => (&m.all_types, &m.ret_types), - clean::TyMethodItem(ref m) => (&m.all_types, &m.ret_types), + clean::FunctionItem(ref f) => get_all_types(&f.generics, &f.decl, tcx), + clean::MethodItem(ref m, _) => get_all_types(&m.generics, &m.decl, tcx), + clean::TyMethodItem(ref m) => get_all_types(&m.generics, &m.decl, tcx), _ => return None, }; @@ -190,9 +194,9 @@ crate fn get_index_search_type( Some(IndexItemFunctionType { inputs, output }) } -fn get_index_type(clean_type: &clean::Type, cache: &Option<&Cache>) -> RenderType { +fn get_index_type(clean_type: &clean::Type, cache: &Cache) -> RenderType { RenderType { - ty: cache.map_or_else(|| clean_type.def_id(), |cache| clean_type.def_id_full(cache)), + ty: clean_type.def_id_full(cache), idx: None, name: get_index_type_name(clean_type, true).map(|s| s.as_str().to_ascii_lowercase()), generics: get_generics(clean_type, cache), @@ -227,14 +231,14 @@ fn get_index_type_name(clean_type: &clean::Type, accept_generic: bool) -> Option } } -fn get_generics(clean_type: &clean::Type, cache: &Option<&Cache>) -> Option> { +fn get_generics(clean_type: &clean::Type, cache: &Cache) -> Option> { clean_type.generics().and_then(|types| { let r = types .iter() .filter_map(|t| { get_index_type_name(t, false).map(|name| Generic { name: name.as_str().to_ascii_lowercase(), - defid: cache.map_or_else(|| t.def_id(), |cache| t.def_id_full(cache)), + defid: t.def_id_full(cache), idx: None, }) }) @@ -242,3 +246,124 @@ fn get_generics(clean_type: &clean::Type, cache: &Option<&Cache>) -> Option` 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, + 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 let &Type::Generic(arg_s) = arg { + 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, 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(&[]) { + if let Some(ty) = bound.get_trait_type() { + let adds = get_real_types(generics, &ty, tcx, recurse + 1, 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, 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>(x: u32, y: B)` will return +/// `[u32, Display, Option]`. +crate fn get_all_types<'tcx>( + generics: &Generics, + decl: &FnDecl, + tcx: TyCtxt<'tcx>, +) -> (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, &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, &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) +} diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 6909ab870db61..16366d7b1310e 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -499,7 +499,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { krate = sources::render(&dst, &mut scx, krate)?; // Build our search index - let index = build_index(&krate, &mut cache); + let index = build_index(&krate, &mut cache, tcx); let mut cx = Context { current: Vec::new(), diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 026d8f96dee65..9107ba59bd013 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -238,7 +238,7 @@ fn stringify_header(header: &rustc_hir::FnHeader) -> String { impl From for Function { fn from(function: clean::Function) -> Self { - let clean::Function { decl, generics, header, all_types: _, ret_types: _ } = function; + let clean::Function { decl, generics, header } = function; Function { decl: decl.into(), generics: generics.into(), @@ -435,7 +435,7 @@ impl From for Impl { } crate fn from_function_method(function: clean::Function, has_body: bool) -> Method { - let clean::Function { header, decl, generics, all_types: _, ret_types: _ } = function; + let clean::Function { header, decl, generics } = function; Method { decl: decl.into(), generics: generics.into(),