@@ -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