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::lints::DelayedLint;
16use rustc_hir::*;
17use rustc_macros::{Decodable, Encodable, HashStable};
18use rustc_span::{ErrorGuaranteed, ExpnId, Span};
19
20use crate::query::Providers;
21use crate::ty::TyCtxt;
22
23/// Gather the LocalDefId for each item-like within a module, including items contained within
24/// bodies. The Ids are in visitor order. This is used to partition a pass between modules.
25#[derive(Debug, HashStable, Encodable, Decodable)]
26pub struct ModuleItems {
27    /// Whether this represents the whole crate, in which case we need to add `CRATE_OWNER_ID` to
28    /// the iterators if we want to account for the crate root.
29    add_root: bool,
30    submodules: Box<[OwnerId]>,
31    free_items: Box<[ItemId]>,
32    trait_items: Box<[TraitItemId]>,
33    impl_items: Box<[ImplItemId]>,
34    foreign_items: Box<[ForeignItemId]>,
35    opaques: Box<[LocalDefId]>,
36    body_owners: Box<[LocalDefId]>,
37    nested_bodies: Box<[LocalDefId]>,
38    // only filled with hir_crate_items, not with hir_module_items
39    delayed_lint_items: Box<[OwnerId]>,
40}
41
42impl ModuleItems {
43    /// Returns all non-associated locally defined items in all modules.
44    ///
45    /// Note that this does *not* include associated items of `impl` blocks! It also does not
46    /// include foreign items. If you want to e.g. get all functions, use `definitions()` below.
47    ///
48    /// However, this does include the `impl` blocks themselves.
49    pub fn free_items(&self) -> impl Iterator<Item = ItemId> {
50        self.free_items.iter().copied()
51    }
52
53    pub fn trait_items(&self) -> impl Iterator<Item = TraitItemId> {
54        self.trait_items.iter().copied()
55    }
56
57    pub fn delayed_lint_items(&self) -> impl Iterator<Item = OwnerId> {
58        self.delayed_lint_items.iter().copied()
59    }
60
61    /// Returns all items that are associated with some `impl` block (both inherent and trait impl
62    /// blocks).
63    pub fn impl_items(&self) -> impl Iterator<Item = ImplItemId> {
64        self.impl_items.iter().copied()
65    }
66
67    pub fn foreign_items(&self) -> impl Iterator<Item = ForeignItemId> {
68        self.foreign_items.iter().copied()
69    }
70
71    pub fn owners(&self) -> impl Iterator<Item = OwnerId> {
72        self.add_root
73            .then_some(CRATE_OWNER_ID)
74            .into_iter()
75            .chain(self.free_items.iter().map(|id| id.owner_id))
76            .chain(self.trait_items.iter().map(|id| id.owner_id))
77            .chain(self.impl_items.iter().map(|id| id.owner_id))
78            .chain(self.foreign_items.iter().map(|id| id.owner_id))
79    }
80
81    pub fn opaques(&self) -> impl Iterator<Item = LocalDefId> {
82        self.opaques.iter().copied()
83    }
84
85    /// Closures and inline consts
86    pub fn nested_bodies(&self) -> impl Iterator<Item = LocalDefId> {
87        self.nested_bodies.iter().copied()
88    }
89
90    pub fn definitions(&self) -> impl Iterator<Item = LocalDefId> {
91        self.owners().map(|id| id.def_id)
92    }
93
94    /// Closures and inline consts
95    pub fn par_nested_bodies(
96        &self,
97        f: impl Fn(LocalDefId) -> Result<(), ErrorGuaranteed> + DynSend + DynSync,
98    ) -> Result<(), ErrorGuaranteed> {
99        try_par_for_each_in(&self.nested_bodies[..], |&&id| f(id))
100    }
101
102    pub fn par_items(
103        &self,
104        f: impl Fn(ItemId) -> Result<(), ErrorGuaranteed> + DynSend + DynSync,
105    ) -> Result<(), ErrorGuaranteed> {
106        try_par_for_each_in(&self.free_items[..], |&&id| f(id))
107    }
108
109    pub fn par_trait_items(
110        &self,
111        f: impl Fn(TraitItemId) -> Result<(), ErrorGuaranteed> + DynSend + DynSync,
112    ) -> Result<(), ErrorGuaranteed> {
113        try_par_for_each_in(&self.trait_items[..], |&&id| f(id))
114    }
115
116    pub fn par_impl_items(
117        &self,
118        f: impl Fn(ImplItemId) -> Result<(), ErrorGuaranteed> + DynSend + DynSync,
119    ) -> Result<(), ErrorGuaranteed> {
120        try_par_for_each_in(&self.impl_items[..], |&&id| f(id))
121    }
122
123    pub fn par_foreign_items(
124        &self,
125        f: impl Fn(ForeignItemId) -> Result<(), ErrorGuaranteed> + DynSend + DynSync,
126    ) -> Result<(), ErrorGuaranteed> {
127        try_par_for_each_in(&self.foreign_items[..], |&&id| f(id))
128    }
129
130    pub fn par_opaques(
131        &self,
132        f: impl Fn(LocalDefId) -> Result<(), ErrorGuaranteed> + DynSend + DynSync,
133    ) -> Result<(), ErrorGuaranteed> {
134        try_par_for_each_in(&self.opaques[..], |&&id| f(id))
135    }
136}
137
138impl<'tcx> TyCtxt<'tcx> {
139    pub fn parent_module(self, id: HirId) -> LocalModDefId {
140        if !id.is_owner() && self.def_kind(id.owner) == DefKind::Mod {
141            LocalModDefId::new_unchecked(id.owner.def_id)
142        } else {
143            self.parent_module_from_def_id(id.owner.def_id)
144        }
145    }
146
147    pub fn parent_module_from_def_id(self, mut id: LocalDefId) -> LocalModDefId {
148        while let Some(parent) = self.opt_local_parent(id) {
149            id = parent;
150            if self.def_kind(id) == DefKind::Mod {
151                break;
152            }
153        }
154        LocalModDefId::new_unchecked(id)
155    }
156
157    /// Returns `true` if this is a foreign item (i.e., linked via `extern { ... }`).
158    pub fn is_foreign_item(self, def_id: impl Into<DefId>) -> bool {
159        self.opt_parent(def_id.into())
160            .is_some_and(|parent| matches!(self.def_kind(parent), DefKind::ForeignMod))
161    }
162
163    pub fn hash_owner_nodes(
164        self,
165        node: OwnerNode<'_>,
166        bodies: &SortedMap<ItemLocalId, &Body<'_>>,
167        attrs: &SortedMap<ItemLocalId, &[Attribute]>,
168        delayed_lints: &[DelayedLint],
169        define_opaque: Option<&[(Span, LocalDefId)]>,
170    ) -> Hashes {
171        if !self.needs_crate_hash() {
172            return Hashes {
173                opt_hash_including_bodies: None,
174                attrs_hash: None,
175                delayed_lints_hash: None,
176            };
177        }
178
179        self.with_stable_hashing_context(|mut hcx| {
180            let mut stable_hasher = StableHasher::new();
181            node.hash_stable(&mut hcx, &mut stable_hasher);
182            // Bodies are stored out of line, so we need to pull them explicitly in the hash.
183            bodies.hash_stable(&mut hcx, &mut stable_hasher);
184            let h1 = stable_hasher.finish();
185
186            let mut stable_hasher = StableHasher::new();
187            attrs.hash_stable(&mut hcx, &mut stable_hasher);
188
189            // Hash the defined opaque types, which are not present in the attrs.
190            define_opaque.hash_stable(&mut hcx, &mut stable_hasher);
191
192            let h2 = stable_hasher.finish();
193
194            // hash lints emitted during ast lowering
195            let mut stable_hasher = StableHasher::new();
196            delayed_lints.hash_stable(&mut hcx, &mut stable_hasher);
197            let h3 = stable_hasher.finish();
198
199            Hashes {
200                opt_hash_including_bodies: Some(h1),
201                attrs_hash: Some(h2),
202                delayed_lints_hash: Some(h3),
203            }
204        })
205    }
206}
207
208/// Hashes computed by [`TyCtxt::hash_owner_nodes`] if necessary.
209#[derive(Clone, Copy, Debug)]
210pub struct Hashes {
211    pub opt_hash_including_bodies: Option<Fingerprint>,
212    pub attrs_hash: Option<Fingerprint>,
213    pub delayed_lints_hash: Option<Fingerprint>,
214}
215
216pub fn provide(providers: &mut Providers) {
217    providers.hir_crate_items = map::hir_crate_items;
218    providers.crate_hash = map::crate_hash;
219    providers.hir_module_items = map::hir_module_items;
220    providers.local_def_id_to_hir_id = |tcx, def_id| match tcx.hir_crate(()).owners[def_id] {
221        MaybeOwner::Owner(_) => HirId::make_owner(def_id),
222        MaybeOwner::NonOwner(hir_id) => hir_id,
223        MaybeOwner::Phantom => bug!("No HirId for {:?}", def_id),
224    };
225    providers.opt_hir_owner_nodes =
226        |tcx, id| tcx.hir_crate(()).owners.get(id)?.as_owner().map(|i| &i.nodes);
227    providers.hir_owner_parent = |tcx, owner_id| {
228        tcx.opt_local_parent(owner_id.def_id).map_or(CRATE_HIR_ID, |parent_def_id| {
229            let parent_owner_id = tcx.local_def_id_to_hir_id(parent_def_id).owner;
230            HirId {
231                owner: parent_owner_id,
232                local_id: tcx.hir_crate(()).owners[parent_owner_id.def_id]
233                    .unwrap()
234                    .parenting
235                    .get(&owner_id.def_id)
236                    .copied()
237                    .unwrap_or(ItemLocalId::ZERO),
238            }
239        })
240    };
241    providers.hir_attr_map = |tcx, id| {
242        tcx.hir_crate(()).owners[id.def_id].as_owner().map_or(AttributeMap::EMPTY, |o| &o.attrs)
243    };
244    providers.opt_ast_lowering_delayed_lints =
245        |tcx, id| tcx.hir_crate(()).owners[id.def_id].as_owner().map(|o| &o.delayed_lints);
246    providers.def_span = |tcx, def_id| tcx.hir_span(tcx.local_def_id_to_hir_id(def_id));
247    providers.def_ident_span = |tcx, def_id| {
248        let hir_id = tcx.local_def_id_to_hir_id(def_id);
249        tcx.hir_opt_ident_span(hir_id)
250    };
251    providers.ty_span = |tcx, def_id| {
252        let node = tcx.hir_node_by_def_id(def_id);
253        match node.ty() {
254            Some(ty) => ty.span,
255            None => bug!("{def_id:?} doesn't have a type: {node:#?}"),
256        }
257    };
258    providers.fn_arg_idents = |tcx, def_id| {
259        let node = tcx.hir_node_by_def_id(def_id);
260        if let Some(body_id) = node.body_id() {
261            tcx.arena.alloc_from_iter(tcx.hir_body_param_idents(body_id))
262        } else if let Node::TraitItem(&TraitItem {
263            kind: TraitItemKind::Fn(_, TraitFn::Required(idents)),
264            ..
265        })
266        | Node::ForeignItem(&ForeignItem {
267            kind: ForeignItemKind::Fn(_, idents, _),
268            ..
269        }) = node
270        {
271            idents
272        } else {
273            span_bug!(
274                tcx.hir_span(tcx.local_def_id_to_hir_id(def_id)),
275                "fn_arg_idents: unexpected item {:?}",
276                def_id
277            );
278        }
279    };
280    providers.all_local_trait_impls = |tcx, ()| &tcx.resolutions(()).trait_impls;
281    providers.local_trait_impls =
282        |tcx, trait_id| tcx.resolutions(()).trait_impls.get(&trait_id).map_or(&[], |xs| &xs[..]);
283    providers.expn_that_defined =
284        |tcx, id| tcx.resolutions(()).expn_that_defined.get(&id).copied().unwrap_or(ExpnId::root());
285    providers.in_scope_traits_map = |tcx, id| {
286        tcx.hir_crate(()).owners[id.def_id].as_owner().map(|owner_info| &owner_info.trait_map)
287    };
288}