summaryrefslogtreecommitdiffstats
path: root/src/librustdoc/html/render/search_index.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/librustdoc/html/render/search_index.rs')
-rw-r--r--src/librustdoc/html/render/search_index.rs433
1 files changed, 368 insertions, 65 deletions
diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs
index af1dab594..a1029320d 100644
--- a/src/librustdoc/html/render/search_index.rs
+++ b/src/librustdoc/html/render/search_index.rs
@@ -3,8 +3,10 @@ use std::collections::BTreeMap;
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
use rustc_middle::ty::TyCtxt;
+use rustc_span::def_id::DefId;
use rustc_span::symbol::Symbol;
use serde::ser::{Serialize, SerializeSeq, SerializeStruct, Serializer};
+use thin_vec::ThinVec;
use crate::clean;
use crate::clean::types::{Function, Generics, ItemId, Type, WherePredicate};
@@ -22,6 +24,7 @@ pub(crate) fn build_index<'tcx>(
) -> String {
let mut itemid_to_pathid = FxHashMap::default();
let mut primitives = FxHashMap::default();
+ let mut associated_types = FxHashMap::default();
let mut crate_paths = vec![];
// Attach all orphan items to the type's definition if the type
@@ -38,7 +41,13 @@ pub(crate) fn build_index<'tcx>(
parent: Some(parent),
parent_idx: None,
impl_id,
- search_type: get_function_type_for_search(item, tcx, impl_generics.as_ref(), cache),
+ search_type: get_function_type_for_search(
+ item,
+ tcx,
+ impl_generics.as_ref(),
+ Some(parent),
+ cache,
+ ),
aliases: item.attrs.get_doc_aliases(),
deprecation: item.deprecation(tcx),
});
@@ -76,83 +85,139 @@ pub(crate) fn build_index<'tcx>(
let mut search_index = std::mem::replace(&mut cache.search_index, Vec::new());
for item in search_index.iter_mut() {
fn insert_into_map<F: std::hash::Hash + Eq>(
- ty: &mut RenderType,
map: &mut FxHashMap<F, isize>,
itemid: F,
lastpathid: &mut isize,
crate_paths: &mut Vec<(ItemType, Vec<Symbol>)>,
item_type: ItemType,
path: &[Symbol],
- ) {
+ ) -> RenderTypeId {
match map.entry(itemid) {
- Entry::Occupied(entry) => ty.id = Some(RenderTypeId::Index(*entry.get())),
+ Entry::Occupied(entry) => RenderTypeId::Index(*entry.get()),
Entry::Vacant(entry) => {
let pathid = *lastpathid;
entry.insert(pathid);
*lastpathid += 1;
crate_paths.push((item_type, path.to_vec()));
- ty.id = Some(RenderTypeId::Index(pathid));
+ RenderTypeId::Index(pathid)
}
}
}
- fn convert_render_type(
- ty: &mut RenderType,
+ fn convert_render_type_id(
+ id: RenderTypeId,
cache: &mut Cache,
itemid_to_pathid: &mut FxHashMap<ItemId, isize>,
primitives: &mut FxHashMap<Symbol, isize>,
+ associated_types: &mut FxHashMap<Symbol, isize>,
lastpathid: &mut isize,
crate_paths: &mut Vec<(ItemType, Vec<Symbol>)>,
- ) {
- if let Some(generics) = &mut ty.generics {
- for item in generics {
- convert_render_type(
- item,
- cache,
- itemid_to_pathid,
- primitives,
- lastpathid,
- crate_paths,
- );
- }
- }
+ ) -> Option<RenderTypeId> {
let Cache { ref paths, ref external_paths, .. } = *cache;
- let Some(id) = ty.id.clone() else {
- assert!(ty.generics.is_some());
- return;
- };
match id {
RenderTypeId::DefId(defid) => {
if let Some(&(ref fqp, item_type)) =
paths.get(&defid).or_else(|| external_paths.get(&defid))
{
- insert_into_map(
- ty,
+ Some(insert_into_map(
itemid_to_pathid,
ItemId::DefId(defid),
lastpathid,
crate_paths,
item_type,
fqp,
- );
+ ))
} else {
- ty.id = None;
+ None
}
}
RenderTypeId::Primitive(primitive) => {
let sym = primitive.as_sym();
- insert_into_map(
- ty,
+ Some(insert_into_map(
primitives,
sym,
lastpathid,
crate_paths,
ItemType::Primitive,
&[sym],
+ ))
+ }
+ RenderTypeId::Index(_) => Some(id),
+ RenderTypeId::AssociatedType(sym) => Some(insert_into_map(
+ associated_types,
+ sym,
+ lastpathid,
+ crate_paths,
+ ItemType::AssocType,
+ &[sym],
+ )),
+ }
+ }
+
+ fn convert_render_type(
+ ty: &mut RenderType,
+ cache: &mut Cache,
+ itemid_to_pathid: &mut FxHashMap<ItemId, isize>,
+ primitives: &mut FxHashMap<Symbol, isize>,
+ associated_types: &mut FxHashMap<Symbol, isize>,
+ lastpathid: &mut isize,
+ crate_paths: &mut Vec<(ItemType, Vec<Symbol>)>,
+ ) {
+ if let Some(generics) = &mut ty.generics {
+ for item in generics {
+ convert_render_type(
+ item,
+ cache,
+ itemid_to_pathid,
+ primitives,
+ associated_types,
+ lastpathid,
+ crate_paths,
);
}
- RenderTypeId::Index(_) => {}
}
+ if let Some(bindings) = &mut ty.bindings {
+ bindings.retain_mut(|(associated_type, constraints)| {
+ let converted_associated_type = convert_render_type_id(
+ *associated_type,
+ cache,
+ itemid_to_pathid,
+ primitives,
+ associated_types,
+ lastpathid,
+ crate_paths,
+ );
+ let Some(converted_associated_type) = converted_associated_type else {
+ return false;
+ };
+ *associated_type = converted_associated_type;
+ for constraint in constraints {
+ convert_render_type(
+ constraint,
+ cache,
+ itemid_to_pathid,
+ primitives,
+ associated_types,
+ lastpathid,
+ crate_paths,
+ );
+ }
+ true
+ });
+ }
+ let Some(id) = ty.id.clone() else {
+ assert!(ty.generics.is_some());
+ return;
+ };
+ ty.id = convert_render_type_id(
+ id,
+ cache,
+ itemid_to_pathid,
+ primitives,
+ associated_types,
+ lastpathid,
+ crate_paths,
+ );
}
if let Some(search_type) = &mut item.search_type {
for item in &mut search_type.inputs {
@@ -161,6 +226,7 @@ pub(crate) fn build_index<'tcx>(
cache,
&mut itemid_to_pathid,
&mut primitives,
+ &mut associated_types,
&mut lastpathid,
&mut crate_paths,
);
@@ -171,6 +237,7 @@ pub(crate) fn build_index<'tcx>(
cache,
&mut itemid_to_pathid,
&mut primitives,
+ &mut associated_types,
&mut lastpathid,
&mut crate_paths,
);
@@ -182,6 +249,7 @@ pub(crate) fn build_index<'tcx>(
cache,
&mut itemid_to_pathid,
&mut primitives,
+ &mut associated_types,
&mut lastpathid,
&mut crate_paths,
);
@@ -228,10 +296,11 @@ pub(crate) fn build_index<'tcx>(
let mut associated_item_duplicates = FxHashMap::<(isize, ItemType, Symbol), usize>::default();
for &item in &crate_items {
- if item.impl_id.is_some() && let Some(parent_idx) = item.parent_idx {
- let count = associated_item_duplicates
- .entry((parent_idx, item.ty, item.name))
- .or_insert(0);
+ if item.impl_id.is_some()
+ && let Some(parent_idx) = item.parent_idx
+ {
+ let count =
+ associated_item_duplicates.entry((parent_idx, item.ty, item.name)).or_insert(0);
*count += 1;
}
}
@@ -419,7 +488,7 @@ pub(crate) fn build_index<'tcx>(
// Collect the index into a string
format!(
- r#""{}":{}"#,
+ r#"["{}",{}]"#,
krate.name(tcx),
serde_json::to_string(&CrateData {
doc: crate_doc,
@@ -441,12 +510,39 @@ pub(crate) fn get_function_type_for_search<'tcx>(
item: &clean::Item,
tcx: TyCtxt<'tcx>,
impl_generics: Option<&(clean::Type, clean::Generics)>,
+ parent: Option<DefId>,
cache: &Cache,
) -> Option<IndexItemFunctionType> {
+ let mut trait_info = None;
+ let impl_or_trait_generics = impl_generics.or_else(|| {
+ if let Some(def_id) = parent
+ && let Some(trait_) = cache.traits.get(&def_id)
+ && let Some((path, _)) =
+ cache.paths.get(&def_id).or_else(|| cache.external_paths.get(&def_id))
+ {
+ let path = clean::Path {
+ res: rustc_hir::def::Res::Def(rustc_hir::def::DefKind::Trait, def_id),
+ segments: path
+ .iter()
+ .map(|name| clean::PathSegment {
+ name: *name,
+ args: clean::GenericArgs::AngleBracketed {
+ args: Vec::new().into_boxed_slice(),
+ bindings: ThinVec::new(),
+ },
+ })
+ .collect(),
+ };
+ trait_info = Some((clean::Type::Path { path }, trait_.generics.clone()));
+ Some(trait_info.as_ref().unwrap())
+ } else {
+ None
+ }
+ });
let (mut inputs, mut output, where_clause) = 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),
- clean::TyMethodItem(ref m) => get_fn_inputs_and_outputs(m, tcx, impl_generics, cache),
+ clean::FunctionItem(ref f) | clean::MethodItem(ref f, _) | clean::TyMethodItem(ref f) => {
+ get_fn_inputs_and_outputs(f, tcx, impl_or_trait_generics, cache)
+ }
_ => return None,
};
@@ -456,14 +552,23 @@ pub(crate) fn get_function_type_for_search<'tcx>(
Some(IndexItemFunctionType { inputs, output, where_clause })
}
-fn get_index_type(clean_type: &clean::Type, generics: Vec<RenderType>) -> RenderType {
+fn get_index_type(
+ clean_type: &clean::Type,
+ generics: Vec<RenderType>,
+ rgen: &mut FxHashMap<SimplifiedParam, (isize, Vec<RenderType>)>,
+) -> RenderType {
RenderType {
- id: get_index_type_id(clean_type),
+ id: get_index_type_id(clean_type, rgen),
generics: if generics.is_empty() { None } else { Some(generics) },
+ bindings: None,
}
}
-fn get_index_type_id(clean_type: &clean::Type) -> Option<RenderTypeId> {
+fn get_index_type_id(
+ clean_type: &clean::Type,
+ rgen: &mut FxHashMap<SimplifiedParam, (isize, Vec<RenderType>)>,
+) -> Option<RenderTypeId> {
+ use rustc_hir::def::{DefKind, Res};
match *clean_type {
clean::Type::Path { ref path, .. } => Some(RenderTypeId::DefId(path.def_id())),
clean::DynTrait(ref bounds, _) => {
@@ -471,18 +576,27 @@ fn get_index_type_id(clean_type: &clean::Type) -> Option<RenderTypeId> {
}
clean::Primitive(p) => Some(RenderTypeId::Primitive(p)),
clean::BorrowedRef { ref type_, .. } | clean::RawPointer(_, ref type_) => {
- get_index_type_id(type_)
+ get_index_type_id(type_, rgen)
}
// The type parameters are converted to generics in `simplify_fn_type`
clean::Slice(_) => Some(RenderTypeId::Primitive(clean::PrimitiveType::Slice)),
clean::Array(_, _) => Some(RenderTypeId::Primitive(clean::PrimitiveType::Array)),
clean::Tuple(_) => Some(RenderTypeId::Primitive(clean::PrimitiveType::Tuple)),
+ clean::QPath(ref data) => {
+ if data.self_type.is_self_type()
+ && let Some(clean::Path { res: Res::Def(DefKind::Trait, trait_), .. }) = data.trait_
+ {
+ let idx = -isize::try_from(rgen.len() + 1).unwrap();
+ let (idx, _) = rgen
+ .entry(SimplifiedParam::AssociatedType(trait_, data.assoc.name))
+ .or_insert_with(|| (idx, Vec::new()));
+ Some(RenderTypeId::Index(*idx))
+ } else {
+ None
+ }
+ }
// Not supported yet
- clean::BareFunction(_)
- | clean::Generic(_)
- | clean::ImplTrait(_)
- | clean::QPath { .. }
- | clean::Infer => None,
+ clean::BareFunction(_) | clean::Generic(_) | clean::ImplTrait(_) | clean::Infer => None,
}
}
@@ -492,6 +606,9 @@ enum SimplifiedParam {
Symbol(Symbol),
// every argument-position impl trait is its own type parameter
Anonymous(isize),
+ // in a trait definition, the associated types are all bound to
+ // their own type parameter
+ AssociatedType(DefId, Symbol),
}
/// The point of this function is to lower generics and types into the simplified form that the
@@ -522,10 +639,17 @@ fn simplify_fn_type<'tcx, 'a>(
}
// First, check if it's "Self".
+ let mut is_self = false;
let mut arg = if let Some(self_) = self_ {
match &*arg {
- Type::BorrowedRef { type_, .. } if type_.is_self_type() => self_,
- type_ if type_.is_self_type() => self_,
+ Type::BorrowedRef { type_, .. } if type_.is_self_type() => {
+ is_self = true;
+ self_
+ }
+ type_ if type_.is_self_type() => {
+ is_self = true;
+ self_
+ }
arg => arg,
}
} else {
@@ -584,11 +708,19 @@ fn simplify_fn_type<'tcx, 'a>(
}
}
if let Some((idx, _)) = rgen.get(&SimplifiedParam::Symbol(arg_s)) {
- res.push(RenderType { id: Some(RenderTypeId::Index(*idx)), generics: None });
+ res.push(RenderType {
+ id: Some(RenderTypeId::Index(*idx)),
+ generics: None,
+ bindings: None,
+ });
} else {
let idx = -isize::try_from(rgen.len() + 1).unwrap();
rgen.insert(SimplifiedParam::Symbol(arg_s), (idx, type_bounds));
- res.push(RenderType { id: Some(RenderTypeId::Index(idx)), generics: None });
+ res.push(RenderType {
+ id: Some(RenderTypeId::Index(idx)),
+ generics: None,
+ bindings: None,
+ });
}
} else if let Type::ImplTrait(ref bounds) = *arg {
let mut type_bounds = Vec::new();
@@ -610,12 +742,16 @@ fn simplify_fn_type<'tcx, 'a>(
}
if is_return && !type_bounds.is_empty() {
// In parameter position, `impl Trait` is a unique thing.
- res.push(RenderType { id: None, generics: Some(type_bounds) });
+ res.push(RenderType { id: None, generics: Some(type_bounds), bindings: None });
} else {
// In parameter position, `impl Trait` is the same as an unnamed generic parameter.
let idx = -isize::try_from(rgen.len() + 1).unwrap();
rgen.insert(SimplifiedParam::Anonymous(idx), (idx, type_bounds));
- res.push(RenderType { id: Some(RenderTypeId::Index(idx)), generics: None });
+ res.push(RenderType {
+ id: Some(RenderTypeId::Index(idx)),
+ generics: None,
+ bindings: None,
+ });
}
} else if let Type::Slice(ref ty) = *arg {
let mut ty_generics = Vec::new();
@@ -630,7 +766,7 @@ fn simplify_fn_type<'tcx, 'a>(
is_return,
cache,
);
- res.push(get_index_type(arg, ty_generics));
+ res.push(get_index_type(arg, ty_generics, rgen));
} else if let Type::Array(ref ty, _) = *arg {
let mut ty_generics = Vec::new();
simplify_fn_type(
@@ -644,7 +780,7 @@ fn simplify_fn_type<'tcx, 'a>(
is_return,
cache,
);
- res.push(get_index_type(arg, ty_generics));
+ res.push(get_index_type(arg, ty_generics, rgen));
} else if let Type::Tuple(ref tys) = *arg {
let mut ty_generics = Vec::new();
for ty in tys {
@@ -660,7 +796,7 @@ fn simplify_fn_type<'tcx, 'a>(
cache,
);
}
- res.push(get_index_type(arg, ty_generics));
+ res.push(get_index_type(arg, ty_generics, rgen));
} else {
// This is not a type parameter. So for example if we have `T, U: Option<T>`, and we're
// looking at `Option`, we enter this "else" condition, otherwise if it's `T`, we don't.
@@ -668,12 +804,16 @@ fn simplify_fn_type<'tcx, 'a>(
// So in here, we can add it directly and look for its own type parameters (so for `Option`,
// we will look for them but not for `T`).
let mut ty_generics = Vec::new();
- if let Some(arg_generics) = arg.generics() {
- for gen in arg_generics.iter() {
+ let mut ty_bindings = Vec::new();
+ if let Some(arg_generics) = arg.generic_args() {
+ for ty in arg_generics.into_iter().filter_map(|gen| match gen {
+ clean::GenericArg::Type(ty) => Some(ty),
+ _ => None,
+ }) {
simplify_fn_type(
self_,
generics,
- gen,
+ &ty,
tcx,
recurse + 1,
&mut ty_generics,
@@ -682,17 +822,180 @@ fn simplify_fn_type<'tcx, 'a>(
cache,
);
}
+ for binding in arg_generics.bindings() {
+ simplify_fn_binding(
+ self_,
+ generics,
+ &binding,
+ tcx,
+ recurse + 1,
+ &mut ty_bindings,
+ rgen,
+ is_return,
+ cache,
+ );
+ }
+ }
+ // Every trait associated type on self gets assigned to a type parameter index
+ // this same one is used later for any appearances of these types
+ //
+ // for example, Iterator::next is:
+ //
+ // trait Iterator {
+ // fn next(&mut self) -> Option<Self::Item>
+ // }
+ //
+ // Self is technically just Iterator, but we want to pretend it's more like this:
+ //
+ // fn next<T>(self: Iterator<Item=T>) -> Option<T>
+ if is_self
+ && let Type::Path { path } = arg
+ && let def_id = path.def_id()
+ && let Some(trait_) = cache.traits.get(&def_id)
+ && trait_.items.iter().any(|at| at.is_ty_associated_type())
+ {
+ for assoc_ty in &trait_.items {
+ if let clean::ItemKind::TyAssocTypeItem(_generics, bounds) = &*assoc_ty.kind
+ && let Some(name) = assoc_ty.name
+ {
+ let idx = -isize::try_from(rgen.len() + 1).unwrap();
+ let (idx, stored_bounds) = rgen
+ .entry(SimplifiedParam::AssociatedType(def_id, name))
+ .or_insert_with(|| (idx, Vec::new()));
+ let idx = *idx;
+ if stored_bounds.is_empty() {
+ // Can't just pass stored_bounds to simplify_fn_type,
+ // because it also accepts rgen as a parameter.
+ // Instead, have it fill in this local, then copy it into the map afterward.
+ let mut type_bounds = Vec::new();
+ for bound in bounds {
+ if let Some(path) = bound.get_trait_path() {
+ let ty = Type::Path { path };
+ simplify_fn_type(
+ self_,
+ generics,
+ &ty,
+ tcx,
+ recurse + 1,
+ &mut type_bounds,
+ rgen,
+ is_return,
+ cache,
+ );
+ }
+ }
+ let stored_bounds = &mut rgen
+ .get_mut(&SimplifiedParam::AssociatedType(def_id, name))
+ .unwrap()
+ .1;
+ if stored_bounds.is_empty() {
+ *stored_bounds = type_bounds;
+ }
+ }
+ ty_bindings.push((
+ RenderTypeId::AssociatedType(name),
+ vec![RenderType {
+ id: Some(RenderTypeId::Index(idx)),
+ generics: None,
+ bindings: None,
+ }],
+ ))
+ }
+ }
}
- let id = get_index_type_id(&arg);
+ let id = get_index_type_id(&arg, rgen);
if id.is_some() || !ty_generics.is_empty() {
res.push(RenderType {
id,
+ bindings: if ty_bindings.is_empty() { None } else { Some(ty_bindings) },
generics: if ty_generics.is_empty() { None } else { Some(ty_generics) },
});
}
}
}
+fn simplify_fn_binding<'tcx, 'a>(
+ self_: Option<&'a Type>,
+ generics: &Generics,
+ binding: &'a clean::TypeBinding,
+ tcx: TyCtxt<'tcx>,
+ recurse: usize,
+ res: &mut Vec<(RenderTypeId, Vec<RenderType>)>,
+ rgen: &mut FxHashMap<SimplifiedParam, (isize, Vec<RenderType>)>,
+ is_return: bool,
+ cache: &Cache,
+) {
+ let mut ty_binding_constraints = Vec::new();
+ let ty_binding_assoc = RenderTypeId::AssociatedType(binding.assoc.name);
+ for gen in &binding.assoc.args {
+ match gen {
+ clean::GenericArg::Type(arg) => simplify_fn_type(
+ self_,
+ generics,
+ &arg,
+ tcx,
+ recurse + 1,
+ &mut ty_binding_constraints,
+ rgen,
+ is_return,
+ cache,
+ ),
+ clean::GenericArg::Lifetime(_)
+ | clean::GenericArg::Const(_)
+ | clean::GenericArg::Infer => {}
+ }
+ }
+ for binding in binding.assoc.args.bindings() {
+ simplify_fn_binding(
+ self_,
+ generics,
+ &binding,
+ tcx,
+ recurse + 1,
+ res,
+ rgen,
+ is_return,
+ cache,
+ );
+ }
+ match &binding.kind {
+ clean::TypeBindingKind::Equality { term } => {
+ if let clean::Term::Type(arg) = &term {
+ simplify_fn_type(
+ self_,
+ generics,
+ arg,
+ tcx,
+ recurse + 1,
+ &mut ty_binding_constraints,
+ rgen,
+ is_return,
+ cache,
+ );
+ }
+ }
+ clean::TypeBindingKind::Constraint { bounds } => {
+ for bound in &bounds[..] {
+ if let Some(path) = bound.get_trait_path() {
+ let ty = Type::Path { path };
+ simplify_fn_type(
+ self_,
+ generics,
+ &ty,
+ tcx,
+ recurse + 1,
+ &mut ty_binding_constraints,
+ rgen,
+ is_return,
+ cache,
+ );
+ }
+ }
+ }
+ }
+ res.push((ty_binding_assoc, ty_binding_constraints));
+}
+
/// 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
@@ -700,13 +1003,15 @@ fn simplify_fn_type<'tcx, 'a>(
fn get_fn_inputs_and_outputs<'tcx>(
func: &Function,
tcx: TyCtxt<'tcx>,
- impl_generics: Option<&(clean::Type, clean::Generics)>,
+ impl_or_trait_generics: Option<&(clean::Type, clean::Generics)>,
cache: &Cache,
) -> (Vec<RenderType>, Vec<RenderType>, Vec<Vec<RenderType>>) {
let decl = &func.decl;
+ let mut rgen: FxHashMap<SimplifiedParam, (isize, Vec<RenderType>)> = Default::default();
+
let combined_generics;
- let (self_, generics) = if let Some((impl_self, impl_generics)) = impl_generics {
+ let (self_, generics) = if let Some((impl_self, impl_generics)) = impl_or_trait_generics {
match (impl_generics.is_empty(), func.generics.is_empty()) {
(true, _) => (Some(impl_self), &func.generics),
(_, true) => (Some(impl_self), impl_generics),
@@ -728,8 +1033,6 @@ fn get_fn_inputs_and_outputs<'tcx>(
(None, &func.generics)
};
- let mut rgen: FxHashMap<SimplifiedParam, (isize, Vec<RenderType>)> = Default::default();
-
let mut arg_types = Vec::new();
for arg in decl.inputs.values.iter() {
simplify_fn_type(