Skip to content

Commit 0acc4a3

Browse files
committed
Auto merge of #96652 - notriddle:notriddle/self, r=GuillaumeGomez
rustdoc: include impl generics / self in search index Fixes #92205
2 parents 84288ed + 718269a commit 0acc4a3

File tree

5 files changed

+251
-62
lines changed

5 files changed

+251
-62
lines changed

src/librustdoc/clean/types.rs

+6
Original file line numberDiff line numberDiff line change
@@ -1410,6 +1410,12 @@ pub(crate) struct Generics {
14101410
pub(crate) where_predicates: Vec<WherePredicate>,
14111411
}
14121412

1413+
impl Generics {
1414+
pub(crate) fn is_empty(&self) -> bool {
1415+
self.params.is_empty() && self.where_predicates.is_empty()
1416+
}
1417+
}
1418+
14131419
#[derive(Clone, Debug)]
14141420
pub(crate) struct Function {
14151421
pub(crate) decl: FnDecl,

src/librustdoc/formats/cache.rs

+98-46
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,7 @@ pub(crate) struct Cache {
9494

9595
// Private fields only used when initially crawling a crate to build a cache
9696
stack: Vec<Symbol>,
97-
parent_stack: Vec<DefId>,
98-
parent_is_trait_impl: bool,
97+
parent_stack: Vec<ParentStackItem>,
9998
stripped_mod: bool,
10099

101100
pub(crate) search_index: Vec<IndexItem>,
@@ -105,7 +104,7 @@ pub(crate) struct Cache {
105104
// then the fully qualified name of the structure isn't presented in `paths`
106105
// yet when its implementation methods are being indexed. Caches such methods
107106
// and their parent id here and indexes them at the end of crate parsing.
108-
pub(crate) orphan_impl_items: Vec<(DefId, clean::Item)>,
107+
pub(crate) orphan_impl_items: Vec<OrphanImplItem>,
109108

110109
// Similarly to `orphan_impl_items`, sometimes trait impls are picked up
111110
// even though the trait itself is not exported. This can happen if a trait
@@ -261,7 +260,11 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
261260
let (parent, is_inherent_impl_item) = match *item.kind {
262261
clean::StrippedItem(..) => ((None, None), false),
263262
clean::AssocConstItem(..) | clean::AssocTypeItem(..)
264-
if self.cache.parent_is_trait_impl =>
263+
if self
264+
.cache
265+
.parent_stack
266+
.last()
267+
.map_or(false, |parent| parent.is_trait_impl()) =>
265268
{
266269
// skip associated items in trait impls
267270
((None, None), false)
@@ -272,7 +275,14 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
272275
| clean::StructFieldItem(..)
273276
| clean::VariantItem(..) => (
274277
(
275-
Some(*self.cache.parent_stack.last().expect("parent_stack is empty")),
278+
Some(
279+
self.cache
280+
.parent_stack
281+
.last()
282+
.expect("parent_stack is empty")
283+
.item_id()
284+
.expect_def_id(),
285+
),
276286
Some(&self.cache.stack[..self.cache.stack.len() - 1]),
277287
),
278288
false,
@@ -282,16 +292,19 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
282292
((None, None), false)
283293
} else {
284294
let last = self.cache.parent_stack.last().expect("parent_stack is empty 2");
285-
let did = *last;
286-
let path = match self.cache.paths.get(&did) {
295+
let did = match &*last {
296+
ParentStackItem::Impl { for_, .. } => for_.def_id(&self.cache),
297+
ParentStackItem::Type(item_id) => item_id.as_def_id(),
298+
};
299+
let path = match did.and_then(|did| self.cache.paths.get(&did)) {
287300
// The current stack not necessarily has correlation
288301
// for where the type was defined. On the other
289302
// hand, `paths` always has the right
290303
// information if present.
291304
Some(&(ref fqp, _)) => Some(&fqp[..fqp.len() - 1]),
292305
None => None,
293306
};
294-
((Some(*last), path), true)
307+
((did, path), true)
295308
}
296309
}
297310
_ => ((None, Some(&*self.cache.stack)), false),
@@ -315,15 +328,25 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
315328
desc,
316329
parent,
317330
parent_idx: None,
318-
search_type: get_function_type_for_search(&item, self.tcx, self.cache),
331+
search_type: get_function_type_for_search(
332+
&item,
333+
self.tcx,
334+
clean_impl_generics(self.cache.parent_stack.last()).as_ref(),
335+
self.cache,
336+
),
319337
aliases: item.attrs.get_doc_aliases(),
320338
});
321339
}
322340
}
323341
(Some(parent), None) if is_inherent_impl_item => {
324342
// We have a parent, but we don't know where they're
325343
// defined yet. Wait for later to index this item.
326-
self.cache.orphan_impl_items.push((parent, item.clone()));
344+
let impl_generics = clean_impl_generics(self.cache.parent_stack.last());
345+
self.cache.orphan_impl_items.push(OrphanImplItem {
346+
parent,
347+
item: item.clone(),
348+
impl_generics,
349+
});
327350
}
328351
_ => {}
329352
}
@@ -398,51 +421,23 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
398421
}
399422
}
400423

