Cache hir_owner_nodes in ParentHirIterator.

This commit is contained in:
Camille GILLOT 2024-07-06 11:49:52 +00:00
parent f6fa358a18
commit 0184c6f52e

View File

@ -31,9 +31,18 @@ pub struct Map<'hir> {
/// An iterator that walks up the ancestor tree of a given `HirId`. /// An iterator that walks up the ancestor tree of a given `HirId`.
/// Constructed using `tcx.hir().parent_iter(hir_id)`. /// Constructed using `tcx.hir().parent_iter(hir_id)`.
pub struct ParentHirIterator<'hir> { struct ParentHirIterator<'hir> {
current_id: HirId, current_id: HirId,
map: Map<'hir>, map: Map<'hir>,
// Cache the current value of `hir_owner_nodes` to avoid repeatedly calling the same query for
// the same owner, which will uselessly record many times the same query dependency.
current_owner_nodes: Option<&'hir OwnerNodes<'hir>>,
}
impl<'hir> ParentHirIterator<'hir> {
fn new(map: Map<'hir>, current_id: HirId) -> ParentHirIterator<'hir> {
ParentHirIterator { current_id, map, current_owner_nodes: None }
}
} }
impl<'hir> Iterator for ParentHirIterator<'hir> { impl<'hir> Iterator for ParentHirIterator<'hir> {
@ -44,13 +53,22 @@ fn next(&mut self) -> Option<Self::Item> {
return None; return None;
} }
// There are nodes that do not have entries, so we need to skip them. let HirId { owner, local_id } = self.current_id;
let parent_id = self.map.tcx.parent_hir_id(self.current_id);
if parent_id == self.current_id { let parent_id = if local_id == ItemLocalId::ZERO {
self.current_id = CRATE_HIR_ID; // We go from an owner to its parent, so clear the cache.
return None; self.current_owner_nodes = None;
} self.map.tcx.hir_owner_parent(owner)
} else {
let owner_nodes =
self.current_owner_nodes.get_or_insert_with(|| self.map.tcx.hir_owner_nodes(owner));
let parent_local_id = owner_nodes.nodes[local_id].parent;
// HIR indexing should have checked that.
debug_assert_ne!(parent_local_id, local_id);
HirId { owner, local_id: parent_local_id }
};
debug_assert_ne!(parent_id, self.current_id);
self.current_id = parent_id; self.current_id = parent_id;
return Some(parent_id); return Some(parent_id);
@ -479,7 +497,7 @@ pub fn try_par_for_each_module(
/// until the crate root is reached. Prefer this over your own loop using `parent_id`. /// until the crate root is reached. Prefer this over your own loop using `parent_id`.
#[inline] #[inline]
pub fn parent_id_iter(self, current_id: HirId) -> impl Iterator<Item = HirId> + 'hir { pub fn parent_id_iter(self, current_id: HirId) -> impl Iterator<Item = HirId> + 'hir {
ParentHirIterator { current_id, map: self } ParentHirIterator::new(self, current_id)
} }
/// Returns an iterator for the nodes in the ancestor tree of the `current_id` /// Returns an iterator for the nodes in the ancestor tree of the `current_id`