Skip to content

issue-90187-fix #92688

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 0 additions & 13 deletions src/librustdoc/clean/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1566,23 +1566,10 @@ impl Type {

/// Use this method to get the [DefId] of a [clean] AST node, including [PrimitiveType]s.
///
/// See [`Self::def_id_no_primitives`] for more.
///
/// [clean]: crate::clean
crate fn def_id(&self, cache: &Cache) -> Option<DefId> {
self.inner_def_id(Some(cache))
}

/// Use this method to get the [`DefId`] of a [`clean`] AST node.
/// This will return [`None`] when called on a primitive [`clean::Type`].
/// Use [`Self::def_id`] if you want to include primitives.
///
/// [`clean`]: crate::clean
/// [`clean::Type`]: crate::clean::Type
// FIXME: get rid of this function and always use `def_id`
crate fn def_id_no_primitives(&self) -> Option<DefId> {
self.inner_def_id(None)
}
}

/// A primitive (aka, builtin) type.
Expand Down
85 changes: 43 additions & 42 deletions src/librustdoc/html/render/search_index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,22 @@ use rustc_span::symbol::Symbol;
use serde::ser::{Serialize, SerializeStruct, Serializer};

use crate::clean;
use crate::clean::types::{FnRetTy, Function, GenericBound, Generics, Type, WherePredicate};
use crate::clean::types::{FnDecl, FnRetTy, 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();
Expand All @@ -32,7 +42,7 @@ crate fn build_index<'tcx>(krate: &clean::Crate, cache: &mut Cache, tcx: TyCtxt<
desc,
parent: Some(did),
parent_idx: None,
search_type: get_function_type_for_search(item, tcx),
search_type: get_index_search_type(item, tcx, cache),
aliases: item.attrs.get_doc_aliases(),
});
}
Expand Down Expand Up @@ -181,14 +191,15 @@ crate fn build_index<'tcx>(krate: &clean::Crate, cache: &mut Cache, tcx: TyCtxt<
)
}

crate fn get_function_type_for_search<'tcx>(
crate fn get_index_search_type<'tcx>(
item: &clean::Item,
tcx: TyCtxt<'tcx>,
cache: &Cache,
) -> Option<IndexItemFunctionType> {
let (mut inputs, mut output) = match *item.kind {
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),
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),
_ => return None,
};

Expand All @@ -200,12 +211,12 @@ crate fn get_function_type_for_search<'tcx>(

