@@ -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+ }
0 commit comments