diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 08478a62b7d85..9a445c49774cd 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -2,8 +2,10 @@ use std::iter::once; use std::sync::Arc; +use std::vec; use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::smallvec::smallvec; use rustc_data_structures::thin_vec::{ThinVec, thin_vec}; use rustc_hir::def::{DefKind, MacroKinds, Res}; use rustc_hir::def_id::{DefId, DefIdSet, LocalDefId, LocalModDefId}; @@ -17,6 +19,7 @@ use rustc_span::symbol::{Symbol, sym}; use tracing::{debug, trace}; use super::{Item, extract_cfg_from_attrs}; +use crate::clean::paths::ItemPath; use crate::clean::{ self, Attributes, CfgInfo, ImplKind, ItemId, Type, clean_bound_vars, clean_generics, clean_impl_item, clean_middle_assoc_item, clean_middle_field, clean_middle_ty, @@ -234,7 +237,7 @@ pub(crate) fn load_attrs<'hir>(tcx: TyCtxt<'hir>, did: DefId) -> &'hir [hir::Att tcx.get_all_attrs(did) } -pub(crate) fn item_relative_path(tcx: TyCtxt<'_>, def_id: DefId) -> Vec { +pub(crate) fn item_relative_path(tcx: TyCtxt<'_>, def_id: DefId) -> ItemPath { tcx.def_path(def_id).data.into_iter().filter_map(|elem| elem.data.get_opt_name()).collect() } @@ -242,7 +245,7 @@ pub(crate) fn item_relative_path(tcx: TyCtxt<'_>, def_id: DefId) -> Vec /// /// In particular: we handle macro differently: if it's not a macro 2.0 oe a built-in macro, then /// it is generated at the top-level of the crate and its path will be `[crate_name, macro_name]`. -pub(crate) fn get_item_path(tcx: TyCtxt<'_>, def_id: DefId, kind: ItemType) -> Vec { +pub(crate) fn get_item_path(tcx: TyCtxt<'_>, def_id: DefId, kind: ItemType) -> ItemPath { let crate_name = tcx.crate_name(def_id.krate); let relative = item_relative_path(tcx, def_id); @@ -255,7 +258,7 @@ pub(crate) fn get_item_path(tcx: TyCtxt<'_>, def_id: DefId, kind: ItemType) -> V ) { once(crate_name).chain(relative).collect() } else { - vec![crate_name, *relative.last().expect("relative was empty")] + smallvec![crate_name, *relative.last().expect("relative was empty")].into() } } else { once(crate_name).chain(relative).collect() diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 7442ec99d90eb..8d251d2f7f8eb 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -25,6 +25,7 @@ mod auto_trait; mod blanket_impl; pub(crate) mod cfg; pub(crate) mod inline; +pub(crate) mod paths; mod render_macro_matchers; mod simplify; pub(crate) mod types; diff --git a/src/librustdoc/clean/paths.rs b/src/librustdoc/clean/paths.rs new file mode 100644 index 0000000000000..be8c9d38d7951 --- /dev/null +++ b/src/librustdoc/clean/paths.rs @@ -0,0 +1,60 @@ +use std::ops::{Deref, DerefMut}; +use std::slice; + +use rustc_data_structures::smallvec::{self, SmallVec}; +use rustc_span::Symbol; + +#[derive(Default, Debug, Clone, PartialEq, Eq, Hash)] +pub(crate) struct ItemPath(SmallVec<[Symbol; 4]>); + +impl From> for ItemPath { + fn from(value: SmallVec<[Symbol; 4]>) -> Self { + Self(value) + } +} + +impl From<&[Symbol]> for ItemPath { + fn from(value: &[Symbol]) -> Self { + SmallVec::from_slice(value).into() + } +} + +impl FromIterator for ItemPath { + fn from_iter>(iter: T) -> Self { + Self(FromIterator::from_iter(iter)) + } +} + +impl Deref for ItemPath { + type Target = SmallVec<[Symbol; 4]>; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for ItemPath { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +impl IntoIterator for ItemPath { + type Item = Symbol; + + type IntoIter = smallvec::IntoIter<[Symbol; 4]>; + + fn into_iter(self) -> Self::IntoIter { + self.0.into_iter() + } +} + +impl<'a> IntoIterator for &'a ItemPath { + type Item = &'a Symbol; + + type IntoIter = slice::Iter<'a, Symbol>; + + fn into_iter(self) -> Self::IntoIter { + self.0.iter() + } +} diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index fee783133133f..5aff103f214d5 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -1,6 +1,7 @@ use std::mem; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; +use rustc_data_structures::smallvec::smallvec; use rustc_hir::StabilityLevel; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet}; use rustc_metadata::creader::CStore; @@ -8,6 +9,7 @@ use rustc_middle::ty::{self, TyCtxt}; use rustc_span::Symbol; use tracing::debug; +use crate::clean::paths::ItemPath; use crate::clean::types::ExternalLocation; use crate::clean::{self, ExternalCrate, ItemId, PrimitiveType}; use crate::config::RenderOptions; @@ -42,11 +44,11 @@ pub(crate) struct Cache { /// URLs when a type is being linked to. External paths are not located in /// this map because the `External` type itself has all the information /// necessary. - pub(crate) paths: FxIndexMap, ItemType)>, + pub(crate) paths: FxIndexMap, /// Similar to `paths`, but only holds external paths. This is only used for /// generating explicit hyperlinks to other crates. - pub(crate) external_paths: FxIndexMap, ItemType)>, + pub(crate) external_paths: FxIndexMap, /// Maps local `DefId`s of exported types to fully qualified paths. /// Unlike 'paths', this mapping ignores any renames that occur @@ -58,7 +60,7 @@ pub(crate) struct Cache { /// to the path used if the corresponding type is inlined. By /// doing this, we can detect duplicate impls on a trait page, and only display /// the impl for the inlined type. - pub(crate) exact_paths: DefIdMap>, + pub(crate) exact_paths: DefIdMap, /// This map contains information about all known traits of this crate. /// Implementations of a crate should inherit the documentation of the @@ -98,7 +100,7 @@ pub(crate) struct Cache { pub(crate) masked_crates: FxHashSet, // Private fields only used when initially crawling a crate to build a cache - stack: Vec, + stack: ItemPath, parent_stack: Vec, stripped_mod: bool, @@ -193,7 +195,7 @@ impl Cache { render_options.extern_html_root_urls.get(name.as_str()).map(|u| &**u); e.location(extern_url, extern_url_takes_precedence, dst, tcx) }); - cx.cache.external_paths.insert(e.def_id(), (vec![name], ItemType::Module)); + cx.cache.external_paths.insert(e.def_id(), (smallvec![name].into(), ItemType::Module)); } // FIXME: avoid this clone (requires implementing Default manually) @@ -204,7 +206,7 @@ impl Cache { // If that restriction is ever lifted, this will have to include the relative paths instead. cx.cache .external_paths - .insert(def_id, (vec![crate_name, prim.as_sym()], ItemType::Primitive)); + .insert(def_id, (smallvec![crate_name, prim.as_sym()].into(), ItemType::Primitive)); } let (krate, mut impl_ids) = { @@ -572,7 +574,7 @@ fn add_item_to_search_index(tcx: TyCtxt<'_>, cache: &mut Cache, item: &clean::It if item_def_id.is_crate_root() || cache.stripped_mod { return; } - (None, &*cache.stack) + (None, &cache.stack[..]) } }; @@ -600,7 +602,7 @@ fn add_item_to_search_index(tcx: TyCtxt<'_>, cache: &mut Cache, item: &clean::It let index_item = IndexItem { defid: Some(defid), name, - module_path: parent_path.to_vec(), + module_path: parent_path.into(), parent: parent_did, parent_idx: None, trait_parent, diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 0b94d2bf1e641..50b847945c083 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -14,6 +14,7 @@ use itertools::{Either, Itertools}; use rustc_abi::ExternAbi; use rustc_ast::join_path_syms; use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::smallvec::smallvec; use rustc_hir as hir; use rustc_hir::def::{DefKind, MacroKinds}; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; @@ -25,6 +26,7 @@ use rustc_span::{Ident, Symbol}; use tracing::{debug, trace}; use super::url_parts_builder::UrlPartsBuilder; +use crate::clean::paths::ItemPath; use crate::clean::types::ExternalLocation; use crate::clean::utils::find_nearest_parent_module; use crate::clean::{self, ExternalCrate, PrimitiveType}; @@ -354,7 +356,7 @@ pub(crate) struct HrefInfo { /// Kind of the item (used to generate the `title` attribute). pub(crate) kind: ItemType, /// Rust path to the item (used to generate the `title` attribute). - pub(crate) rust_path: Vec, + pub(crate) rust_path: ItemPath, } /// This function is to get the external macro path because they are not in the cache used in @@ -451,7 +453,7 @@ fn generate_item_def_id_path( } } - let mut fqp = vec![crate_name]; + let mut fqp = ItemPath::from(smallvec![crate_name]); let shortty = if let Some(prim) = prim { fqp.push(prim.as_sym()); ItemType::Primitive diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index fd6d389542b99..038ae337a66fc 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -64,6 +64,7 @@ use tracing::{debug, info}; pub(crate) use self::context::*; pub(crate) use self::write_shared::*; +use crate::clean::paths::ItemPath; use crate::clean::{self, Defaultness, Item, ItemId, RenderedLink}; use crate::display::{Joined as _, MaybeDisplay as _}; use crate::error::Error; @@ -158,12 +159,12 @@ impl IndexItemInfo { pub(crate) struct IndexItem { pub(crate) defid: Option, pub(crate) name: Symbol, - pub(crate) module_path: Vec, + pub(crate) module_path: ItemPath, pub(crate) parent: Option, pub(crate) parent_idx: Option, pub(crate) trait_parent: Option, pub(crate) trait_parent_idx: Option, - pub(crate) exact_module_path: Option>, + pub(crate) exact_module_path: Option, pub(crate) impl_id: Option, pub(crate) info: IndexItemInfo, } diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index 6ee56cdd5a8a3..5f0a0feeca5e2 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -12,6 +12,7 @@ use ::serde::ser::{SerializeSeq, Serializer}; use ::serde::{Deserialize, Serialize}; use rustc_ast::join_path_syms; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; +use rustc_data_structures::smallvec::smallvec; use rustc_data_structures::thin_vec::ThinVec; use rustc_hir::def_id::{CrateNum, DefIndex, LOCAL_CRATE}; use rustc_hir::find_attr; @@ -22,6 +23,7 @@ use rustc_span::symbol::{Symbol, kw}; use stringdex::internals as stringdex_internals; use tracing::instrument; +use crate::clean::paths::ItemPath; use crate::clean::types::{Function, Generics, ItemId, Type, WherePredicate}; use crate::clean::{self, ExternalLocation, utils}; use crate::config::ShouldMerge; @@ -58,7 +60,7 @@ pub(crate) struct SerializedSearchIndex { generic_inverted_index: Vec>>, // generated in-memory backref cache #[serde(skip)] - crate_paths_index: FxHashMap<(ItemType, Vec), usize>, + crate_paths_index: FxHashMap<(ItemType, ItemPath), usize>, } impl SerializedSearchIndex { @@ -188,13 +190,13 @@ impl SerializedSearchIndex { // generic_inverted_index is not the same length as other columns, // because it's actually a completely different set of objects - let mut crate_paths_index: FxHashMap<(ItemType, Vec), usize> = FxHashMap::default(); + let mut crate_paths_index: FxHashMap<(ItemType, ItemPath), usize> = FxHashMap::default(); for (i, (name, path_data)) in names.iter().zip(path_data.iter()).enumerate() { if let Some(path_data) = path_data { let full_path = if path_data.module_path.is_empty() { - vec![Symbol::intern(name)] + smallvec![Symbol::intern(name)].into() } else { - let mut full_path = path_data.module_path.to_vec(); + let mut full_path = path_data.module_path.clone(); full_path.push(Symbol::intern(name)); full_path }; @@ -229,7 +231,7 @@ impl SerializedSearchIndex { if let Some(path_data) = &path_data && let name = Symbol::intern(&name) && let fqp = if path_data.module_path.is_empty() { - vec![name] + ItemPath::from(smallvec![name]) } else { let mut v = path_data.module_path.clone(); v.push(name); @@ -268,7 +270,7 @@ impl SerializedSearchIndex { .chain([Symbol::intern(&self.names[module_path_index]), name]) .collect() } else { - vec![name] + smallvec![name].into() }; // If a path with the same name already exists, but no entry does, // we can fill in the entry without having to allocate a new row ID. @@ -298,14 +300,14 @@ impl SerializedSearchIndex { fn get_id_by_module_path(&mut self, path: &[Symbol]) -> usize { let ty = if path.len() == 1 { ItemType::ExternCrate } else { ItemType::Module }; - match self.crate_paths_index.entry((ty, path.to_vec())) { + match self.crate_paths_index.entry((ty, path.into())) { Entry::Occupied(index) => *index.get(), Entry::Vacant(slot) => { slot.insert(self.path_data.len()); let (name, module_path) = path.split_last().unwrap(); self.push_path( name.as_str().to_string(), - PathData { ty, module_path: module_path.to_vec(), exact_module_path: None }, + PathData { ty, module_path: module_path.into(), exact_module_path: None }, ) } } @@ -978,8 +980,8 @@ impl<'de> Deserialize<'de> for EntryData { #[derive(Clone, Debug)] struct PathData { ty: ItemType, - module_path: Vec, - exact_module_path: Option>, + module_path: ItemPath, + exact_module_path: Option, } impl Serialize for PathData { @@ -1026,13 +1028,13 @@ impl<'de> Deserialize<'de> for PathData { Ok(PathData { ty, module_path: if module_path.is_empty() { - vec![] + ItemPath::default() } else { module_path.split("::").map(Symbol::intern).collect() }, exact_module_path: exact_module_path.map(|path| { if path.is_empty() { - vec![] + ItemPath::default() } else { path.split("::").map(Symbol::intern).collect() } @@ -1283,7 +1285,7 @@ pub(crate) fn build_index( search_index.push(IndexItem { defid: item.item_id.as_def_id(), name: item.name.unwrap(), - module_path: fqp[..fqp.len() - 1].to_vec(), + module_path: fqp[..fqp.len() - 1].into(), parent: Some(parent), parent_idx: None, trait_parent, @@ -1320,7 +1322,7 @@ pub(crate) fn build_index( let crate_doc = short_markdown_summary(&krate.module.doc_value(), &krate.module.link_names(cache)); let crate_idx = { - let crate_path = (ItemType::ExternCrate, vec![crate_name]); + let crate_path = (ItemType::ExternCrate, ItemPath::from(smallvec![crate_name])); match serialized_index.crate_paths_index.entry(crate_path) { Entry::Occupied(index) => { let index = *index.get(); @@ -1378,7 +1380,7 @@ pub(crate) fn build_index( crate_name.as_str().to_string(), Some(PathData { ty: ItemType::ExternCrate, - module_path: vec![], + module_path: ItemPath::default(), exact_module_path: None, }), Some(EntryData { @@ -1422,14 +1424,14 @@ pub(crate) fn build_index( name.as_str().to_string(), PathData { ty, - module_path: path.to_vec(), + module_path: path.into(), exact_module_path: if let Some(exact_path) = cache.exact_paths.get(&defid) && let Some((name2, exact_path)) = exact_path.split_last() && name == name2 { - Some(exact_path.to_vec()) + Some(exact_path.into()) } else { None }, @@ -1467,12 +1469,12 @@ pub(crate) fn build_index( && find_attr!(tcx, defid, MacroExport { .. }) { // `#[macro_export]` always exports to the crate root. - vec![tcx.crate_name(defid.krate)] + smallvec![tcx.crate_name(defid.krate)].into() } else { if fqp.len() < 2 { return None; } - fqp[..fqp.len() - 1].to_vec() + fqp[..fqp.len() - 1].into() }; if path == item.module_path { return None; @@ -1576,7 +1578,8 @@ pub(crate) fn build_index( used_in_function_signature: &mut BTreeSet, ) -> RenderTypeId { let pathid = serialized_index.names.len(); - let pathid = match serialized_index.crate_paths_index.entry((ty, path.to_vec())) { + let pathid = match serialized_index.crate_paths_index.entry((ty, ItemPath::from(path))) + { Entry::Occupied(entry) => { let id = *entry.get(); if serialized_index.type_data[id].as_mut().is_none() { @@ -1597,12 +1600,12 @@ pub(crate) fn build_index( name.to_string(), PathData { ty, - module_path: path.to_vec(), + module_path: path.into(), exact_module_path: if let Some(exact_path) = exact_path && let Some((name2, exact_path)) = exact_path.split_last() && name == name2 { - Some(exact_path.to_vec()) + Some(exact_path.into()) } else { None }, diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index d0b02c20644fe..962ff0d211760 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -18,6 +18,7 @@ use rustc_span::def_id::{CRATE_DEF_ID, LOCAL_CRATE}; use rustc_span::symbol::{Symbol, kw}; use tracing::debug; +use crate::clean::paths::ItemPath; use crate::clean::reexport_chain; use crate::clean::utils::{inherits_doc_hidden, should_ignore_res}; use crate::core; @@ -113,7 +114,7 @@ impl Module<'_> { } // FIXME: Should this be replaced with tcx.def_path_str? -fn def_id_to_path(tcx: TyCtxt<'_>, did: DefId) -> Vec { +fn def_id_to_path(tcx: TyCtxt<'_>, did: DefId) -> ItemPath { let crate_name = tcx.crate_name(did.krate); let relative = tcx.def_path(did).data.into_iter().filter_map(|elem| elem.data.get_opt_name()); std::iter::once(crate_name).chain(relative).collect() @@ -125,7 +126,7 @@ pub(crate) struct RustdocVisitor<'a, 'tcx> { inlining: bool, /// Are the current module and all of its parents public? inside_public_path: bool, - exact_paths: DefIdMap>, + exact_paths: DefIdMap, modules: Vec>, is_importable_from_parent: bool, inside_body: bool,