@@ -31,9 +31,18 @@ pub struct Map<'hir> {
31
31
32
32
/// An iterator that walks up the ancestor tree of a given `HirId`.
33
33
/// Constructed using `tcx.hir().parent_iter(hir_id)`.
34
- pub struct ParentHirIterator < ' hir > {
34
+ struct ParentHirIterator < ' hir > {
35
35
current_id : HirId ,
36
36
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
+ }
37
46
}
38
47
39
48
impl < ' hir > Iterator for ParentHirIterator < ' hir > {
@@ -44,13 +53,22 @@ impl<'hir> Iterator for ParentHirIterator<'hir> {
44
53
return None ;
45
54
}
46
55
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 ;
49
57
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) ;
54
72
55
73
self . current_id = parent_id;
56
74
return Some ( parent_id) ;
@@ -479,7 +497,7 @@ impl<'hir> Map<'hir> {
479
497
/// until the crate root is reached. Prefer this over your own loop using `parent_id`.
480
498
#[ inline]
481
499
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 )
483
501
}
484
502
485
503
/// Returns an iterator for the nodes in the ancestor tree of the `current_id`
0 commit comments