@@ -94,10 +94,7 @@ pub(crate) struct Cache {
94
94
95
95
// Private fields only used when initially crawling a crate to build a cache
96
96
stack: Vec<Symbol>,
97
- parent_stack : Vec < DefId > ,
98
- impl_generics_stack : Vec < ( clean:: Type , clean:: Generics ) > ,
99
- parent_is_trait_impl : bool ,
100
- parent_is_blanket_or_auto_impl : bool ,
97
+ parent_stack: Vec<ParentStackItem>,
101
98
stripped_mod: bool,
102
99
103
100
pub(crate) search_index: Vec<IndexItem>,
@@ -263,7 +260,11 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
263
260
let (parent, is_inherent_impl_item) = match *item.kind {
264
261
clean::StrippedItem(..) => ((None, None), false),
265
262
clean::AssocConstItem(..) | clean::AssocTypeItem(..)
266
- 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()) =>
267
268
{
268
269
// skip associated items in trait impls
269
270
((None, None), false)
@@ -274,7 +275,14 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
274
275
| clean::StructFieldItem(..)
275
276
| clean::VariantItem(..) => (
276
277
(
277
- 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
+ ),
278
286
Some(&self.cache.stack[..self.cache.stack.len() - 1]),
279
287
),
280
288
false,
@@ -284,16 +292,19 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
284
292
((None, None), false)
285
293
} else {
286
294
let last = self.cache.parent_stack.last().expect("parent_stack is empty 2");
287
- let did = * last;
288
- 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)) {
289
300
// The current stack not necessarily has correlation
290
301
// for where the type was defined. On the other
291
302
// hand, `paths` always has the right
292
303
// information if present.
293
304
Some(&(ref fqp, _)) => Some(&fqp[..fqp.len() - 1]),
294
305
None => None,
295
306
};
296
- ( ( Some ( * last ) , path) , true )
307
+ ((did , path), true)
297
308
}
298
309
}
299
310
_ => ((None, Some(&*self.cache.stack)), false),
@@ -320,8 +331,7 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
320
331
search_type: get_function_type_for_search(
321
332
&item,
322
333
self.tcx,
323
- self . cache . impl_generics_stack . last ( ) ,
324
- self . cache . parent_is_blanket_or_auto_impl ,
334
+ clean_impl_generics(self.cache.parent_stack.last()).as_ref(),
325
335
self.cache,
326
336
),
327
337
aliases: item.attrs.get_doc_aliases(),
@@ -331,11 +341,11 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
331
341
(Some(parent), None) if is_inherent_impl_item => {
332
342
// We have a parent, but we don't know where they're
333
343
// defined yet. Wait for later to index this item.
344
+ let impl_generics = clean_impl_generics(self.cache.parent_stack.last());
334
345
self.cache.orphan_impl_items.push(OrphanImplItem {
335
346
parent,
336
347
item: item.clone(),
337
- impl_generics : self . cache . impl_generics_stack . last ( ) . cloned ( ) ,
338
- parent_is_blanket_or_auto_impl : self . cache . parent_is_blanket_or_auto_impl ,
348
+ impl_generics,
339
349
});
340
350
}
341
351
_ => {}
@@ -411,72 +421,19 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
411
421
}
412
422
}
413
423
414
- // Maintain the parent stack
415
- let orig_parent_is_trait_impl = self . cache . parent_is_trait_impl ;
416
- let parent_pushed = match * item. kind {
424
+ // Maintain the parent stack.
425
+ let (item, parent_pushed) = match *item.kind {
417
426
clean::TraitItem(..)
418
427
| clean::EnumItem(..)
419
428
| clean::ForeignTypeItem
420
429
| clean::StructItem(..)
421
430
| clean::UnionItem(..)
422
- | clean:: VariantItem ( ..) => {
423
- self . cache . parent_stack . push ( item. item_id . expect_def_id ( ) ) ;
424
- self . cache . parent_is_trait_impl = false ;
425
- true
426
- }
427
- clean:: ImplItem ( ref i) => {
428
- self . cache . parent_is_trait_impl = i. trait_ . is_some ( ) ;
429
- match i. for_ {
430
- clean:: Type :: Path { ref path } => {
431
- self . cache . parent_stack . push ( path. def_id ( ) ) ;
432
- true
433
- }
434
- clean:: DynTrait ( ref bounds, _)
435
- | clean:: BorrowedRef { type_ : box clean:: DynTrait ( ref bounds, _) , .. } => {
436
- self . cache . parent_stack . push ( bounds[ 0 ] . trait_ . def_id ( ) ) ;
437
- true
438
- }
439
- ref t => {
440
- let prim_did = t
441
- . primitive_type ( )
442
- . and_then ( |t| self . cache . primitive_locations . get ( & t) . cloned ( ) ) ;
443
- match prim_did {
444
- Some ( did) => {
445
- self . cache . parent_stack . push ( did) ;
446
- true
447
- }
448
- None => false ,
449
- }
450
- }
451
- }
452
- }
453
- _ => false ,
454
- } ;
455
-
456
- // When recursing into an impl item, make the generics context visible
457
- // to the child items.
458
- let item = {
459
- let mut item = item;
460
- let mut old_parent_is_blanket_or_auto_impl = false ;
461
- if let clean:: Item { kind : box clean:: ImplItem ( ref mut i) , .. } = item {
462
- old_parent_is_blanket_or_auto_impl = mem:: replace (
463
- & mut self . cache . parent_is_blanket_or_auto_impl ,
464
- !matches ! ( i. kind, clean:: ImplKind :: Normal ) ,
465
- ) ;
466
- self . cache . impl_generics_stack . push ( (
467
- mem:: replace ( & mut i. for_ , clean:: Type :: Infer ) ,
468
- mem:: replace (
469
- & mut i. generics ,
470
- clean:: Generics { params : Vec :: new ( ) , where_predicates : Vec :: new ( ) } ,
471
- ) ,
472
- ) ) ;
473
- }
474
- let mut item = self . fold_item_recur ( item) ;
475
- if let clean:: Item { kind : box clean:: ImplItem ( ref mut i) , .. } = item {
476
- self . cache . parent_is_blanket_or_auto_impl = old_parent_is_blanket_or_auto_impl;
477
- ( i. for_ , i. generics ) = self . cache . impl_generics_stack . pop ( ) . expect ( "pushed above" ) ;
431
+ | clean::VariantItem(..)
432
+ | clean::ImplItem(..) => {
433
+ self.cache.parent_stack.push(ParentStackItem::new(&item));
434
+ (self.fold_item_recur(item), true)
478
435
}
479
- item
436
+ _ => (self.fold_item_recur( item), false),
480
437
};
481
438
482
439
// Once we've recursively found all the generics, hoard off all the
@@ -549,7 +506,6 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
549
506
self.cache.parent_stack.pop().expect("parent stack already empty");
550
507
}
551
508
self.cache.stripped_mod = orig_stripped_mod;
552
- self . cache . parent_is_trait_impl = orig_parent_is_trait_impl;
553
509
ret
554
510
}
555
511
}
@@ -558,5 +514,56 @@ pub(crate) struct OrphanImplItem {
558
514
pub(crate) parent: DefId,
559
515
pub(crate) item: clean::Item,
560
516
pub(crate) impl_generics: Option<(clean::Type, clean::Generics)>,
561
- pub ( crate ) parent_is_blanket_or_auto_impl : bool ,
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
+ }
562
569
}
0 commit comments