rustc_middle/hir/
mod.rs

1//! HIR datatypes. See the [rustc dev guide] for more info.
2//!
3//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/hir.html
4
5pub mod map;
6pub mod nested_filter;
7pub mod place;
8
9use rustc_data_structures::fingerprint::Fingerprint;
10use rustc_data_structures::sorted_map::SortedMap;
11use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
12use rustc_data_structures::sync::{DynSend, DynSync, try_par_for_each_in};
13use rustc_hir::def::DefKind;
14use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId};
15use rustc_hir::*;
16use rustc_macros::{Decodable, Encodable, HashStable};
17use rustc_span::{ErrorGuaranteed, ExpnId};
18
19use crate::query::Providers;
20use crate::ty::{EarlyBinder, ImplSubject, TyCtxt};
21
22/// Gather the LocalDefId for each item-like within a module, including items contained within
23/// bodies. The Ids are in visitor order. This is used to partition a pass between modules.
24#[derive(Debug, HashStable, Encodable, Decodable)]
25pub struct ModuleItems {
26    submodules: Box<[OwnerId]>,
27    free_items: Box<[ItemId]>,
28    trait_items: Box<[TraitItemId]>,
29    impl_items: Box<[ImplItemId]>,
30    foreign_items: Box<[ForeignItemId]>,
31    opaques: Box<[LocalDefId]>,
32    body_owners: Box<[LocalDefId]>,
33    nested_bodies: Box<[LocalDefId]>,
34}
35
36impl ModuleItems {
37    /// Returns all non-associated locally defined items in all modules.
38    ///
39    /// Note that this does *not* include associated items of `impl` blocks! It also does not
40    /// include foreign items. If you want to e.g. get all functions, use `definitions()` below.
41    ///
42    /// However, this does include the `impl` blocks themselves.
43    pub fn free_items(&self) -> impl Iterator<Item = ItemId> + '_ {
44        self.free_items.iter().copied()
45    }
46
47    pub fn trait_items(&self) -> impl Iterator<Item = TraitItemId> + '_ {
48        self.trait_items.iter().copied()
49    }
50
51    /// Returns all items that are associated with some `impl` block (both inherent and trait impl
52    /// blocks).
53    pub fn impl_items(&self) -> impl Iterator<Item = ImplItemId> + '_ {
54        self.impl_items.iter().copied()
55    }
56
57    pub fn foreign_items(&self) -> impl Iterator<Item = ForeignItemId> + '_ {
58        self.foreign_items.iter().copied()
59    }
60
61    pub fn owners(&self) -> impl Iterator<Item = OwnerId> + '_ {
62        self.free_items
63            .iter()
64            .map(|id| id.owner_id)
65            .chain(self.trait_items.iter().map(|id| id.owner_id))
66            .chain(self.impl_items.iter().map(|id| id.owner_id))
67            .chain(self.foreign_items.iter().map(|id| id.owner_id))
68    }
69
70    pub fn opaques(&self) -> impl Iterator<Item = LocalDefId> + '_ {
71        self.opaques.iter().copied()
72    }
73
74    pub fn nested_bodies(&self) -> impl Iterator<Item = LocalDefId> + '_ {
75        self.nested_bodies.iter().copied()
76    }
77
78    pub fn definitions(&self) -> impl Iterator<Item = LocalDefId> + '_ {
79        self.owners().map(|id| id.def_id)
80    }
81
82    pub fn par_items(
83        &self,
84        f: impl Fn(ItemId) -> Result<(), ErrorGuaranteed> + DynSend + DynSync,
85    ) -> Result<(), ErrorGuaranteed> {
86        try_par_for_each_in(&self.free_items[..], |&id| f(id))
87    }
88
89    pub fn par_trait_items(
90        &self,
91        f: impl Fn(TraitItemId) -> Result<(), ErrorGuaranteed> + DynSend + DynSync,
92    ) -> Result<(), ErrorGuaranteed> {
93        try_par_for_each_in(&self.trait_items[..], |&id| f(id))
94    }
95
96    pub fn par_impl_items(
97        &self,
98        f: impl Fn(ImplItemId) -> Result<(), ErrorGuaranteed> + DynSend + DynSync,
99    ) -> Result<(), ErrorGuaranteed> {
100        try_par_for_each_in(&self.impl_items[..], |&id| f(id))
101    }
102
103    pub fn par_foreign_items(
104        &self,
105        f: impl Fn(ForeignItemId) -> Result<(), ErrorGuaranteed> + DynSend + DynSync,
106    ) -> Result<(), ErrorGuaranteed> {
107        try_par_for_each_in(&self.foreign_items[..], |&id| f(id))
108    }
109
110    pub fn par_opaques(
111        &self,
112        f: impl Fn(LocalDefId) -> Result<(), ErrorGuaranteed> + DynSend + DynSync,
113    ) -> Result<(), ErrorGuaranteed> {
114        try_par_for_each_in(&self.opaques[..], |&id| f(id))
115    }
116}
117
118impl<'tcx> TyCtxt<'tcx> {
119    #[inline(always)]
120    pub fn hir(self) -> map::Map<'tcx> {
121        map::Map { tcx: self }
122    }
123
124    pub fn parent_module(self, id: HirId) -> LocalModDefId {
125        if !id.is_owner() && self.def_kind(id.owner) == DefKind::Mod {
126            LocalModDefId::new_unchecked(id.owner.def_id)
127        } else {
128            self.parent_module_from_def_id(id.owner.def_id)
129        }
130    }
131
132    pub fn parent_module_from_def_id(self, mut id: LocalDefId) -> LocalModDefId {
133        while let Some(parent) = self.opt_local_parent(id) {
134            id = parent;
135            if self.def_kind(id) == DefKind::Mod {
136                break;
137            }
138        }
139        LocalModDefId::new_unchecked(id)
140    }
141
142    pub fn impl_subject(self, def_id: DefId) -> EarlyBinder<'tcx, ImplSubject<'tcx>> {
143        match self.impl_trait_ref(def_id) {
144            Some(t) => t.map_bound(ImplSubject::Trait),
145            None => self.type_of(def_id).map_bound(ImplSubject::Inherent),
146        }
147    }
148
149    /// Returns `true` if this is a foreign item (i.e., linked via `extern { ... }`).
150    pub fn is_foreign_item(self, def_id: impl Into<DefId>) -> bool {
151        self.opt_parent(def_id.into())
152            .is_some_and(|parent| matches!(self.def_kind(parent), DefKind::ForeignMod))
153    }
154
155    pub fn hash_owner_nodes(
156        self,
157        node: OwnerNode<'_>,
158        bodies: &SortedMap<ItemLocalId, &Body<'_>>,
159        attrs: &SortedMap<ItemLocalId, &[Attribute]>,
160    ) -> (Option<Fingerprint>, Option<Fingerprint>) {
161        if self.needs_crate_hash() {
162            self.with_stable_hashing_context(|mut hcx| {
163                let mut stable_hasher = StableHasher::new();
164                node.hash_stable(&mut hcx, &mut stable_hasher);
165                // Bodies are stored out of line, so we need to pull them explicitly in the hash.
166                bodies.hash_stable(&mut hcx, &mut stable_hasher);
167                let h1 = stable_hasher.finish();
168
169                let mut stable_hasher = StableHasher::new();
170                attrs.hash_stable(&mut hcx, &mut stable_hasher);
171                let h2 = stable_hasher.finish();
172                (Some(h1), Some(h2))
173            })
174        } else {
175            (None, None)
176        }
177    }
178}
179
180pub fn provide(providers: &mut Providers) {
181    providers.hir_crate_items = map::hir_crate_items;
182    providers.crate_hash = map::crate_hash;
183    providers.hir_module_items = map::hir_module_items;
184    providers.local_def_id_to_hir_id = |tcx, def_id| match tcx.hir_crate(()).owners[def_id] {
185        MaybeOwner::Owner(_) => HirId::make_owner(def_id),
186        MaybeOwner::NonOwner(hir_id) => hir_id,
187        MaybeOwner::Phantom => bug!("No HirId for {:?}", def_id),
188    };
189    providers.opt_hir_owner_nodes =
190        |tcx, id| tcx.hir_crate(()).owners.get(id)?.as_owner().map(|i| &i.nodes);
191    providers.hir_owner_parent = |tcx, owner_id| {
192        tcx.opt_local_parent(owner_id.def_id).map_or(CRATE_HIR_ID, |parent_def_id| {
193            let parent_owner_id = tcx.local_def_id_to_hir_id(parent_def_id).owner;
194            HirId {
195                owner: parent_owner_id,
196                local_id: tcx.hir_crate(()).owners[parent_owner_id.def_id]
197                    .unwrap()
198                    .parenting
199                    .get(&owner_id.def_id)
200                    .copied()
201                    .unwrap_or(ItemLocalId::ZERO),
202            }
203        })
204    };
205    providers.hir_attrs = |tcx, id| {
206        tcx.hir_crate(()).owners[id.def_id].as_owner().map_or(AttributeMap::EMPTY, |o| &o.attrs)
207    };
208    providers.def_span = |tcx, def_id| tcx.hir().span(tcx.local_def_id_to_hir_id(def_id));
209    providers.def_ident_span = |tcx, def_id| {
210        let hir_id = tcx.local_def_id_to_hir_id(def_id);
211        tcx.hir().opt_ident_span(hir_id)
212    };
213    providers.fn_arg_names = |tcx, def_id| {
214        let hir = tcx.hir();
215        if let Some(body_id) = tcx.hir_node_by_def_id(def_id).body_id() {
216            tcx.arena.alloc_from_iter(hir.body_param_names(body_id))
217        } else if let Node::TraitItem(&TraitItem {
218            kind: TraitItemKind::Fn(_, TraitFn::Required(idents)),
219            ..
220        })
221        | Node::ForeignItem(&ForeignItem {
222            kind: ForeignItemKind::Fn(_, idents, _),
223            ..
224        }) = tcx.hir_node(tcx.local_def_id_to_hir_id(def_id))
225        {
226            idents
227        } else {
228            span_bug!(
229                hir.span(tcx.local_def_id_to_hir_id(def_id)),
230                "fn_arg_names: unexpected item {:?}",
231                def_id
232            );
233        }
234    };
235    providers.all_local_trait_impls = |tcx, ()| &tcx.resolutions(()).trait_impls;
236    providers.expn_that_defined =
237        |tcx, id| tcx.resolutions(()).expn_that_defined.get(&id).copied().unwrap_or(ExpnId::root());
238    providers.in_scope_traits_map = |tcx, id| {
239        tcx.hir_crate(()).owners[id.def_id].as_owner().map(|owner_info| &owner_info.trait_map)
240    };
241}