@@ -31,9 +31,18 @@ pub struct Map<'hir> {
3131
3232/// An iterator that walks up the ancestor tree of a given `HirId`.
3333/// Constructed using `tcx.hir().parent_iter(hir_id)`.
34- pub struct ParentHirIterator < ' hir > {
34+ struct ParentHirIterator < ' hir > {
3535 current_id : HirId ,
3636 map : Map < ' hir > ,
37+ // Cache the current value of `hir_owner_nodes` to avoid repeatedly calling the same query for
38+ // the same owner, which will uselessly record many times the same query dependency.
39+ current_owner_nodes : Option < & ' hir OwnerNodes < ' hir > > ,
40+ }
41+
42+ impl < ' hir > ParentHirIterator < ' hir > {
43+ fn new ( map : Map < ' hir > , current_id : HirId ) -> ParentHirIterator < ' hir > {
44+ ParentHirIterator { current_id, map, current_owner_nodes : None }
45+ }
3746}
3847
3948impl < ' hir > Iterator for ParentHirIterator < ' hir > {
@@ -44,13 +53,22 @@ impl<'hir> Iterator for ParentHirIterator<'hir> {
4453 return None ;
4554 }
4655
47- // There are nodes that do not have entries, so we need to skip them.
48- let parent_id = self . map . tcx . parent_hir_id ( self . current_id ) ;
56+ let HirId { owner, local_id } = self . current_id ;
4957
50- if parent_id == self . current_id {
51- self . current_id = CRATE_HIR_ID ;
52- return None ;
53- }
58+ let parent_id = if local_id == ItemLocalId :: ZERO {
59+ // We go from an owner to its parent, so clear the cache.
60+ self . current_owner_nodes = None ;
61+ self . map . tcx . hir_owner_parent ( owner)
62+ } else {
63+ let owner_nodes =
64+ self . current_owner_nodes . get_or_insert_with ( || self . map . tcx . hir_owner_nodes ( owner) ) ;
65+ let parent_local_id = owner_nodes. nodes [ local_id] . parent ;
66+ // HIR indexing should have checked that.
67+ debug_assert_ne ! ( parent_local_id, local_id) ;
68+ HirId { owner, local_id : parent_local_id }
69+ } ;
70+
71+ debug_assert_ne ! ( parent_id, self . current_id) ;
5472
5573 self . current_id = parent_id;
5674 return Some ( parent_id) ;
@@ -479,7 +497,7 @@ impl<'hir> Map<'hir> {
479497 /// until the crate root is reached. Prefer this over your own loop using `parent_id`.
480498 #[ inline]
481499 pub fn parent_id_iter ( self , current_id : HirId ) -> impl Iterator < Item = HirId > + ' hir {
482- ParentHirIterator { current_id , map : self }
500+ ParentHirIterator :: new ( self , current_id )
483501 }
484502
485503 /// Returns an iterator for the nodes in the ancestor tree of the `current_id`
0 commit comments