about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustdoc/clean/types.rs11
-rw-r--r--src/librustdoc/formats/cache.rs6
-rw-r--r--src/librustdoc/html/format.rs6
-rw-r--r--src/librustdoc/html/render/context.rs4
-rw-r--r--src/librustdoc/html/render/mod.rs2
-rw-r--r--src/librustdoc/html/render/search_index.rs (renamed from src/librustdoc/html/render/cache.rs)72
-rw-r--r--src/librustdoc/json/mod.rs3
-rw-r--r--src/test/rustdoc-ui/search-index-generics-recursion-bug-issue-59502.rs11
8 files changed, 65 insertions, 50 deletions
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index d928b41cad4..2b1a1d4a600 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 5813062ceab..6b9ccd37cfb 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 e4c612aaab9..3a7c7186877 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 45a436c4487..534a542d58e 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 eb606178d24..3e7711181f7 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
index 631eacc9618..0fbe090f219 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<IndexItemFunctionType> {
     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<TypeWithKind>) -> 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<Symbol> {
+fn get_index_type_name(clean_type: &clean::Type) -> Option<Symbol> {
     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<Result<(), ()>>`, 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<TypeWithKind>,
-    cache: &Cache,
 ) {
     fn insert_ty(
         res: &mut Vec<TypeWithKind>,
         tcx: TyCtxt<'_>,
         ty: Type,
         mut generics: Vec<TypeWithKind>,
-        _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 &param_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<u32>`...
         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<T>`, 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<A: Display, B: Option<A>>(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<TypeWithKind>, Vec<TypeWithKind>) {
+    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 0031e3915fa..005da01b52b 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 00000000000..ce51556dd41
--- /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<T> {
+    type Output;
+}
+
+pub fn pow<T: MyTrait<T, Output = T>>(arg: T) -> T {
+    arg
+}