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, Res};
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    /// Statics and functions with an `EiiImpls` or `EiiExternTarget` attribute
42    eiis: Box<[LocalDefId]>,
43}
44
45impl ModuleItems {
46    /// Returns all non-associated locally defined items in all modules.
47    ///
48    /// Note that this does *not* include associated items of `impl` blocks! It also does not
49    /// include foreign items. If you want to e.g. get all functions, use `definitions()` below.
50    ///
51    /// However, this does include the `impl` blocks themselves.
52    pub fn free_items(&self) -> impl Iterator<Item = ItemId> {
53        self.free_items.iter().copied()
54    }
55
56    pub fn trait_items(&self) -> impl Iterator<Item = TraitItemId> {
57        self.trait_items.iter().copied()
58    }
59
60    pub fn delayed_lint_items(&self) -> impl Iterator<Item = OwnerId> {
61        self.delayed_lint_items.iter().copied()
62    }
63
64    pub fn eiis(&self) -> impl Iterator<Item = LocalDefId> {
65        self.eiis.iter().copied()
66    }
67
68    /// Returns all items that are associated with some `impl` block (both inherent and trait impl
69    /// blocks).
70    pub fn impl_items(&self) -> impl Iterator<Item = ImplItemId> {
71        self.impl_items.iter().copied()
72    }
73
74    pub fn foreign_items(&self) -> impl Iterator<Item = ForeignItemId> {
75        self.foreign_items.iter().copied()
76    }
77
78    pub fn owners(&self) -> impl Iterator<Item = OwnerId> {
79        self.add_root
80            .then_some(CRATE_OWNER_ID)
81            .into_iter()
82            .chain(self.free_items.iter().map(|id| id.owner_id))
83            .chain(self.trait_items.iter().map(|id| id.owner_id))
84            .chain(self.impl_items.iter().map(|id| id.owner_id))
85            .chain(self.foreign_items.iter().map(|id| id.owner_id))
86    }
87
88    pub fn opaques(&self) -> impl Iterator<Item = LocalDefId> {
89        self.opaques.iter().copied()
90    }
91
92    /// Closures and inline consts
93    pub fn nested_bodies(&self) -> impl Iterator<Item = LocalDefId> {
94        self.nested_bodies.iter().copied()
95    }
96
97    pub fn definitions(&self) -> impl Iterator<Item = LocalDefId> {
98        self.owners().map(|id| id.def_id)
99    }
100
101    /// Closures and inline consts
102    pub fn par_nested_bodies(
103        &self,
104        f: impl Fn(LocalDefId) -> Result<(), ErrorGuaranteed> + DynSend + DynSync,
105    ) -> Result<(), ErrorGuaranteed> {
106        try_par_for_each_in(&self.nested_bodies[..], |&&id| f(id))
107    }
108
109    pub fn par_items(
110        &self,
111        f: impl Fn(ItemId) -> Result<(), ErrorGuaranteed> + DynSend + DynSync,
112    ) -> Result<(), ErrorGuaranteed> {
113        try_par_for_each_in(&self.free_items[..], |&&id| f(id))
114    }
115
116    pub fn par_trait_items(
117        &self,
118        f: impl Fn(TraitItemId) -> Result<(), ErrorGuaranteed> + DynSend + DynSync,
119    ) -> Result<(), ErrorGuaranteed> {
120        try_par_for_each_in(&self.trait_items[..], |&&id| f(id))
121    }
122
123    pub fn par_impl_items(
124        &self,
125        f: impl Fn(ImplItemId) -> Result<(), ErrorGuaranteed> + DynSend + DynSync,
126    ) -> Result<(), ErrorGuaranteed> {
127        try_par_for_each_in(&self.impl_items[..], |&&id| f(id))
128    }
129
130    pub fn par_foreign_items(
131        &self,
132        f: impl Fn(ForeignItemId) -> Result<(), ErrorGuaranteed> + DynSend + DynSync,
133    ) -> Result<(), ErrorGuaranteed> {
134        try_par_for_each_in(&self.foreign_items[..], |&&id| f(id))
135    }
136
137    pub fn par_opaques(
138        &self,
139        f: impl Fn(LocalDefId) -> Result<(), ErrorGuaranteed> + DynSend + DynSync,
140    ) -> Result<(), ErrorGuaranteed> {
141        try_par_for_each_in(&self.opaques[..], |&&id| f(id))
142    }
143}
144
145impl<'tcx> TyCtxt<'tcx> {
146    pub fn parent_module(self, id: HirId) -> LocalModDefId {
147        if !id.is_owner() && self.def_kind(id.owner) == DefKind::Mod {
148            LocalModDefId::new_unchecked(id.owner.def_id)
149        } else {
150            self.parent_module_from_def_id(id.owner.def_id)
151        }
152    }
153
154    pub fn parent_module_from_def_id(self, mut id: LocalDefId) -> LocalModDefId {
155        while let Some(parent) = self.opt_local_parent(id) {
156            id = parent;
157            if self.def_kind(id) == DefKind::Mod {
158                break;
159            }
160        }
161        LocalModDefId::new_unchecked(id)
162    }
163
164    /// Returns `true` if this is a foreign item (i.e., linked via `extern { ... }`).
165    pub fn is_foreign_item(self, def_id: impl Into<DefId>) -> bool {
166        self.opt_parent(def_id.into())
167            .is_some_and(|parent| matches!(self.def_kind(parent), DefKind::ForeignMod))
168    }
169
170    pub fn hash_owner_nodes(
171        self,
172        node: OwnerNode<'_>,
173        bodies: &SortedMap<ItemLocalId, &Body<'_>>,
174        attrs: &SortedMap<ItemLocalId, &[Attribute]>,
175        delayed_lints: &[DelayedLint],
176        define_opaque: Option<&[(Span, LocalDefId)]>,
177    ) -> Hashes {
178        if !self.needs_crate_hash() {
179            return Hashes {
180                opt_hash_including_bodies: None,
181                attrs_hash: None,
182                delayed_lints_hash: None,
183            };
184        }
185
186        self.with_stable_hashing_context(|mut hcx| {
187            let mut stable_hasher = StableHasher::new();
188            node.hash_stable(&mut hcx, &mut stable_hasher);
189            // Bodies are stored out of line, so we need to pull them explicitly in the hash.
190            bodies.hash_stable(&mut hcx, &mut stable_hasher);
191            let h1 = stable_hasher.finish();
192
193            let mut stable_hasher = StableHasher::new();
194            attrs.hash_stable(&mut hcx, &mut stable_hasher);
195
196            // Hash the defined opaque types, which are not present in the attrs.
197            define_opaque.hash_stable(&mut hcx, &mut stable_hasher);
198
199            let h2 = stable_hasher.finish();
200
201            // hash lints emitted during ast lowering
202            let mut stable_hasher = StableHasher::new();
203            delayed_lints.hash_stable(&mut hcx, &mut stable_hasher);
204            let h3 = stable_hasher.finish();
205
206            Hashes {
207                opt_hash_including_bodies: Some(h1),
208                attrs_hash: Some(h2),
209                delayed_lints_hash: Some(h3),
210            }
211        })
212    }
213
214    pub fn qpath_is_lang_item(self, qpath: QPath<'_>, lang_item: LangItem) -> bool {
215        self.qpath_lang_item(qpath) == Some(lang_item)
216    }
217
218    /// This does not use typeck results since this is intended to be used with generated code.
219    pub fn qpath_lang_item(self, qpath: QPath<'_>) -> Option<LangItem> {
220        if let QPath::Resolved(_, path) = qpath
221            && let Res::Def(_, def_id) = path.res
222        {
223            return self.lang_items().from_def_id(def_id);
224        }
225        None
226    }
227
228    /// Whether this expression constitutes a read of value of the type that
229    /// it evaluates to.
230    ///
231    /// This is used to determine if we should consider the block to diverge
232    /// if the expression evaluates to `!`, and if we should insert a `NeverToAny`
233    /// coercion for values of type `!`.
234    ///
235    /// This function generally returns `false` if the expression is a place
236    /// expression and the *parent* expression is the scrutinee of a match or
237    /// the pointee of an `&` addr-of expression, since both of those parent
238    /// expressions take a *place* and not a value.
239    pub fn expr_guaranteed_to_constitute_read_for_never(self, expr: &Expr<'_>) -> bool {
240        // We only care about place exprs. Anything else returns an immediate
241        // which would constitute a read. We don't care about distinguishing
242        // "syntactic" place exprs since if the base of a field projection is
243        // not a place then it would've been UB to read from it anyways since
244        // that constitutes a read.
245        if !expr.is_syntactic_place_expr() {
246            return true;
247        }
248
249        let parent_node = self.parent_hir_node(expr.hir_id);
250        match parent_node {
251            Node::Expr(parent_expr) => {
252                match parent_expr.kind {
253                    // Addr-of, field projections, and LHS of assignment don't constitute reads.
254                    // Assignment does call `drop_in_place`, though, but its safety
255                    // requirements are not the same.
256                    ExprKind::AddrOf(..) | ExprKind::Field(..) => false,
257
258                    // Place-preserving expressions only constitute reads if their
259                    // parent expression constitutes a read.
260                    ExprKind::Type(..) | ExprKind::UnsafeBinderCast(..) => {
261                        self.expr_guaranteed_to_constitute_read_for_never(parent_expr)
262                    }
263
264                    ExprKind::Assign(lhs, _, _) => {
265                        // Only the LHS does not constitute a read
266                        expr.hir_id != lhs.hir_id
267                    }
268
269                    // See note on `PatKind::Or` in `Pat::is_guaranteed_to_constitute_read_for_never`
270                    // for why this is `all`.
271                    ExprKind::Match(scrutinee, arms, _) => {
272                        assert_eq!(scrutinee.hir_id, expr.hir_id);
273                        arms.iter().all(|arm| arm.pat.is_guaranteed_to_constitute_read_for_never())
274                    }
275                    ExprKind::Let(LetExpr { init, pat, .. }) => {
276                        assert_eq!(init.hir_id, expr.hir_id);
277                        pat.is_guaranteed_to_constitute_read_for_never()
278                    }
279
280                    // Any expression child of these expressions constitute reads.
281                    ExprKind::Array(_)
282                    | ExprKind::Call(_, _)
283                    | ExprKind::Use(_, _)
284                    | ExprKind::MethodCall(_, _, _, _)
285                    | ExprKind::Tup(_)
286                    | ExprKind::Binary(_, _, _)
287                    | ExprKind::Unary(_, _)
288                    | ExprKind::Cast(_, _)
289                    | ExprKind::DropTemps(_)
290                    | ExprKind::If(_, _, _)
291                    | ExprKind::Closure(_)
292                    | ExprKind::Block(_, _)
293                    | ExprKind::AssignOp(_, _, _)
294                    | ExprKind::Index(_, _, _)
295                    | ExprKind::Break(_, _)
296                    | ExprKind::Ret(_)
297                    | ExprKind::Become(_)
298                    | ExprKind::InlineAsm(_)
299                    | ExprKind::Struct(_, _, _)
300                    | ExprKind::Repeat(_, _)
301                    | ExprKind::Yield(_, _) => true,
302
303                    // These expressions have no (direct) sub-exprs.
304                    ExprKind::ConstBlock(_)
305                    | ExprKind::Loop(_, _, _, _)
306                    | ExprKind::Lit(_)
307                    | ExprKind::Path(_)
308                    | ExprKind::Continue(_)
309                    | ExprKind::OffsetOf(_, _)
310                    | ExprKind::Err(_) => unreachable!("no sub-expr expected for {:?}", expr.kind),
311                }
312            }
313
314            // If we have a subpattern that performs a read, we want to consider this
315            // to diverge for compatibility to support something like `let x: () = *never_ptr;`.
316            Node::LetStmt(LetStmt { init: Some(target), pat, .. }) => {
317                assert_eq!(target.hir_id, expr.hir_id);
318                pat.is_guaranteed_to_constitute_read_for_never()
319            }
320
321            // These nodes (if they have a sub-expr) do constitute a read.
322            Node::Block(_)
323            | Node::Arm(_)
324            | Node::ExprField(_)
325            | Node::AnonConst(_)
326            | Node::ConstBlock(_)
327            | Node::ConstArg(_)
328            | Node::Stmt(_)
329            | Node::Item(Item { kind: ItemKind::Const(..) | ItemKind::Static(..), .. })
330            | Node::TraitItem(TraitItem { kind: TraitItemKind::Const(..), .. })
331            | Node::ImplItem(ImplItem { kind: ImplItemKind::Const(..), .. }) => true,
332
333            Node::TyPat(_) | Node::Pat(_) => {
334                self.dcx().span_delayed_bug(expr.span, "place expr not allowed in pattern");
335                true
336            }
337
338            // These nodes do not have direct sub-exprs.
339            Node::Param(_)
340            | Node::Item(_)
341            | Node::ForeignItem(_)
342            | Node::TraitItem(_)
343            | Node::ImplItem(_)
344            | Node::Variant(_)
345            | Node::Field(_)
346            | Node::PathSegment(_)
347            | Node::Ty(_)
348            | Node::AssocItemConstraint(_)
349            | Node::TraitRef(_)
350            | Node::PatField(_)
351            | Node::PatExpr(_)
352            | Node::LetStmt(_)
353            | Node::Synthetic
354            | Node::Err(_)
355            | Node::Ctor(_)
356            | Node::Lifetime(_)
357            | Node::GenericParam(_)
358            | Node::Crate(_)
359            | Node::Infer(_)
360            | Node::WherePredicate(_)
361            | Node::PreciseCapturingNonLifetimeArg(_)
362            | Node::OpaqueTy(_) => {
363                unreachable!("no sub-expr expected for {parent_node:?}")
364            }
365        }
366    }
367}
368
369/// Hashes computed by [`TyCtxt::hash_owner_nodes`] if necessary.
370#[derive(Clone, Copy, Debug)]
371pub struct Hashes {
372    pub opt_hash_including_bodies: Option<Fingerprint>,
373    pub attrs_hash: Option<Fingerprint>,
374    pub delayed_lints_hash: Option<Fingerprint>,
375}
376
377pub fn provide(providers: &mut Providers) {
378    providers.hir_crate_items = map::hir_crate_items;
379    providers.crate_hash = map::crate_hash;
380    providers.hir_module_items = map::hir_module_items;
381    providers.local_def_id_to_hir_id = |tcx, def_id| match tcx.hir_crate(()).owners[def_id] {
382        MaybeOwner::Owner(_) => HirId::make_owner(def_id),
383        MaybeOwner::NonOwner(hir_id) => hir_id,
384        MaybeOwner::Phantom => bug!("No HirId for {:?}", def_id),
385    };
386    providers.opt_hir_owner_nodes =
387        |tcx, id| tcx.hir_crate(()).owners.get(id)?.as_owner().map(|i| &i.nodes);
388    providers.hir_owner_parent = |tcx, owner_id| {
389        tcx.opt_local_parent(owner_id.def_id).map_or(CRATE_HIR_ID, |parent_def_id| {
390            let parent_owner_id = tcx.local_def_id_to_hir_id(parent_def_id).owner;
391            HirId {
392                owner: parent_owner_id,
393                local_id: tcx.hir_crate(()).owners[parent_owner_id.def_id]
394                    .unwrap()
395                    .parenting
396                    .get(&owner_id.def_id)
397                    .copied()
398                    .unwrap_or(ItemLocalId::ZERO),
399            }
400        })
401    };
402    providers.hir_attr_map = |tcx, id| {
403        tcx.hir_crate(()).owners[id.def_id].as_owner().map_or(AttributeMap::EMPTY, |o| &o.attrs)
404    };
405    providers.opt_ast_lowering_delayed_lints =
406        |tcx, id| tcx.hir_crate(()).owners[id.def_id].as_owner().map(|o| &o.delayed_lints);
407    providers.def_span = |tcx, def_id| tcx.hir_span(tcx.local_def_id_to_hir_id(def_id));
408    providers.def_ident_span = |tcx, def_id| {
409        let hir_id = tcx.local_def_id_to_hir_id(def_id);
410        tcx.hir_opt_ident_span(hir_id)
411    };
412    providers.ty_span = |tcx, def_id| {
413        let node = tcx.hir_node_by_def_id(def_id);
414        match node.ty() {
415            Some(ty) => ty.span,
416            None => bug!("{def_id:?} doesn't have a type: {node:#?}"),
417        }
418    };
419    providers.fn_arg_idents = |tcx, def_id| {
420        let node = tcx.hir_node_by_def_id(def_id);
421        if let Some(body_id) = node.body_id() {
422            tcx.arena.alloc_from_iter(tcx.hir_body_param_idents(body_id))
423        } else if let Node::TraitItem(&TraitItem {
424            kind: TraitItemKind::Fn(_, TraitFn::Required(idents)),
425            ..
426        })
427        | Node::ForeignItem(&ForeignItem {
428            kind: ForeignItemKind::Fn(_, idents, _),
429            ..
430        }) = node
431        {
432            idents
433        } else {
434            span_bug!(
435                tcx.hir_span(tcx.local_def_id_to_hir_id(def_id)),
436                "fn_arg_idents: unexpected item {:?}",
437                def_id
438            );
439        }
440    };
441    providers.all_local_trait_impls = |tcx, ()| &tcx.resolutions(()).trait_impls;
442    providers.local_trait_impls =
443        |tcx, trait_id| tcx.resolutions(()).trait_impls.get(&trait_id).map_or(&[], |xs| &xs[..]);
444    providers.expn_that_defined =
445        |tcx, id| tcx.resolutions(()).expn_that_defined.get(&id).copied().unwrap_or(ExpnId::root());
446    providers.in_scope_traits_map = |tcx, id| {
447        tcx.hir_crate(()).owners[id.def_id].as_owner().map(|owner_info| &owner_info.trait_map)
448    };
449}