401-
// Maintain the parent stack
402-
let orig_parent_is_trait_impl = self.cache.parent_is_trait_impl;
403-
let parent_pushed = match *item.kind {
424+
// Maintain the parent stack.
425+
let (item, parent_pushed) = match *item.kind {
404426
clean::TraitItem(..)
405427
| clean::EnumItem(..)
406428
| clean::ForeignTypeItem
407429
| clean::StructItem(..)
408430
| clean::UnionItem(..)
409-
| clean::VariantItem(..) => {
410-
self.cache.parent_stack.push(item.item_id.expect_def_id());
411-
self.cache.parent_is_trait_impl = false;
412-
true
413-
}
414-
clean::ImplItem(ref i) => {
415-
self.cache.parent_is_trait_impl = i.trait_.is_some();
416-
match i.for_ {
417-
clean::Type::Path { ref path } => {
418-
self.cache.parent_stack.push(path.def_id());
419-
true
420-
}
421-
clean::DynTrait(ref bounds, _)
422-
| clean::BorrowedRef { type_: box clean::DynTrait(ref bounds, _), .. } => {
423-
self.cache.parent_stack.push(bounds[0].trait_.def_id());
424-
true
425-
}
426-
ref t => {
427-
let prim_did = t
428-
.primitive_type()
429-
.and_then(|t| self.cache.primitive_locations.get(&t).cloned());
430-
match prim_did {
431-
Some(did) => {
432-
self.cache.parent_stack.push(did);
433-
true
434-
}
435-
None => false,
436-
}
437-
}
438-
}
431+
| clean::VariantItem(..)
432+
| clean::ImplItem(..) => {
433+
self.cache.parent_stack.push(ParentStackItem::new(&item));
434+
(self.fold_item_recur(item), true)
439435
}
440-
_ => false,
436+
_ => (self.fold_item_recur(item), false),
441437
};
442438

443439
// Once we've recursively found all the generics, hoard off all the
444440
// implementations elsewhere.
445-
let item = self.fold_item_recur(item);
446441
let ret = if let clean::Item { kind: box clean::ImplItem(ref i), .. } = item {
447442
// Figure out the id of this impl. This may map to a
448443
// primitive rather than always to a struct/enum.
@@ -511,7 +506,64 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
511506
self.cache.parent_stack.pop().expect("parent stack already empty");
512507
}
513508
self.cache.stripped_mod = orig_stripped_mod;
514-
self.cache.parent_is_trait_impl = orig_parent_is_trait_impl;
515509
ret
516510
}
517511
}
512+
513+
pub(crate) struct OrphanImplItem {
514+
pub(crate) parent: DefId,
515+
pub(crate) item: clean::Item,
516+
pub(crate) impl_generics: Option<(clean::Type, clean::Generics)>,
517+
}
518+
519+
/// Information about trait and type parents is tracked while traversing the item tree to build
520+
/// the cache.
521+
///
522+
/// We don't just store `Item` in there, because `Item` contains the list of children being
523+
/// traversed and it would be wasteful to clone all that. We also need the item id, so just
524+
/// storing `ItemKind` won't work, either.
525+
enum ParentStackItem {
526+
Impl {
527+
for_: clean::Type,
528+
trait_: Option<clean::Path>,
529+
generics: clean::Generics,
530+
kind: clean::ImplKind,
531+
item_id: ItemId,
532+
},
533+
Type(ItemId),
534+
}
535+
536+
impl ParentStackItem {
537+
fn new(item: &clean::Item) -> Self {
538+
match &*item.kind {
539+
clean::ItemKind::ImplItem(clean::Impl { for_, trait_, generics, kind, .. }) => {
540+
ParentStackItem::Impl {
541+
for_: for_.clone(),
542+
trait_: trait_.clone(),
543+
generics: generics.clone(),
544+
kind: kind.clone(),
545+
item_id: item.item_id,
546+
}
547+
}
548+
_ => ParentStackItem::Type(item.item_id),
549+
}
550+
}
551+
fn is_trait_impl(&self) -> bool {
552+
matches!(self, ParentStackItem::Impl { trait_: Some(..), .. })
553+
}
554+
fn item_id(&self) -> ItemId {
555+
match self {
556+
ParentStackItem::Impl { item_id, .. } => *item_id,
557+
ParentStackItem::Type(item_id) => *item_id,
558+
}
559+
}
560+
}
561+
562+
fn clean_impl_generics(item: Option<&ParentStackItem>) -> Option<(clean::Type, clean::Generics)> {
563+
if let Some(ParentStackItem::Impl { for_, generics, kind: clean::ImplKind::Normal, .. }) = item
564+
{
565+
Some((for_.clone(), generics.clone()))
566+
} else {
567+
None
568+
}
569+
}

