diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index d928b41cad49a..2b1a1d4a600d6 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -39,7 +39,6 @@ use crate::clean::Clean; use crate::core::DocContext; use crate::formats::cache::Cache; use crate::formats::item_type::ItemType; -use crate::html::render::cache::ExternalLocation; use crate::html::render::Context; use crate::passes::collect_intra_doc_links::UrlFragment; @@ -339,6 +338,16 @@ impl ExternalCrate { } } +/// Indicates where an external crate can be found. +crate enum ExternalLocation { + /// Remote URL root of the external crate + Remote(String), + /// This external crate can be found in the local doc/ folder + Local, + /// The external crate could not be found. + Unknown, +} + /// Anything with a source location and set of attributes and, optionally, a /// name. That is, anything that can be documented. This doesn't correspond /// directly to the AST's concept of an item; it's a strict superset. diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index 5813062ceab77..6b9ccd37cfb37 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -6,13 +6,13 @@ use rustc_middle::middle::privacy::AccessLevels; use rustc_middle::ty::TyCtxt; use rustc_span::symbol::sym; -use crate::clean::{self, ExternalCrate, ItemId, PrimitiveType}; +use crate::clean::{self, types::ExternalLocation, ExternalCrate, ItemId, PrimitiveType}; use crate::core::DocContext; use crate::fold::DocFolder; use crate::formats::item_type::ItemType; use crate::formats::Impl; use crate::html::markdown::short_markdown_summary; -use crate::html::render::cache::{get_index_search_type, ExternalLocation}; +use crate::html::render::search_index::get_function_type_for_search; use crate::html::render::IndexItem; /// This cache is used to store information about the [`clean::Crate`] being @@ -303,7 +303,7 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> { desc, parent, parent_idx: None, - search_type: get_index_search_type(&item, self.tcx, self.cache), + search_type: get_function_type_for_search(&item, self.tcx), aliases: item.attrs.get_doc_aliases(), }); } diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index e4c612aaab96e..3a7c7186877e2 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -21,10 +21,12 @@ use rustc_middle::ty::TyCtxt; use rustc_span::def_id::CRATE_DEF_INDEX; use rustc_target::spec::abi::Abi; -use crate::clean::{self, utils::find_nearest_parent_module, ExternalCrate, ItemId, PrimitiveType}; +use crate::clean::{ + self, types::ExternalLocation, utils::find_nearest_parent_module, ExternalCrate, ItemId, + PrimitiveType, +}; use crate::formats::item_type::ItemType; use crate::html::escape::Escape; -use crate::html::render::cache::ExternalLocation; use crate::html::render::Context; use super::url_parts_builder::UrlPartsBuilder; diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index 45a436c448710..534a542d58ed0 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -13,8 +13,8 @@ use rustc_span::edition::Edition; use rustc_span::source_map::FileName; use rustc_span::symbol::sym; -use super::cache::{build_index, ExternalLocation}; use super::print_item::{full_path, item_path, print_item}; +use super::search_index::build_index; use super::templates; use super::write_shared::write_shared; use super::{ @@ -22,7 +22,7 @@ use super::{ BASIC_KEYWORDS, }; -use crate::clean::{self, ExternalCrate}; +use crate::clean::{self, types::ExternalLocation, ExternalCrate}; use crate::config::RenderOptions; use crate::docfs::{DocFS, PathError}; use crate::error::Error; diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index eb606178d244d..3e7711181f730 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -23,7 +23,7 @@ //! These threads are not parallelized (they haven't been a bottleneck yet), and //! both occur before the crate is rendered. -crate mod cache; +crate mod search_index; #[cfg(test)] mod tests; diff --git a/src/librustdoc/html/render/cache.rs b/src/librustdoc/html/render/search_index.rs similarity index 88% rename from src/librustdoc/html/render/cache.rs rename to src/librustdoc/html/render/search_index.rs index 631eacc961828..0fbe090f2190a 100644 --- a/src/librustdoc/html/render/cache.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -7,22 +7,12 @@ use rustc_span::symbol::Symbol; use serde::ser::{Serialize, SerializeStruct, Serializer}; use crate::clean; -use crate::clean::types::{FnDecl, FnRetTy, GenericBound, Generics, Type, WherePredicate}; +use crate::clean::types::{FnRetTy, Function, GenericBound, Generics, Type, WherePredicate}; use crate::formats::cache::Cache; use crate::formats::item_type::ItemType; use crate::html::markdown::short_markdown_summary; use crate::html::render::{IndexItem, IndexItemFunctionType, RenderType, TypeWithKind}; -/// Indicates where an external crate can be found. -crate enum ExternalLocation { - /// Remote URL root of the external crate - Remote(String), - /// This external crate can be found in the local doc/ folder - Local, - /// The external crate could not be found. - Unknown, -} - /// Builds the search index from the collected metadata crate fn build_index<'tcx>(krate: &clean::Crate, cache: &mut Cache, tcx: TyCtxt<'tcx>) -> String { let mut defid_to_pathid = FxHashMap::default(); @@ -42,7 +32,7 @@ crate fn build_index<'tcx>(krate: &clean::Crate, cache: &mut Cache, tcx: TyCtxt< desc, parent: Some(did), parent_idx: None, - search_type: get_index_search_type(item, tcx, cache), + search_type: get_function_type_for_search(item, tcx), aliases: item.attrs.get_doc_aliases(), }); } @@ -191,15 +181,14 @@ crate fn build_index<'tcx>(krate: &clean::Crate, cache: &mut Cache, tcx: TyCtxt< ) } -crate fn get_index_search_type<'tcx>( +crate fn get_function_type_for_search<'tcx>( item: &clean::Item, tcx: TyCtxt<'tcx>, - cache: &Cache, ) -> Option { let (mut inputs, mut output) = match *item.kind { - clean::FunctionItem(ref f) => get_all_types(&f.generics, &f.decl, tcx, cache), - clean::MethodItem(ref m, _) => get_all_types(&m.generics, &m.decl, tcx, cache), - clean::TyMethodItem(ref m) => get_all_types(&m.generics, &m.decl, tcx, cache), + clean::FunctionItem(ref f) => get_fn_inputs_and_outputs(f, tcx), + clean::MethodItem(ref m, _) => get_fn_inputs_and_outputs(m, tcx), + clean::TyMethodItem(ref m) => get_fn_inputs_and_outputs(m, tcx), _ => return None, }; @@ -211,12 +200,12 @@ crate fn get_index_search_type<'tcx>( fn get_index_type(clean_type: &clean::Type, generics: Vec) -> RenderType { RenderType { - name: get_index_type_name(clean_type, true).map(|s| s.as_str().to_ascii_lowercase()), + name: get_index_type_name(clean_type).map(|s| s.as_str().to_ascii_lowercase()), generics: if generics.is_empty() { None } else { Some(generics) }, } } -fn get_index_type_name(clean_type: &clean::Type, accept_generic: bool) -> Option { +fn get_index_type_name(clean_type: &clean::Type) -> Option { match *clean_type { clean::Type::Path { ref path, .. } => { let path_segment = path.segments.last().unwrap(); @@ -226,11 +215,10 @@ fn get_index_type_name(clean_type: &clean::Type, accept_generic: bool) -> Option let path = &bounds[0].trait_; Some(path.segments.last().unwrap().name) } - clean::Generic(s) if accept_generic => Some(s), + clean::Generic(s) => Some(s), clean::Primitive(ref p) => Some(p.as_sym()), - clean::BorrowedRef { ref type_, .. } => get_index_type_name(type_, accept_generic), - clean::Generic(_) - | clean::BareFunction(_) + clean::BorrowedRef { ref type_, .. } => get_index_type_name(type_), + clean::BareFunction(_) | clean::Tuple(_) | clean::Slice(_) | clean::Array(_, _) @@ -248,20 +236,19 @@ fn get_index_type_name(clean_type: &clean::Type, accept_generic: bool) -> Option /// /// Important note: It goes through generics recursively. So if you have /// `T: Option>`, it'll go into `Option` and then into `Result`. -crate fn get_real_types<'tcx>( +#[instrument(level = "trace", skip(tcx, res))] +fn add_generics_and_bounds_as_types<'tcx>( generics: &Generics, arg: &Type, tcx: TyCtxt<'tcx>, recurse: usize, res: &mut Vec, - cache: &Cache, ) { fn insert_ty( res: &mut Vec, tcx: TyCtxt<'_>, ty: Type, mut generics: Vec, - _cache: &Cache, ) { let is_full_generic = ty.is_full_generic(); @@ -330,6 +317,7 @@ crate fn get_real_types<'tcx>( if recurse >= 10 { // FIXME: remove this whole recurse thing when the recursion bug is fixed + // See #59502 for the original issue. return; } @@ -350,13 +338,12 @@ crate fn get_real_types<'tcx>( for param_def in poly_trait.generic_params.iter() { match ¶m_def.kind { clean::GenericParamDefKind::Type { default: Some(ty), .. } => { - get_real_types( + add_generics_and_bounds_as_types( generics, ty, tcx, recurse + 1, &mut ty_generics, - cache, ) } _ => {} @@ -364,7 +351,7 @@ crate fn get_real_types<'tcx>( } } } - insert_ty(res, tcx, arg.clone(), ty_generics, cache); + insert_ty(res, tcx, arg.clone(), ty_generics); } // Otherwise we check if the trait bounds are "inlined" like `T: Option`... if let Some(bound) = generics.params.iter().find(|g| g.is_type() && g.name == arg_s) { @@ -372,10 +359,16 @@ crate fn get_real_types<'tcx>( for bound in bound.get_bounds().unwrap_or(&[]) { if let Some(path) = bound.get_trait_path() { let ty = Type::Path { path }; - get_real_types(generics, &ty, tcx, recurse + 1, &mut ty_generics, cache); + add_generics_and_bounds_as_types( + generics, + &ty, + tcx, + recurse + 1, + &mut ty_generics, + ); } } - insert_ty(res, tcx, arg.clone(), ty_generics, cache); + insert_ty(res, tcx, arg.clone(), ty_generics); } } else { // This is not a type parameter. So for example if we have `T, U: Option`, and we're @@ -386,10 +379,10 @@ crate fn get_real_types<'tcx>( let mut ty_generics = Vec::new(); if let Some(arg_generics) = arg.generics() { for gen in arg_generics.iter() { - get_real_types(generics, gen, tcx, recurse + 1, &mut ty_generics, cache); + add_generics_and_bounds_as_types(generics, gen, tcx, recurse + 1, &mut ty_generics); } } - insert_ty(res, tcx, arg.clone(), ty_generics, cache); + insert_ty(res, tcx, arg.clone(), ty_generics); } } @@ -397,19 +390,20 @@ crate fn get_real_types<'tcx>( /// /// i.e. `fn foo>(x: u32, y: B)` will return /// `[u32, Display, Option]`. -crate fn get_all_types<'tcx>( - generics: &Generics, - decl: &FnDecl, +fn get_fn_inputs_and_outputs<'tcx>( + func: &Function, tcx: TyCtxt<'tcx>, - cache: &Cache, ) -> (Vec, Vec) { + let decl = &func.decl; + let generics = &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(); - get_real_types(generics, &arg.type_, tcx, 0, &mut args, cache); + add_generics_and_bounds_as_types(generics, &arg.type_, tcx, 0, &mut args); if !args.is_empty() { all_types.extend(args); } else { @@ -423,7 +417,7 @@ crate fn get_all_types<'tcx>( let mut ret_types = Vec::new(); match decl.output { FnRetTy::Return(ref return_type) => { - get_real_types(generics, return_type, tcx, 0, &mut ret_types, cache); + add_generics_and_bounds_as_types(generics, return_type, tcx, 0, &mut ret_types); if ret_types.is_empty() { if let Some(kind) = return_type.def_id_no_primitives().map(|did| tcx.def_kind(did).into()) diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs index 0031e3915fa40..005da01b52b6c 100644 --- a/src/librustdoc/json/mod.rs +++ b/src/librustdoc/json/mod.rs @@ -19,12 +19,11 @@ use rustc_session::Session; use rustdoc_json_types as types; use crate::clean; -use crate::clean::ExternalCrate; +use crate::clean::types::{ExternalCrate, ExternalLocation}; use crate::config::RenderOptions; use crate::error::Error; use crate::formats::cache::Cache; use crate::formats::FormatRenderer; -use crate::html::render::cache::ExternalLocation; use crate::json::conversions::{from_item_id, IntoWithTcx}; #[derive(Clone)] diff --git a/src/test/rustdoc-ui/search-index-generics-recursion-bug-issue-59502.rs b/src/test/rustdoc-ui/search-index-generics-recursion-bug-issue-59502.rs new file mode 100644 index 0000000000000..ce51556dd418b --- /dev/null +++ b/src/test/rustdoc-ui/search-index-generics-recursion-bug-issue-59502.rs @@ -0,0 +1,11 @@ +// check-pass + +// Minimization of issue #59502 + +trait MyTrait { + type Output; +} + +pub fn pow>(arg: T) -> T { + arg +}