rustc_public_bridge/
builder.rs

1//! Logic required to produce a monomorphic body.
2//!
3//! We retrieve and monomorphize the rustc body representation, i.e., we generate a
4//! monomorphic body using internal representation.
5
6use rustc_hir::def::DefKind;
7use rustc_middle::mir;
8use rustc_middle::mir::visit::MutVisitor;
9use rustc_middle::ty::{self, TyCtxt};
10
11/// Builds a monomorphic body for a given instance.
12pub(crate) struct BodyBuilder<'tcx> {
13    tcx: TyCtxt<'tcx>,
14    instance: ty::Instance<'tcx>,
15}
16
17impl<'tcx> BodyBuilder<'tcx> {
18    pub(crate) fn new(tcx: TyCtxt<'tcx>, instance: ty::Instance<'tcx>) -> Self {
19        let instance = match instance.def {
20            // To get the fallback body of an intrinsic, we need to convert it to an item.
21            ty::InstanceKind::Intrinsic(def_id) => ty::Instance::new_raw(def_id, instance.args),
22            _ => instance,
23        };
24        BodyBuilder { tcx, instance }
25    }
26
27    /// Build a monomorphic body for a given instance based on the MIR body.
28    ///
29    /// All constants are also evaluated.
30    pub(crate) fn build(mut self) -> mir::Body<'tcx> {
31        let body = self.tcx.instance_mir(self.instance.def).clone();
32        let mono_body = if !self.instance.args.is_empty()
33            // Without the `generic_const_exprs` feature gate, anon consts in signatures do not
34            // get generic parameters. Which is wrong, but also not a problem without
35            // generic_const_exprs
36            || self.tcx.def_kind(self.instance.def_id()) != DefKind::AnonConst
37        {
38            let mut mono_body = self.instance.instantiate_mir_and_normalize_erasing_regions(
39                self.tcx,
40                ty::TypingEnv::fully_monomorphized(),
41                ty::EarlyBinder::bind(body),
42            );
43            self.visit_body(&mut mono_body);
44            mono_body
45        } else {
46            // Already monomorphic.
47            body
48        };
49
50        mono_body
51    }
52}
53
54impl<'tcx> MutVisitor<'tcx> for BodyBuilder<'tcx> {
55    fn visit_const_operand(
56        &mut self,
57        constant: &mut mir::ConstOperand<'tcx>,
58        location: mir::Location,
59    ) {
60        let const_ = constant.const_;
61        let val = match const_.eval(self.tcx, ty::TypingEnv::fully_monomorphized(), constant.span) {
62            Ok(v) => v,
63            Err(mir::interpret::ErrorHandled::Reported(..)) => return,
64            Err(mir::interpret::ErrorHandled::TooGeneric(..)) => {
65                unreachable!("Failed to evaluate instance constant: {:?}", const_)
66            }
67        };
68        let ty = constant.ty();
69        constant.const_ = mir::Const::Val(val, ty);
70        self.super_const_operand(constant, location);
71    }
72
73    fn tcx(&self) -> TyCtxt<'tcx> {
74        self.tcx
75    }
76}