fn get_index_type(clean_type: &clean::Type, generics: Vec<TypeWithKind>) -> RenderType {
RenderType {
name: get_index_type_name(clean_type).map(|s| s.as_str().to_ascii_lowercase()),
name: get_index_type_name(clean_type, true).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) -> Option<Symbol> {
fn get_index_type_name(clean_type: &clean::Type, accept_generic: bool) -> Option<Symbol> {
match *clean_type {
clean::Type::Path { ref path, .. } => {
let path_segment = path.segments.last().unwrap();
Expand All @@ -215,10 +226,11 @@ fn get_index_type_name(clean_type: &clean::Type) -> Option<Symbol> {
let path = &bounds[0].trait_;
Some(path.segments.last().unwrap().name)
}
clean::Generic(s) => Some(s),
clean::Generic(s) if accept_generic => Some(s),
clean::Primitive(ref p) => Some(p.as_sym()),
clean::BorrowedRef { ref type_, .. } => get_index_type_name(type_),
clean::BareFunction(_)
clean::BorrowedRef { ref type_, .. } => get_index_type_name(type_, accept_generic),
clean::Generic(_)
| clean::BareFunction(_)
| clean::Tuple(_)
| clean::Slice(_)
| clean::Array(_, _)
Expand All @@ -236,19 +248,20 @@ fn get_index_type_name(clean_type: &clean::Type) -> Option<Symbol> {
///
/// Important note: It goes through generics recursively. So if you have
/// `T: Option<Result<(), ()>>`, it'll go into `Option` and then into `Result`.
#[instrument(level = "trace", skip(tcx, res))]
fn add_generics_and_bounds_as_types<'tcx>(
crate fn get_real_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();

Expand Down Expand Up @@ -307,7 +320,7 @@ fn add_generics_and_bounds_as_types<'tcx>(
// We remove the name of the full generic because we have no use for it.
index_ty.name = Some(String::new());
res.push(TypeWithKind::from((index_ty, ItemType::Generic)));
} else if let Some(kind) = ty.def_id_no_primitives().map(|did| tcx.def_kind(did).into()) {
} else if let Some(kind) = ty.def_id(cache).map(|did| tcx.def_kind(did).into()) {
res.push(TypeWithKind::from((index_ty, kind)));
} else if ty.is_primitive() {
// This is a primitive, let's store it as such.
Expand All @@ -317,7 +330,6 @@ fn add_generics_and_bounds_as_types<'tcx>(

if recurse >= 10 {
// FIXME: remove this whole recurse thing when the recursion bug is fixed
// See #59502 for the original issue.
return;
}

Expand All @@ -326,9 +338,7 @@ fn add_generics_and_bounds_as_types<'tcx>(
if let Type::Generic(arg_s) = *arg {
// First we check if the bounds are in a `where` predicate...
if let Some(where_pred) = generics.where_predicates.iter().find(|g| match g {
WherePredicate::BoundPredicate { ty, .. } => {
ty.def_id_no_primitives() == arg.def_id_no_primitives()
}
WherePredicate::BoundPredicate { ty, .. } => ty.def_id(cache) == arg.def_id(cache),
_ => false,
}) {
let mut ty_generics = Vec::new();
Expand All @@ -338,37 +348,32 @@ fn add_generics_and_bounds_as_types<'tcx>(
for param_def in poly_trait.generic_params.iter() {
match &param_def.kind {
clean::GenericParamDefKind::Type { default: Some(ty), .. } => {
add_generics_and_bounds_as_types(
get_real_types(
generics,
ty,
tcx,
recurse + 1,
&mut ty_generics,
cache,
)
}
_ => {}
}
}
}
}
insert_ty(res, tcx, arg.clone(), ty_generics);
insert_ty(res, tcx, arg.clone(), ty_generics, cache);
}
// 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) {
let mut ty_generics = Vec::new();
for bound in bound.get_bounds().unwrap_or(&[]) {
if let Some(path) = bound.get_trait_path() {
let ty = Type::Path { path };
add_generics_and_bounds_as_types(
generics,
&ty,
tcx,
recurse + 1,
&mut ty_generics,
);
get_real_types(generics, &ty, tcx, recurse + 1, &mut ty_generics, cache);
}
}
insert_ty(res, tcx, arg.clone(), ty_generics);
insert_ty(res, tcx, arg.clone(), ty_generics, cache);
}
} else {
// This is not a type parameter. So for example if we have `T, U: Option<T>`, and we're
Expand All @@ -379,36 +384,34 @@ fn add_generics_and_bounds_as_types<'tcx>(
let mut ty_generics = Vec::new();
if let Some(arg_generics) = arg.generics() {
for gen in arg_generics.iter() {
add_generics_and_bounds_as_types(generics, gen, tcx, recurse + 1, &mut ty_generics);
get_real_types(generics, gen, tcx, recurse + 1, &mut ty_generics, cache);
}
}
insert_ty(res, tcx, arg.clone(), ty_generics);
insert_ty(res, tcx, arg.clone(), ty_generics, cache);
}
}

/// Return the full list of types when bounds have been resolved.
///
/// i.e. `fn foo<A: Display, B: Option<A>>(x: u32, y: B)` will return
/// `[u32, Display, Option]`.
fn get_fn_inputs_and_outputs<'tcx>(
func: &Function,
crate fn get_all_types<'tcx>(
generics: &Generics,
decl: &FnDecl,
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();
add_generics_and_bounds_as_types(generics, &arg.type_, tcx, 0, &mut args);
get_real_types(generics, &arg.type_, tcx, 0, &mut args, cache);
if !args.is_empty() {
all_types.extend(args);
} else {
if let Some(kind) = arg.type_.def_id_no_primitives().map(|did| tcx.def_kind(did).into())
{
if let Some(kind) = arg.type_.def_id(cache).map(|did| tcx.def_kind(did).into()) {
all_types.push(TypeWithKind::from((get_index_type(&arg.type_, vec![]), kind)));
}
}
Expand All @@ -417,11 +420,9 @@ 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);
get_real_types(generics, return_type, tcx, 0, &mut ret_types, cache);
if ret_types.is_empty() {
if let Some(kind) =
return_type.def_id_no_primitives().map(|did| tcx.def_kind(did).into())
{
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)));
}
}
Expand Down
14 changes: 8 additions & 6 deletions src/librustdoc/passes/collect_trait_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use crate::clean::*;
use crate::core::DocContext;
use crate::visit::DocVisitor;

use crate::formats::cache::Cache;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir::def_id::DefId;
use rustc_middle::ty::DefIdTree;
Expand Down Expand Up @@ -55,14 +56,14 @@ crate fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> Crate
}
}

let mut cleaner = BadImplStripper { prims, items: crate_items };
let mut cleaner = BadImplStripper { prims, items: crate_items, cache: &cx.cache };
let mut type_did_to_deref_target: FxHashMap<DefId, &Type> = FxHashMap::default();

