hir: Introduce TyCtxt::parent_hir_{id,node}

Remove the FIXME and keep `CRATE_HIR_ID` being its own parent.
This scheme turned out to be more practical than having an `Option` on closer inspection.

Also make `hir_owner_parent` more readable.
This commit is contained in:
Vadim Petrochenkov 2024-02-09 23:58:36 +03:00
parent 68125c72d3
commit e46e3e7107
2 changed files with 34 additions and 28 deletions

View File

@ -175,6 +175,28 @@ impl<'tcx> TyCtxt<'tcx> {
self.opt_hir_node_by_def_id(id)
.unwrap_or_else(|| bug!("couldn't find HIR node for def id {id:?}"))
}
/// Returns `HirId` of the parent HIR node of node with this `hir_id`.
/// Returns the same `hir_id` if and only if `hir_id == CRATE_HIR_ID`.
///
/// If calling repeatedly and iterating over parents, prefer [`Map::parent_iter`].
pub fn parent_hir_id(self, hir_id: HirId) -> HirId {
let HirId { owner, local_id } = hir_id;
if local_id == ItemLocalId::from_u32(0) {
self.hir_owner_parent(owner)
} else {
let parent_local_id = self.hir_owner_nodes(owner).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 }
}
}
/// Returns parent HIR node of node with this `hir_id`.
/// Returns HIR node of the same `hir_id` if and only if `hir_id == CRATE_HIR_ID`.
pub fn parent_hir_node(self, hir_id: HirId) -> Node<'tcx> {
self.hir_node(self.parent_hir_id(hir_id))
}
}
impl<'hir> Map<'hir> {
@ -217,37 +239,20 @@ impl<'hir> Map<'hir> {
self.tcx.definitions_untracked().def_path_hash(def_id)
}
/// Finds the id of the parent node to this one.
///
/// If calling repeatedly and iterating over parents, prefer [`Map::parent_iter`].
pub fn opt_parent_id(self, id: HirId) -> Option<HirId> {
if id.local_id == ItemLocalId::from_u32(0) {
// FIXME: This function never returns `None` right now, and the parent chain end is
// determined by checking for `parent(id) == id`. This function should return `None`
// for the crate root instead.
Some(self.tcx.hir_owner_parent(id.owner))
} else {
let owner = self.tcx.hir_owner_nodes(id.owner);
let node = &owner.nodes[id.local_id];
let hir_id = HirId { owner: id.owner, local_id: node.parent };
// HIR indexing should have checked that.
debug_assert_ne!(id.local_id, node.parent);
Some(hir_id)
}
Some(self.tcx.parent_hir_id(id))
}
#[track_caller]
pub fn parent_id(self, hir_id: HirId) -> HirId {
self.opt_parent_id(hir_id)
.unwrap_or_else(|| bug!("No parent for node {}", self.node_to_string(hir_id)))
self.tcx.parent_hir_id(hir_id)
}
pub fn get_parent(self, hir_id: HirId) -> Node<'hir> {
self.tcx.hir_node(self.parent_id(hir_id))
self.tcx.parent_hir_node(hir_id)
}
pub fn find_parent(self, hir_id: HirId) -> Option<Node<'hir>> {
Some(self.tcx.hir_node(self.opt_parent_id(hir_id)?))
Some(self.tcx.parent_hir_node(hir_id))
}
pub fn get_if_local(self, id: DefId) -> Option<Node<'hir>> {

View File

@ -136,13 +136,14 @@ pub fn provide(providers: &mut Providers) {
};
providers.opt_hir_owner_nodes =
|tcx, id| tcx.hir_crate(()).owners.get(id)?.as_owner().map(|i| &i.nodes);
providers.hir_owner_parent = |tcx, id| {
// Accessing the local_parent is ok since its value is hashed as part of `id`'s DefPathHash.
tcx.opt_local_parent(id.def_id).map_or(CRATE_HIR_ID, |parent| {
let mut parent_hir_id = tcx.local_def_id_to_hir_id(parent);
parent_hir_id.local_id =
tcx.hir_crate(()).owners[parent_hir_id.owner.def_id].unwrap().parenting[&id.def_id];
parent_hir_id
providers.hir_owner_parent = |tcx, owner_id| {
tcx.opt_local_parent(owner_id.def_id).map_or(CRATE_HIR_ID, |parent_def_id| {
let parent_owner_id = tcx.local_def_id_to_hir_id(parent_def_id).owner;
HirId {
owner: parent_owner_id,
local_id: tcx.hir_crate(()).owners[parent_owner_id.def_id].unwrap().parenting
[&owner_id.def_id],
}
})
};
providers.hir_attrs = |tcx, id| {