charon_driver/translate/
get_mir.rs1use std::panic;
4use std::rc::Rc;
5
6use hax::{HasParamEnv, UnderOwnerState};
7use rustc_middle::mir;
8use rustc_middle::ty;
9
10use charon_lib::ast::*;
11use charon_lib::options::MirLevel;
12
13use super::translate_ctx::ItemTransCtx;
14
15impl ItemTransCtx<'_, '_> {
16 pub fn get_mir(
17 &mut self,
18 item_ref: &hax::ItemRef,
19 span: Span,
20 ) -> Result<Option<hax::MirBody<hax::mir_kinds::Unknown>>, Error> {
21 let mut this = panic::AssertUnwindSafe(&mut *self);
23 let res = panic::catch_unwind(move || this.get_mir_inner(item_ref, span));
24 match res {
25 Ok(Ok(body)) => Ok(body),
26 Ok(Err(e)) => Err(e),
28 Err(_) => {
29 raise_error!(self, span, "Thread panicked when extracting body.");
30 }
31 }
32 }
33
34 fn get_mir_inner(
35 &mut self,
36 item_ref: &hax::ItemRef,
37 span: Span,
38 ) -> Result<Option<hax::MirBody<hax::mir_kinds::Unknown>>, Error> {
39 let tcx = self.t_ctx.tcx;
40 let mir_level = self.t_ctx.options.mir_level;
41 let def_id = &item_ref.def_id;
42 Ok(match get_mir_for_def_id_and_level(tcx, def_id, mir_level) {
43 Some(body) => {
44 let s = self.hax_state_with_id();
45 let body = if self.monomorphize() {
46 let typing_env = s.typing_env();
47 let args = item_ref.rustc_args(s);
48 hax::substitute(tcx, typing_env, Some(args), body)
49 } else {
50 body
51 };
52 let body = Rc::new(body);
54 let state = s.with_mir(body.clone());
55 let body: hax::MirBody<hax::mir_kinds::Unknown> =
57 self.t_ctx.catch_sinto(&state, span, body.as_ref())?;
58 Some(body)
59 }
60 None => None,
61 })
62 }
63}
64
65#[tracing::instrument(skip(tcx))]
68fn get_mir_for_def_id_and_level<'tcx>(
69 tcx: ty::TyCtxt<'tcx>,
70 def_id: &hax::DefId,
71 level: MirLevel,
72) -> Option<mir::Body<'tcx>> {
73 let rust_def_id = def_id.underlying_rust_def_id();
74 match def_id.promoted_id() {
75 None => {
76 if let Some(local_def_id) = rust_def_id.as_local() {
77 match level {
78 MirLevel::Built => {
79 let body = tcx.mir_built(local_def_id);
80 if !body.is_stolen() {
81 return Some(body.borrow().clone());
82 }
83 }
84 MirLevel::Promoted => {
85 let (body, _) = tcx.mir_promoted(local_def_id);
86 if !body.is_stolen() {
87 return Some(body.borrow().clone());
88 }
89 }
90 MirLevel::Elaborated => {
91 let body = tcx.mir_drops_elaborated_and_const_checked(local_def_id);
92 if !body.is_stolen() {
93 return Some(body.borrow().clone());
94 }
95 }
96 MirLevel::Optimized => {}
97 }
98 }
100
101 let is_global = matches!(
108 def_id.kind,
109 hax::DefKind::Const
110 | hax::DefKind::AnonConst
111 | hax::DefKind::AssocConst
112 | hax::DefKind::InlineConst
113 );
114 let mir_available = tcx.is_mir_available(rust_def_id);
115 let ctfe_mir_available = tcx.is_ctfe_mir_available(rust_def_id);
116 let body = if mir_available && !(is_global && ctfe_mir_available) {
118 tcx.optimized_mir(rust_def_id).clone()
119 } else if ctfe_mir_available {
120 tcx.mir_for_ctfe(rust_def_id).clone()
121 } else {
122 trace!("no mir available");
123 return None;
124 };
125 Some(body)
126 }
127 Some(promoted_id) => {
128 let promoted_id = promoted_id.as_rust_promoted_id();
129 Some(hax::get_promoted_mir(tcx, rust_def_id, promoted_id))
130 }
131 }
132}