rustdoc: also index impl trait

This commit is contained in:
Michael Howell 2022-05-31 11:12:02 -07:00
parent 16a0d03698
commit 59d35d6e90
4 changed files with 100 additions and 6 deletions

View File

@ -1667,6 +1667,10 @@ impl Type {
matches!(self, Type::Generic(_))
}
pub(crate) fn is_impl_trait(&self) -> bool {
matches!(self, Type::ImplTrait(_))
}
pub(crate) fn is_primitive(&self) -> bool {
self.primitive_type().is_some()
}

View File

@ -226,7 +226,7 @@ fn get_index_type_name(clean_type: &clean::Type) -> Option<Symbol> {
Some(path.segments.last().unwrap().name)
}
// We return an empty name because we don't care about the generic name itself.
clean::Generic(_) => Some(kw::Empty),
clean::Generic(_) | clean::ImplTrait(_) => Some(kw::Empty),
clean::Primitive(ref p) => Some(p.as_sym()),
clean::BorrowedRef { ref type_, .. } => get_index_type_name(type_),
clean::BareFunction(_)
@ -235,8 +235,7 @@ fn get_index_type_name(clean_type: &clean::Type) -> Option<Symbol> {
| clean::Array(_, _)
| clean::RawPointer(_, _)
| clean::QPath { .. }
| clean::Infer
| clean::ImplTrait(_) => None,
| clean::Infer => None,
}
}
@ -264,10 +263,12 @@ fn add_generics_and_bounds_as_types<'tcx, 'a>(
mut generics: Vec<TypeWithKind>,
cache: &Cache,
) {
let is_full_generic = ty.is_full_generic();
// generics and impl trait are both identified by their generics,
// rather than a type name itself
let anonymous = ty.is_full_generic() || ty.is_impl_trait();
let generics_empty = generics.is_empty();
if is_full_generic {
if anonymous {
if generics_empty {
// This is a type parameter with no trait bounds (for example: `T` in
// `fn f<T>(p: T)`, so not useful for the rustdoc search because we would end up
@ -318,7 +319,7 @@ fn add_generics_and_bounds_as_types<'tcx, 'a>(
if index_ty.name.as_ref().map(|s| s.is_empty() && generics_empty).unwrap_or(true) {
return;
}
if is_full_generic {
if anonymous {
// 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)));
@ -398,6 +399,23 @@ fn add_generics_and_bounds_as_types<'tcx, 'a>(
}
insert_ty(res, tcx, arg.clone(), ty_generics, cache);
}
} else if let Type::ImplTrait(ref bounds) = *arg {
let mut ty_generics = Vec::new();
for bound in bounds {
if let Some(path) = bound.get_trait_path() {
let ty = Type::Path { path };
add_generics_and_bounds_as_types(
self_,
generics,
&ty,
tcx,
recurse + 1,
&mut ty_generics,
cache,
);
}
}
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
// looking at `Option`, we enter this "else" condition, otherwise if it's `T`, we don't.

View File

@ -0,0 +1,51 @@
// ignore-order
const QUERY = [
'Aaaaaaa -> i32',
'Aaaaaaa -> Aaaaaaa',
'Aaaaaaa -> usize',
'-> Aaaaaaa',
'Aaaaaaa',
];
const EXPECTED = [
{
// Aaaaaaa -> i32
'others': [
{ 'path': 'impl_trait::Ccccccc', 'name': 'eeeeeee' },
],
},
{
// Aaaaaaa -> Aaaaaaa
'others': [
{ 'path': 'impl_trait::Ccccccc', 'name': 'fffffff' },
],
},
{
// Aaaaaaa -> usize
'others': [],
},
{
// -> Aaaaaaa
'others': [
{ 'path': 'impl_trait::Ccccccc', 'name': 'fffffff' },
{ 'path': 'impl_trait::Ccccccc', 'name': 'ddddddd' },
{ 'path': 'impl_trait', 'name': 'bbbbbbb' },
],
},
{
// Aaaaaaa
'others': [
{ 'path': 'impl_trait', 'name': 'Aaaaaaa' },
],
'in_args': [
{ 'path': 'impl_trait::Ccccccc', 'name': 'fffffff' },
{ 'path': 'impl_trait::Ccccccc', 'name': 'eeeeeee' },
],
'returned': [
{ 'path': 'impl_trait::Ccccccc', 'name': 'fffffff' },
{ 'path': 'impl_trait::Ccccccc', 'name': 'ddddddd' },
{ 'path': 'impl_trait', 'name': 'bbbbbbb' },
],
},
];

View File

@ -0,0 +1,21 @@
pub trait Aaaaaaa {}
impl Aaaaaaa for () {}
pub fn bbbbbbb() -> impl Aaaaaaa {
()
}
pub struct Ccccccc {}
impl Ccccccc {
pub fn ddddddd(&self) -> impl Aaaaaaa {
()
}
pub fn eeeeeee(&self, _x: impl Aaaaaaa) -> i32 {
0
}
pub fn fffffff(&self, x: impl Aaaaaaa) -> impl Aaaaaaa {
x
}
}