Skip to content

Commit

Permalink
rustdoc-search: add support for associated types
Browse files Browse the repository at this point in the history
  • Loading branch information
notriddle committed Nov 20, 2023
1 parent 9a66e44 commit 63c5071
Show file tree
Hide file tree
Showing 21 changed files with 1,383 additions and 117 deletions.
44 changes: 44 additions & 0 deletions src/librustdoc/clean/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1651,6 +1651,13 @@ impl Type {
}
}

pub(crate) fn generic_args(&self) -> Option<&GenericArgs> {
match self {
Type::Path { path, .. } => path.generic_args(),
_ => None,
}
}

pub(crate) fn generics(&self) -> Option<Vec<&Type>> {
match self {
Type::Path { path, .. } => path.generics(),
Expand Down Expand Up @@ -2191,6 +2198,10 @@ impl Path {
}
}

pub(crate) fn generic_args(&self) -> Option<&GenericArgs> {
self.segments.last().map(|seg| &seg.args)
}

pub(crate) fn generics(&self) -> Option<Vec<&Type>> {
self.segments.last().and_then(|seg| {
if let GenericArgs::AngleBracketed { ref args, .. } = seg.args {
Expand Down Expand Up @@ -2232,6 +2243,39 @@ impl GenericArgs {
GenericArgs::Parenthesized { inputs, output } => inputs.is_empty() && output.is_none(),
}
}
pub(crate) fn bindings<'a>(&'a self) -> Box<dyn Iterator<Item = TypeBinding> + 'a> {
match self {
&GenericArgs::AngleBracketed { ref bindings, .. } => Box::new(bindings.iter().cloned()),
&GenericArgs::Parenthesized { ref output, .. } => Box::new(
output
.as_ref()
.map(|ty| TypeBinding {
assoc: PathSegment {
name: sym::Output,
args: GenericArgs::AngleBracketed {
args: Vec::new().into_boxed_slice(),
bindings: ThinVec::new(),
},
},
kind: TypeBindingKind::Equality { term: Term::Type((**ty).clone()) },
})
.into_iter(),
),
}
}
}

impl<'a> IntoIterator for &'a GenericArgs {
type IntoIter = Box<dyn Iterator<Item = GenericArg> + 'a>;
type Item = GenericArg;
fn into_iter(self) -> Self::IntoIter {
match self {
&GenericArgs::AngleBracketed { ref args, .. } => Box::new(args.iter().cloned()),
&GenericArgs::Parenthesized { ref inputs, .. } => {
Box::new(inputs.iter().cloned().map(GenericArg::Type))
}
}
}
}

#[derive(Clone, PartialEq, Eq, Debug, Hash)]
Expand Down
1 change: 1 addition & 0 deletions src/librustdoc/formats/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,7 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
&item,
self.tcx,
clean_impl_generics(self.cache.parent_stack.last()).as_ref(),
parent,
self.cache,
),
aliases: item.attrs.get_doc_aliases(),
Expand Down
2 changes: 2 additions & 0 deletions src/librustdoc/formats/item_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ pub(crate) enum ItemType {
ProcAttribute = 23,
ProcDerive = 24,
TraitAlias = 25,
// This number is reserved for use in JavaScript
// Generic = 26,
}

impl Serialize for ItemType {
Expand Down
39 changes: 34 additions & 5 deletions src/librustdoc/html/render/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ pub(crate) struct IndexItem {
pub(crate) struct RenderType {
id: Option<RenderTypeId>,
generics: Option<Vec<RenderType>>,
bindings: Option<Vec<(RenderTypeId, Vec<RenderType>)>>,
}

impl Serialize for RenderType {
Expand All @@ -129,24 +130,47 @@ impl Serialize for RenderType {
Some(RenderTypeId::Index(idx)) => *idx,
_ => panic!("must convert render types to indexes before serializing"),
};
if let Some(generics) = &self.generics {
if self.generics.is_some() || self.bindings.is_some() {
let mut seq = serializer.serialize_seq(None)?;
seq.serialize_element(&id)?;
seq.serialize_element(generics)?;
seq.serialize_element(self.generics.as_ref().map(Vec::as_slice).unwrap_or_default())?;
if self.bindings.is_some() {
seq.serialize_element(
self.bindings.as_ref().map(Vec::as_slice).unwrap_or_default(),
)?;
}
seq.end()
} else {
id.serialize(serializer)
}
}
}

#[derive(Clone, Debug)]
#[derive(Clone, Copy, Debug)]
pub(crate) enum RenderTypeId {
DefId(DefId),
Primitive(clean::PrimitiveType),
AssociatedType(Symbol),
Index(isize),
}

impl Serialize for RenderTypeId {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let id = match &self {
// 0 is a sentinel, everything else is one-indexed
// concrete type
RenderTypeId::Index(idx) if *idx >= 0 => idx + 1,
// generic type parameter
RenderTypeId::Index(idx) => *idx,
_ => panic!("must convert render types to indexes before serializing"),
};
id.serialize(serializer)
}
}

/// Full type of functions/methods in the search index.
#[derive(Debug)]
pub(crate) struct IndexItemFunctionType {
Expand All @@ -171,17 +195,22 @@ impl Serialize for IndexItemFunctionType {
} else {
let mut seq = serializer.serialize_seq(None)?;
match &self.inputs[..] {
[one] if one.generics.is_none() => seq.serialize_element(one)?,
[one] if one.generics.is_none() && one.bindings.is_none() => {
seq.serialize_element(one)?
}
_ => seq.serialize_element(&self.inputs)?,
}
match &self.output[..] {
[] if self.where_clause.is_empty() => {}
[one] if one.generics.is_none() => seq.serialize_element(one)?,
[one] if one.generics.is_none() && one.bindings.is_none() => {
seq.serialize_element(one)?
}
_ => seq.serialize_element(&self.output)?,
}
for constraint in &self.where_clause {
if let [one] = &constraint[..]
&& one.generics.is_none()
&& one.bindings.is_none()
{
seq.serialize_element(one)?;
} else {
Expand Down
Loading

0 comments on commit 63c5071

Please sign in to comment.