// Follow all `Deref` targets of included items and recursively add them as valid
fn add_deref_target(
cx: &DocContext<'_>,
map: &FxHashMap<DefId, &Type>,
cleaner: &mut BadImplStripper,
cleaner: &mut BadImplStripper<'_>,
type_did: DefId,
) {
if let Some(target) = map.get(&type_did) {
Expand Down Expand Up @@ -100,7 +101,7 @@ crate fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> Crate
} else if let Some(did) = target.def_id(&cx.cache) {
cleaner.items.insert(did.into());
}
if let Some(for_did) = for_.def_id_no_primitives() {
if let Some(for_did) = for_.def_id(&cx.cache) {
if type_did_to_deref_target.insert(for_did, target).is_none() {
// Since only the `DefId` portion of the `Type` instances is known to be same for both the
// `Deref` target type and the impl for type positions, this map of types is keyed by
Expand Down Expand Up @@ -205,19 +206,20 @@ impl DocVisitor for ItemCollector {
}
}

struct BadImplStripper {
struct BadImplStripper<'a> {
prims: FxHashSet<PrimitiveType>,
items: FxHashSet<ItemId>,
cache: &'a Cache,
}

impl BadImplStripper {
impl<'a> BadImplStripper<'a> {
fn keep_impl(&self, ty: &Type, is_deref: bool) -> bool {
if let Generic(_) = ty {
// keep impls made on generics
true
} else if let Some(prim) = ty.primitive_type() {
self.prims.contains(&prim)
} else if let Some(did) = ty.def_id_no_primitives() {
} else if let Some(did) = ty.def_id(&self.cache) {
is_deref || self.keep_impl_with_def_id(did.into())
} else {
false
Expand Down
4 changes: 2 additions & 2 deletions src/librustdoc/passes/strip_hidden.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ crate const STRIP_HIDDEN: Pass = Pass {
};

/// Strip items marked `#[doc(hidden)]`
crate fn strip_hidden(krate: clean::Crate, _: &mut DocContext<'_>) -> clean::Crate {
crate fn strip_hidden(krate: clean::Crate, cx: &mut DocContext<'_>) -> clean::Crate {
let mut retained = ItemIdSet::default();

// strip all #[doc(hidden)] items
Expand All @@ -25,7 +25,7 @@ crate fn strip_hidden(krate: clean::Crate, _: &mut DocContext<'_>) -> clean::Cra
};

// strip all impls referencing stripped items
let mut stripper = ImplStripper { retained: &retained };
let mut stripper = ImplStripper { retained: &retained, cache: &cx.cache };
stripper.fold_crate(krate)
}

Expand Down
2 changes: 1 addition & 1 deletion src/librustdoc/passes/strip_private.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,6 @@ crate fn strip_private(mut krate: clean::Crate, cx: &mut DocContext<'_>) -> clea
}

// strip all impls referencing private items
let mut stripper = ImplStripper { retained: &retained };
let mut stripper = ImplStripper { retained: &retained, cache: &cx.cache };
stripper.fold_crate(krate)
}
6 changes: 4 additions & 2 deletions src/librustdoc/passes/stripper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use std::mem;

use crate::clean::{self, Item, ItemIdSet};
use crate::fold::{strip_item, DocFolder};
use crate::formats::cache::Cache;

crate struct Stripper<'a> {
crate retained: &'a mut ItemIdSet,
Expand Down Expand Up @@ -119,6 +120,7 @@ impl<'a> DocFolder for Stripper<'a> {
/// This stripper discards all impls which reference stripped items
crate struct ImplStripper<'a> {
crate retained: &'a ItemIdSet,
crate cache: &'a Cache,
}

impl<'a> DocFolder for ImplStripper<'a> {
Expand All @@ -128,7 +130,7 @@ impl<'a> DocFolder for ImplStripper<'a> {
if imp.trait_.is_none() && imp.items.is_empty() {
return None;
}
if let Some(did) = imp.for_.def_id_no_primitives() {
if let Some(did) = imp.for_.def_id(&self.cache) {
if did.is_local() && !imp.for_.is_assoc_ty() && !self.retained.contains(&did.into())
{
debug!("ImplStripper: impl item for stripped type; removing");
Expand All @@ -143,7 +145,7 @@ impl<'a> DocFolder for ImplStripper<'a> {
}
if let Some(generics) = imp.trait_.as_ref().and_then(|t| t.generics()) {
for typaram in generics {
if let Some(did) = typaram.def_id_no_primitives() {
if let Some(did) = typaram.def_id(&self.cache) {
if did.is_local() && !self.retained.contains(&did.into()) {
debug!(
"ImplStripper: stripped item in trait's generics; removing impl"
Expand Down