From b9ed8784b3f6ffd16d562198cfef5f66a0253a18 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Mon, 2 May 2022 14:51:45 -0700 Subject: [PATCH 1/4] rustdoc: include impl generics / self in search index --- src/librustdoc/clean/types.rs | 6 ++ src/librustdoc/formats/cache.rs | 47 +++++++++++-- src/librustdoc/html/render/search_index.rs | 76 ++++++++++++++++++---- src/test/rustdoc-js/generics-impl.js | 57 ++++++++++++++++ src/test/rustdoc-js/generics-impl.rs | 35 ++++++++++ 5 files changed, 204 insertions(+), 17 deletions(-) create mode 100644 src/test/rustdoc-js/generics-impl.js create mode 100644 src/test/rustdoc-js/generics-impl.rs diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index e10c61901d0..23bb020716d 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1410,6 +1410,12 @@ pub(crate) struct Generics { pub(crate) where_predicates: Vec, } +impl Generics { + pub(crate) fn is_empty(&self) -> bool { + self.params.is_empty() && self.where_predicates.is_empty() + } +} + #[derive(Clone, Debug)] pub(crate) struct Function { pub(crate) decl: FnDecl, diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index 09aa042b1d0..813e6fa24ec 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -95,7 +95,9 @@ pub(crate) struct Cache { // Private fields only used when initially crawling a crate to build a cache stack: Vec, parent_stack: Vec, + impl_generics_stack: Vec<(clean::Type, clean::Generics)>, parent_is_trait_impl: bool, + parent_is_blanket_or_auto_impl: bool, stripped_mod: bool, pub(crate) search_index: Vec, @@ -105,7 +107,8 @@ pub(crate) struct Cache { // then the fully qualified name of the structure isn't presented in `paths` // yet when its implementation methods are being indexed. Caches such methods // and their parent id here and indexes them at the end of crate parsing. - pub(crate) orphan_impl_items: Vec<(DefId, clean::Item)>, + pub(crate) orphan_impl_items: + Vec<(DefId, clean::Item, Option<(clean::Type, clean::Generics)>, bool)>, // Similarly to `orphan_impl_items`, sometimes trait impls are picked up // even though the trait itself is not exported. This can happen if a trait @@ -315,7 +318,13 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> { desc, parent, parent_idx: None, - search_type: get_function_type_for_search(&item, self.tcx, self.cache), + search_type: get_function_type_for_search( + &item, + self.tcx, + self.cache.impl_generics_stack.last(), + self.cache.parent_is_blanket_or_auto_impl, + self.cache, + ), aliases: item.attrs.get_doc_aliases(), }); } @@ -323,7 +332,12 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> { (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.cache.orphan_impl_items.push((parent, item.clone())); + self.cache.orphan_impl_items.push(( + parent, + item.clone(), + self.cache.impl_generics_stack.last().cloned(), + self.cache.parent_is_blanket_or_auto_impl, + )); } _ => {} } @@ -440,9 +454,34 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> { _ => false, }; + // When recursing into an impl item, make the generics context visible + // to the child items. + let item = { + let mut item = item; + let mut old_parent_is_blanket_or_auto_impl = false; + if let clean::Item { kind: box clean::ImplItem(ref mut i), .. } = item { + old_parent_is_blanket_or_auto_impl = mem::replace( + &mut self.cache.parent_is_blanket_or_auto_impl, + !matches!(i.kind, clean::ImplKind::Normal), + ); + self.cache.impl_generics_stack.push(( + mem::replace(&mut i.for_, clean::Type::Infer), + mem::replace( + &mut i.generics, + clean::Generics { params: Vec::new(), where_predicates: Vec::new() }, + ), + )); + } + let mut item = self.fold_item_recur(item); + if let clean::Item { kind: box clean::ImplItem(ref mut i), .. } = item { + self.cache.parent_is_blanket_or_auto_impl = old_parent_is_blanket_or_auto_impl; + (i.for_, i.generics) = self.cache.impl_generics_stack.pop().expect("pushed above"); + } + item + }; + // Once we've recursively found all the generics, hoard off all the // implementations elsewhere. - let item = self.fold_item_recur(item); let ret = if let clean::Item { kind: box clean::ImplItem(ref i), .. } = item { // Figure out the id of this impl. This may map to a // primitive rather than always to a struct/enum. diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index 3daef3dbb79..323c0e89f29 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -25,7 +25,7 @@ pub(crate) fn build_index<'tcx>( // 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 { + for &(did, ref item, ref impl_generics, from_blanket_or_auto_impl) in &cache.orphan_impl_items { if let Some(&(ref fqp, _)) = cache.paths.get(&did) { let desc = item .doc_value() @@ -37,7 +37,13 @@ pub(crate) fn build_index<'tcx>( desc, parent: Some(did), parent_idx: None, - search_type: get_function_type_for_search(item, tcx, cache), + search_type: get_function_type_for_search( + item, + tcx, + impl_generics.as_ref(), + from_blanket_or_auto_impl, + cache, + ), aliases: item.attrs.get_doc_aliases(), }); } @@ -192,12 +198,18 @@ pub(crate) fn build_index<'tcx>( pub(crate) fn get_function_type_for_search<'tcx>( item: &clean::Item, tcx: TyCtxt<'tcx>, + impl_generics: Option<&(clean::Type, clean::Generics)>, + from_blanket_or_auto_impl: bool, cache: &Cache, ) -> Option { + if from_blanket_or_auto_impl { + return None; + } + let (mut inputs, mut output) = match *item.kind { - clean::FunctionItem(ref f) => get_fn_inputs_and_outputs(f, tcx, cache), - clean::MethodItem(ref m, _) => get_fn_inputs_and_outputs(m, tcx, cache), - clean::TyMethodItem(ref m) => get_fn_inputs_and_outputs(m, tcx, cache), + clean::FunctionItem(ref f) => get_fn_inputs_and_outputs(f, tcx, impl_generics, cache), + clean::MethodItem(ref m, _) => get_fn_inputs_and_outputs(m, tcx, impl_generics, cache), + clean::TyMethodItem(ref m) => get_fn_inputs_and_outputs(m, tcx, impl_generics, cache), _ => return None, }; @@ -247,9 +259,10 @@ fn get_index_type_name(clean_type: &clean::Type) -> Option { /// Important note: It goes through generics recursively. So if you have /// `T: Option>`, it'll go into `Option` and then into `Result`. #[instrument(level = "trace", skip(tcx, res, cache))] -fn add_generics_and_bounds_as_types<'tcx>( +fn add_generics_and_bounds_as_types<'tcx, 'a>( + self_: Option<&'a Type>, generics: &Generics, - arg: &Type, + arg: &'a Type, tcx: TyCtxt<'tcx>, recurse: usize, res: &mut Vec, @@ -334,6 +347,17 @@ fn add_generics_and_bounds_as_types<'tcx>( return; } + // First, check if it's "Self". + let arg = if let Some(self_) = self_ { + match &*arg { + Type::BorrowedRef { type_, .. } if type_.is_self_type() => self_, + type_ if type_.is_self_type() => self_, + arg => arg, + } + } else { + arg + }; + // If this argument is a type parameter and not a trait bound or a type, we need to look // for its bounds. if let Type::Generic(arg_s) = *arg { @@ -350,6 +374,7 @@ fn add_generics_and_bounds_as_types<'tcx>( match ¶m_def.kind { clean::GenericParamDefKind::Type { default: Some(ty), .. } => { add_generics_and_bounds_as_types( + self_, generics, ty, tcx, @@ -372,6 +397,7 @@ fn add_generics_and_bounds_as_types<'tcx>( if let Some(path) = bound.get_trait_path() { let ty = Type::Path { path }; add_generics_and_bounds_as_types( + self_, generics, &ty, tcx, @@ -393,6 +419,7 @@ fn add_generics_and_bounds_as_types<'tcx>( if let Some(arg_generics) = arg.generics() { for gen in arg_generics.iter() { add_generics_and_bounds_as_types( + self_, generics, gen, tcx, @@ -413,18 +440,33 @@ fn add_generics_and_bounds_as_types<'tcx>( fn get_fn_inputs_and_outputs<'tcx>( func: &Function, tcx: TyCtxt<'tcx>, + impl_generics: Option<&(clean::Type, clean::Generics)>, cache: &Cache, ) -> (Vec, Vec) { let decl = &func.decl; - let generics = &func.generics; + + let combined_generics; + let (self_, generics) = if let Some(&(ref impl_self, ref impl_generics)) = impl_generics { + match (impl_generics.is_empty(), func.generics.is_empty()) { + (true, _) => (Some(impl_self), &func.generics), + (_, true) => (Some(impl_self), impl_generics), + (false, false) => { + let mut params = func.generics.params.clone(); + params.extend(impl_generics.params.clone()); + let mut where_predicates = func.generics.where_predicates.clone(); + where_predicates.extend(impl_generics.where_predicates.clone()); + combined_generics = clean::Generics { params, where_predicates }; + (Some(impl_self), &combined_generics) + } + } + } else { + (None, &func.generics) + }; let mut all_types = Vec::new(); for arg in decl.inputs.values.iter() { - if arg.type_.is_self_type() { - continue; - } let mut args = Vec::new(); - add_generics_and_bounds_as_types(generics, &arg.type_, tcx, 0, &mut args, cache); + add_generics_and_bounds_as_types(self_, generics, &arg.type_, tcx, 0, &mut args, cache); if !args.is_empty() { all_types.extend(args); } else { @@ -437,7 +479,15 @@ fn get_fn_inputs_and_outputs<'tcx>( let mut ret_types = Vec::new(); match decl.output { FnRetTy::Return(ref return_type) => { - add_generics_and_bounds_as_types(generics, return_type, tcx, 0, &mut ret_types, cache); + add_generics_and_bounds_as_types( + self_, + generics, + return_type, + tcx, + 0, + &mut ret_types, + cache, + ); if ret_types.is_empty() { if let Some(kind) = return_type.def_id(cache).map(|did| tcx.def_kind(did).into()) { ret_types.push(TypeWithKind::from((get_index_type(return_type, vec![]), kind))); diff --git a/src/test/rustdoc-js/generics-impl.js b/src/test/rustdoc-js/generics-impl.js new file mode 100644 index 00000000000..20bb7be6ba0 --- /dev/null +++ b/src/test/rustdoc-js/generics-impl.js @@ -0,0 +1,57 @@ +// exact-check + +const QUERY = [ + 'Aaaaaaa -> u32', + 'Aaaaaaa -> bool', + 'Aaaaaaa -> usize', + 'Read -> u64', + 'bool -> u64', + 'Ddddddd -> u64', + '-> Ddddddd' +]; + +const EXPECTED = [ + { + // Aaaaaaa -> u32 + 'others': [ + { 'path': 'generics_impl::Aaaaaaa', 'name': 'bbbbbbb' }, + ], + }, + { + // Aaaaaaa -> bool + 'others': [ + { 'path': 'generics_impl::Aaaaaaa', 'name': 'ccccccc' }, + ], + }, + { + // Aaaaaaa -> usize + 'others': [ + { 'path': 'generics_impl::Aaaaaaa', 'name': 'read' }, + ], + }, + { + // Read -> u64 + 'others': [ + { 'path': 'generics_impl::Ddddddd', 'name': 'eeeeeee' }, + { 'path': 'generics_impl::Ddddddd', 'name': 'ggggggg' }, + ], + }, + { + // bool -> u64 + 'others': [ + { 'path': 'generics_impl::Ddddddd', 'name': 'fffffff' }, + ], + }, + { + // Ddddddd -> u64 + 'others': [ + { 'path': 'generics_impl::Ddddddd', 'name': 'ggggggg' }, + ], + }, + { + // -> "Ddddddd" + 'returned': [ + { 'path': 'generics_impl::Ddddddd', 'name': 'hhhhhhh' }, + ], + }, +]; diff --git a/src/test/rustdoc-js/generics-impl.rs b/src/test/rustdoc-js/generics-impl.rs new file mode 100644 index 00000000000..696218021d5 --- /dev/null +++ b/src/test/rustdoc-js/generics-impl.rs @@ -0,0 +1,35 @@ +use std::io::{Result as IoResult, Read}; + +pub struct Aaaaaaa; + +impl Aaaaaaa { + pub fn bbbbbbb(self) -> u32 { + 1 + } + pub fn ccccccc(&self) -> bool { + true + } +} + +impl Read for Aaaaaaa { + fn read(&mut self, out: &mut [u8]) -> IoResult { + Ok(out.len()) + } +} + +pub struct Ddddddd(T); + +impl Ddddddd { + pub fn eeeeeee(_: T) -> u64 { + 1 + } + pub fn fffffff(_: bool) -> u64 { + 1 + } + pub fn ggggggg(self) -> u64 { + 1 + } + pub fn hhhhhhh() -> Self where T: Default { + Ddddddd(T::default()) + } +} From c516ffa8e531290687b60bb8023fbccd3abe43ad Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Mon, 23 May 2022 12:06:16 -0700 Subject: [PATCH 2/4] Adjust test case to account for 6c8a2d4 --- src/test/rustdoc-js/generics-impl.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/rustdoc-js/generics-impl.js b/src/test/rustdoc-js/generics-impl.js index 20bb7be6ba0..bb6e0041db5 100644 --- a/src/test/rustdoc-js/generics-impl.js +++ b/src/test/rustdoc-js/generics-impl.js @@ -49,8 +49,8 @@ const EXPECTED = [ ], }, { - // -> "Ddddddd" - 'returned': [ + // -> Ddddddd + 'others': [ { 'path': 'generics_impl::Ddddddd', 'name': 'hhhhhhh' }, ], }, From 767719cc304e9b025875aea073f66ce248ae2616 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Thu, 26 May 2022 14:01:08 -0700 Subject: [PATCH 3/4] rustdoc: factor orphan impl items into an actual struct --- src/librustdoc/formats/cache.rs | 20 +++++++++++++------- src/librustdoc/html/render/search_index.rs | 12 +++++++----- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index 813e6fa24ec..9b2756b1d5c 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -107,8 +107,7 @@ pub(crate) struct Cache { // then the fully qualified name of the structure isn't presented in `paths` // yet when its implementation methods are being indexed. Caches such methods // and their parent id here and indexes them at the end of crate parsing. - pub(crate) orphan_impl_items: - Vec<(DefId, clean::Item, Option<(clean::Type, clean::Generics)>, bool)>, + pub(crate) orphan_impl_items: Vec, // Similarly to `orphan_impl_items`, sometimes trait impls are picked up // even though the trait itself is not exported. This can happen if a trait @@ -332,12 +331,12 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> { (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.cache.orphan_impl_items.push(( + self.cache.orphan_impl_items.push(OrphanImplItem { parent, - item.clone(), - self.cache.impl_generics_stack.last().cloned(), - self.cache.parent_is_blanket_or_auto_impl, - )); + item: item.clone(), + impl_generics: self.cache.impl_generics_stack.last().cloned(), + parent_is_blanket_or_auto_impl: self.cache.parent_is_blanket_or_auto_impl, + }); } _ => {} } @@ -554,3 +553,10 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> { ret } } + +pub(crate) struct OrphanImplItem { + pub(crate) parent: DefId, + pub(crate) item: clean::Item, + pub(crate) impl_generics: Option<(clean::Type, clean::Generics)>, + pub(crate) parent_is_blanket_or_auto_impl: bool, +} diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index 323c0e89f29..dcdf18978e3 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -8,7 +8,7 @@ use serde::ser::{Serialize, SerializeStruct, Serializer}; use crate::clean; use crate::clean::types::{FnRetTy, Function, GenericBound, Generics, Type, WherePredicate}; -use crate::formats::cache::Cache; +use crate::formats::cache::{Cache, OrphanImplItem}; use crate::formats::item_type::ItemType; use crate::html::format::join_with_double_colon; use crate::html::markdown::short_markdown_summary; @@ -25,8 +25,10 @@ pub(crate) fn build_index<'tcx>( // Attach all orphan items to the type's definition if the type // has since been learned. - for &(did, ref item, ref impl_generics, from_blanket_or_auto_impl) in &cache.orphan_impl_items { - if let Some(&(ref fqp, _)) = cache.paths.get(&did) { + for &OrphanImplItem { parent, ref item, ref impl_generics, parent_is_blanket_or_auto_impl } in + &cache.orphan_impl_items + { + if let Some(&(ref fqp, _)) = cache.paths.get(&parent) { let desc = item .doc_value() .map_or_else(String::new, |s| short_markdown_summary(&s, &item.link_names(cache))); @@ -35,13 +37,13 @@ pub(crate) fn build_index<'tcx>( name: item.name.unwrap().to_string(), path: join_with_double_colon(&fqp[..fqp.len() - 1]), desc, - parent: Some(did), + parent: Some(parent), parent_idx: None, search_type: get_function_type_for_search( item, tcx, impl_generics.as_ref(), - from_blanket_or_auto_impl, + parent_is_blanket_or_auto_impl, cache, ), aliases: item.attrs.get_doc_aliases(), From 718269aab8adf85c9ceacf91421ec135d97a3bfa Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Fri, 27 May 2022 12:23:29 -0700 Subject: [PATCH 4/4] cleanup librustdoc by making parent stack store items --- src/librustdoc/formats/cache.rs | 157 +++++++++++---------- src/librustdoc/html/render/search_index.rs | 17 +-- 2 files changed, 84 insertions(+), 90 deletions(-) diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index 9b2756b1d5c..d7276a427c4 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -94,10 +94,7 @@ pub(crate) struct Cache { // Private fields only used when initially crawling a crate to build a cache stack: Vec, - parent_stack: Vec, - impl_generics_stack: Vec<(clean::Type, clean::Generics)>, - parent_is_trait_impl: bool, - parent_is_blanket_or_auto_impl: bool, + parent_stack: Vec, stripped_mod: bool, pub(crate) search_index: Vec, @@ -263,7 +260,11 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> { let (parent, is_inherent_impl_item) = match *item.kind { clean::StrippedItem(..) => ((None, None), false), clean::AssocConstItem(..) | clean::AssocTypeItem(..) - if self.cache.parent_is_trait_impl => + if self + .cache + .parent_stack + .last() + .map_or(false, |parent| parent.is_trait_impl()) => { // skip associated items in trait impls ((None, None), false) @@ -274,7 +275,14 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> { | clean::StructFieldItem(..) | clean::VariantItem(..) => ( ( - Some(*self.cache.parent_stack.last().expect("parent_stack is empty")), + Some( + self.cache + .parent_stack + .last() + .expect("parent_stack is empty") + .item_id() + .expect_def_id(), + ), Some(&self.cache.stack[..self.cache.stack.len() - 1]), ), false, @@ -284,8 +292,11 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> { ((None, None), false) } else { let last = self.cache.parent_stack.last().expect("parent_stack is empty 2"); - let did = *last; - let path = match self.cache.paths.get(&did) { + let did = match &*last { + ParentStackItem::Impl { for_, .. } => for_.def_id(&self.cache), + ParentStackItem::Type(item_id) => item_id.as_def_id(), + }; + let path = match did.and_then(|did| 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 @@ -293,7 +304,7 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> { Some(&(ref fqp, _)) => Some(&fqp[..fqp.len() - 1]), None => None, }; - ((Some(*last), path), true) + ((did, path), true) } } _ => ((None, Some(&*self.cache.stack)), false), @@ -320,8 +331,7 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> { search_type: get_function_type_for_search( &item, self.tcx, - self.cache.impl_generics_stack.last(), - self.cache.parent_is_blanket_or_auto_impl, + clean_impl_generics(self.cache.parent_stack.last()).as_ref(), self.cache, ), aliases: item.attrs.get_doc_aliases(), @@ -331,11 +341,11 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> { (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. + let impl_generics = clean_impl_generics(self.cache.parent_stack.last()); self.cache.orphan_impl_items.push(OrphanImplItem { parent, item: item.clone(), - impl_generics: self.cache.impl_generics_stack.last().cloned(), - parent_is_blanket_or_auto_impl: self.cache.parent_is_blanket_or_auto_impl, + impl_generics, }); } _ => {} @@ -411,72 +421,19 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> { } } - // Maintain the parent stack - let orig_parent_is_trait_impl = self.cache.parent_is_trait_impl; - let parent_pushed = match *item.kind { + // Maintain the parent stack. + let (item, parent_pushed) = match *item.kind { clean::TraitItem(..) | clean::EnumItem(..) | clean::ForeignTypeItem | clean::StructItem(..) | clean::UnionItem(..) - | clean::VariantItem(..) => { - self.cache.parent_stack.push(item.item_id.expect_def_id()); - self.cache.parent_is_trait_impl = false; - true + | clean::VariantItem(..) + | clean::ImplItem(..) => { + self.cache.parent_stack.push(ParentStackItem::new(&item)); + (self.fold_item_recur(item), true) } - clean::ImplItem(ref i) => { - self.cache.parent_is_trait_impl = i.trait_.is_some(); - match i.for_ { - clean::Type::Path { ref path } => { - self.cache.parent_stack.push(path.def_id()); - true - } - clean::DynTrait(ref bounds, _) - | clean::BorrowedRef { type_: box clean::DynTrait(ref bounds, _), .. } => { - self.cache.parent_stack.push(bounds[0].trait_.def_id()); - true - } - ref t => { - let prim_did = t - .primitive_type() - .and_then(|t| self.cache.primitive_locations.get(&t).cloned()); - match prim_did { - Some(did) => { - self.cache.parent_stack.push(did); - true - } - None => false, - } - } - } - } - _ => false, - }; - - // When recursing into an impl item, make the generics context visible - // to the child items. - let item = { - let mut item = item; - let mut old_parent_is_blanket_or_auto_impl = false; - if let clean::Item { kind: box clean::ImplItem(ref mut i), .. } = item { - old_parent_is_blanket_or_auto_impl = mem::replace( - &mut self.cache.parent_is_blanket_or_auto_impl, - !matches!(i.kind, clean::ImplKind::Normal), - ); - self.cache.impl_generics_stack.push(( - mem::replace(&mut i.for_, clean::Type::Infer), - mem::replace( - &mut i.generics, - clean::Generics { params: Vec::new(), where_predicates: Vec::new() }, - ), - )); - } - let mut item = self.fold_item_recur(item); - if let clean::Item { kind: box clean::ImplItem(ref mut i), .. } = item { - self.cache.parent_is_blanket_or_auto_impl = old_parent_is_blanket_or_auto_impl; - (i.for_, i.generics) = self.cache.impl_generics_stack.pop().expect("pushed above"); - } - item + _ => (self.fold_item_recur(item), false), }; // Once we've recursively found all the generics, hoard off all the @@ -549,7 +506,6 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> { self.cache.parent_stack.pop().expect("parent stack already empty"); } self.cache.stripped_mod = orig_stripped_mod; - self.cache.parent_is_trait_impl = orig_parent_is_trait_impl; ret } } @@ -558,5 +514,56 @@ pub(crate) struct OrphanImplItem { pub(crate) parent: DefId, pub(crate) item: clean::Item, pub(crate) impl_generics: Option<(clean::Type, clean::Generics)>, - pub(crate) parent_is_blanket_or_auto_impl: bool, +} + +/// Information about trait and type parents is tracked while traversing the item tree to build +/// the cache. +/// +/// We don't just store `Item` in there, because `Item` contains the list of children being +/// traversed and it would be wasteful to clone all that. We also need the item id, so just +/// storing `ItemKind` won't work, either. +enum ParentStackItem { + Impl { + for_: clean::Type, + trait_: Option, + generics: clean::Generics, + kind: clean::ImplKind, + item_id: ItemId, + }, + Type(ItemId), +} + +impl ParentStackItem { + fn new(item: &clean::Item) -> Self { + match &*item.kind { + clean::ItemKind::ImplItem(clean::Impl { for_, trait_, generics, kind, .. }) => { + ParentStackItem::Impl { + for_: for_.clone(), + trait_: trait_.clone(), + generics: generics.clone(), + kind: kind.clone(), + item_id: item.item_id, + } + } + _ => ParentStackItem::Type(item.item_id), + } + } + fn is_trait_impl(&self) -> bool { + matches!(self, ParentStackItem::Impl { trait_: Some(..), .. }) + } + fn item_id(&self) -> ItemId { + match self { + ParentStackItem::Impl { item_id, .. } => *item_id, + ParentStackItem::Type(item_id) => *item_id, + } + } +} + +fn clean_impl_generics(item: Option<&ParentStackItem>) -> Option<(clean::Type, clean::Generics)> { + if let Some(ParentStackItem::Impl { for_, generics, kind: clean::ImplKind::Normal, .. }) = item + { + Some((for_.clone(), generics.clone())) + } else { + None + } } diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index dcdf18978e3..25c70f0808c 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -25,9 +25,7 @@ pub(crate) fn build_index<'tcx>( // Attach all orphan items to the type's definition if the type // has since been learned. - for &OrphanImplItem { parent, ref item, ref impl_generics, parent_is_blanket_or_auto_impl } in - &cache.orphan_impl_items - { + for &OrphanImplItem { parent, ref item, ref impl_generics } in &cache.orphan_impl_items { if let Some(&(ref fqp, _)) = cache.paths.get(&parent) { let desc = item .doc_value() @@ -39,13 +37,7 @@ pub(crate) fn build_index<'tcx>( desc, parent: Some(parent), parent_idx: None, - search_type: get_function_type_for_search( - item, - tcx, - impl_generics.as_ref(), - parent_is_blanket_or_auto_impl, - cache, - ), + search_type: get_function_type_for_search(item, tcx, impl_generics.as_ref(), cache), aliases: item.attrs.get_doc_aliases(), }); } @@ -201,13 +193,8 @@ pub(crate) fn get_function_type_for_search<'tcx>( item: &clean::Item, tcx: TyCtxt<'tcx>, impl_generics: Option<&(clean::Type, clean::Generics)>, - from_blanket_or_auto_impl: bool, cache: &Cache, ) -> Option { - if from_blanket_or_auto_impl { - return None; - } - let (mut inputs, mut output) = match *item.kind { clean::FunctionItem(ref f) => get_fn_inputs_and_outputs(f, tcx, impl_generics, cache), clean::MethodItem(ref m, _) => get_fn_inputs_and_outputs(m, tcx, impl_generics, cache),