src/librustdoc/html/render/search_index.rs

+55-16
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use serde::ser::{Serialize, SerializeStruct, Serializer};
88

99
use crate::clean;
1010
use crate::clean::types::{FnRetTy, Function, GenericBound, Generics, Type, WherePredicate};
11-
use crate::formats::cache::Cache;
11+
use crate::formats::cache::{Cache, OrphanImplItem};
1212
use crate::formats::item_type::ItemType;
1313
use crate::html::format::join_with_double_colon;
1414
use crate::html::markdown::short_markdown_summary;
@@ -25,8 +25,8 @@ pub(crate) fn build_index<'tcx>(
2525

2626
// Attach all orphan items to the type's definition if the type
2727
// has since been learned.
28-
for &(did, ref item) in &cache.orphan_impl_items {
29-
if let Some(&(ref fqp, _)) = cache.paths.get(&did) {
28+
for &OrphanImplItem { parent, ref item, ref impl_generics } in &cache.orphan_impl_items {
29+
if let Some(&(ref fqp, _)) = cache.paths.get(&parent) {
3030
let desc = item
3131
.doc_value()
3232
.map_or_else(String::new, |s| short_markdown_summary(&s, &item.link_names(cache)));
@@ -35,9 +35,9 @@ pub(crate) fn build_index<'tcx>(
3535
name: item.name.unwrap().to_string(),
3636
path: join_with_double_colon(&fqp[..fqp.len() - 1]),
3737
desc,
38-
parent: Some(did),
38+
parent: Some(parent),
3939
parent_idx: None,
40-
search_type: get_function_type_for_search(item, tcx, cache),
40+
search_type: get_function_type_for_search(item, tcx, impl_generics.as_ref(), cache),
4141
aliases: item.attrs.get_doc_aliases(),
4242
});
4343
}
@@ -192,12 +192,13 @@ pub(crate) fn build_index<'tcx>(
192192
pub(crate) fn get_function_type_for_search<'tcx>(
193193
item: &clean::Item,
194194
tcx: TyCtxt<'tcx>,
195+
impl_generics: Option<&(clean::Type, clean::Generics)>,
195196
cache: &Cache,
196197
) -> Option<IndexItemFunctionType> {
197198
let (mut inputs, mut output) = match *item.kind {
198-
clean::FunctionItem(ref f) => get_fn_inputs_and_outputs(f, tcx, cache),
199-
clean::MethodItem(ref m, _) => get_fn_inputs_and_outputs(m, tcx, cache),
200-
clean::TyMethodItem(ref m) => get_fn_inputs_and_outputs(m, tcx, cache),
199+
clean::FunctionItem(ref f) => get_fn_inputs_and_outputs(f, tcx, impl_generics, cache),
200+
clean::MethodItem(ref m, _) => get_fn_inputs_and_outputs(m, tcx, impl_generics, cache),
201+
clean::TyMethodItem(ref m) => get_fn_inputs_and_outputs(m, tcx, impl_generics, cache),
201202
_ => return None,
202203
};
203204

@@ -247,9 +248,10 @@ fn get_index_type_name(clean_type: &clean::Type) -> Option<Symbol> {
247248
/// Important note: It goes through generics recursively. So if you have
248249
/// `T: Option<Result<(), ()>>`, it'll go into `Option` and then into `Result`.
249250
#[instrument(level = "trace", skip(tcx, res, cache))]
250-
fn add_generics_and_bounds_as_types<'tcx>(
251+
fn add_generics_and_bounds_as_types<'tcx, 'a>(
252+
self_: Option<&'a Type>,
251253
generics: &Generics,
252-
arg: &Type,
254+
arg: &'a Type,
253255
tcx: TyCtxt<'tcx>,
254256
recurse: usize,
255257
res: &mut Vec<TypeWithKind>,
@@ -334,6 +336,17 @@ fn add_generics_and_bounds_as_types<'tcx>(
334336
return;
335337
}
336338

339+
// First, check if it's "Self".
340+
let arg = if let Some(self_) = self_ {
341+
match &*arg {
342+
Type::BorrowedRef { type_, .. } if type_.is_self_type() => self_,
343+
type_ if type_.is_self_type() => self_,
344+
arg => arg,
345+
}
346+
} else {
347+
arg
348+
};
349+
337350
// If this argument is a type parameter and not a trait bound or a type, we need to look
338351
// for its bounds.
339352
if let Type::Generic(arg_s) = *arg {
@@ -350,6 +363,7 @@ fn add_generics_and_bounds_as_types<'tcx>(
350363
match &param_def.kind {
351364
clean::GenericParamDefKind::Type { default: Some(ty), .. } => {
352365
add_generics_and_bounds_as_types(
366+
self_,
353367
generics,
354368
ty,
355369
tcx,
@@ -372,6 +386,7 @@ fn add_generics_and_bounds_as_types<'tcx>(
372386
if let Some(path) = bound.get_trait_path() {
373387
let ty = Type::Path { path };
374388
add_generics_and_bounds_as_types(
389+
self_,
375390
generics,
376391
&ty,
377392
tcx,
@@ -393,6 +408,7 @@ fn add_generics_and_bounds_as_types<'tcx>(
393408
if let Some(arg_generics) = arg.generics() {
394409
for gen in arg_generics.iter() {
395410
add_generics_and_bounds_as_types(
411+
self_,
396412
generics,
397413
gen,
398414
tcx,
@@ -413,18 +429,33 @@ fn add_generics_and_bounds_as_types<'tcx>(
413429
fn get_fn_inputs_and_outputs<'tcx>(
414430
func: &Function,
415431
tcx: TyCtxt<'tcx>,
432+
impl_generics: Option<&(clean::Type, clean::Generics)>,
416433
cache: &Cache,
417434
) -> (Vec<TypeWithKind>, Vec<TypeWithKind>) {
418435
let decl = &func.decl;
419-
let generics = &func.generics;
436+
437+
let combined_generics;
438+
let (self_, generics) = if let Some(&(ref impl_self, ref impl_generics)) = impl_generics {
439+
match (impl_generics.is_empty(), func.generics.is_empty()) {
440+
(true, _) => (Some(impl_self), &func.generics),
441+
(_, true) => (Some(impl_self), impl_generics),
442+
(false, false) => {
443+
let mut params = func.generics.params.clone();
444+
params.extend(impl_generics.params.clone());
445+
let mut where_predicates = func.generics.where_predicates.clone();
446+
where_predicates.extend(impl_generics.where_predicates.clone());
447+
combined_generics = clean::Generics { params, where_predicates };
448+
(Some(impl_self), &combined_generics)
449+
}
450+
}
451+
} else {
452+
(None, &func.generics)
453+
};
420454

421455
let mut all_types = Vec::new();
422456
for arg in decl.inputs.values.iter() {
423-
if arg.type_.is_self_type() {
424-
continue;
425-
}
426457
let mut args = Vec::new();
427-
add_generics_and_bounds_as_types(generics, &arg.type_, tcx, 0, &mut args, cache);
458+
add_generics_and_bounds_as_types(self_, generics, &arg.type_, tcx, 0, &mut args, cache);
428459
if !args.is_empty() {
429460
all_types.extend(args);
430461
} else {
@@ -437,7 +468,15 @@ fn get_fn_inputs_and_outputs<'tcx>(
437468
let mut ret_types = Vec::new();
438469
match decl.output {
439470
FnRetTy::Return(ref return_type) => {
440-
add_generics_and_bounds_as_types(generics, return_type, tcx, 0, &mut ret_types, cache);
471+
add_generics_and_bounds_as_types(
472+
self_,
473+
generics,
474+
return_type,
475+
tcx,
476+
0,
477+
&mut ret_types,
478+
cache,
479+
);
441480
if ret_types.is_empty() {
442481
if let Some(kind) = return_type.def_id(cache).map(|did| tcx.def_kind(did).into()) {
443482
ret_types.push(TypeWithKind::from((get_index_type(return_type, vec![]), kind)));

0 commit comments

Comments
 (0)