1pub use module::*;
2
3#[cfg(not(feature = "rustc"))]
4mod module {
5 pub trait IsBody: Sized + Clone + 'static {}
6 impl<T: Sized + Clone + 'static> IsBody for T {}
7}
8
9#[cfg(feature = "rustc")]
10mod module {
11 pub use crate::prelude::*;
12 pub use rustc_hir::{
13 def_id::{DefId as RDefId, LocalDefId as RLocalDefId},
14 hir_id::OwnerId as ROwnerId,
15 };
16
17 mod store {
18 use rustc_hir::def_id::LocalDefId;
23 use rustc_middle::mir::Body;
24 use rustc_middle::query::plumbing::IntoQueryParam;
25 use rustc_middle::thir::{ExprId, Thir};
26 use std::cell::RefCell;
27 use std::collections::HashMap;
28 use std::rc::Rc;
29
30 thread_local! {
31 static THIR_BODY: RefCell<HashMap<LocalDefId, (Rc<Thir<'static>>, ExprId)>> = RefCell::new(HashMap::new());
32 static MIR_BUILT: RefCell<HashMap<LocalDefId, Rc<Body<'static>>>> = RefCell::new(HashMap::new());
33 }
34
35 pub fn override_queries_store_body(providers: &mut rustc_middle::query::Providers) {
38 providers.thir_body = |tcx, def_id| {
39 let (steal, expr_id) =
40 (rustc_interface::DEFAULT_QUERY_PROVIDERS.thir_body)(tcx, def_id)?;
41 let body = steal.borrow().clone();
42 let body: Thir<'static> = unsafe { std::mem::transmute(body) };
43 THIR_BODY.with(|map| map.borrow_mut().insert(def_id, (Rc::new(body), expr_id)));
44 Ok((steal, expr_id))
45 };
46 providers.mir_built = |tcx, def_id| {
47 let steal = (rustc_interface::DEFAULT_QUERY_PROVIDERS.mir_built)(tcx, def_id);
48 let body = steal.borrow().clone();
49 let body: Body<'static> = unsafe { std::mem::transmute(body) };
50 MIR_BUILT.with(|map| map.borrow_mut().insert(def_id, Rc::new(body)));
51 steal
52 };
53 }
54
55 #[extension_traits::extension(pub trait SafeTyCtxtBodies)]
58 impl<'tcx> rustc_middle::ty::TyCtxt<'tcx> {
59 fn thir_body_safe(
60 &self,
61 key: impl IntoQueryParam<rustc_span::def_id::LocalDefId>,
62 ) -> Result<(Rc<Thir<'tcx>>, ExprId), rustc_span::ErrorGuaranteed> {
63 let key = key.into_query_param();
64 if !THIR_BODY.with(|map| map.borrow().contains_key(&key)) {
65 let _ = self.thir_body(key);
67 }
68 THIR_BODY.with(|map| {
69 let (body, expr) = map
70 .borrow_mut()
71 .get(&key)
72 .expect("Did we forgot to call `register`?")
73 .clone();
74 let body: Rc<Thir<'tcx>> = unsafe { std::mem::transmute(body) };
75 Ok((body, expr))
76 })
77 }
78 fn mir_built_safe(
79 &self,
80 key: impl IntoQueryParam<rustc_span::def_id::LocalDefId>,
81 ) -> Rc<Body<'tcx>> {
82 let key = key.into_query_param();
83 if !MIR_BUILT.with(|map| map.borrow().contains_key(&key)) {
84 let _ = self.mir_built(key);
86 }
87 MIR_BUILT.with(|map| {
88 let body = map
89 .borrow_mut()
90 .get(&key)
91 .expect("Did we forgot to call `register`?")
92 .clone();
93 unsafe { std::mem::transmute(body) }
94 })
95 }
96 }
97 }
98 pub use store::*;
99
100 pub fn get_thir<'tcx, S: UnderOwnerState<'tcx>>(
101 did: RLocalDefId,
102 s: &S,
103 ) -> (
104 Rc<rustc_middle::thir::Thir<'tcx>>,
105 rustc_middle::thir::ExprId,
106 ) {
107 let tcx = s.base().tcx;
108
109 let hir_id = tcx.local_def_id_to_hir_id(did);
113 for (parent_id, parent) in tcx.hir_parent_iter(hir_id) {
114 if let rustc_hir::Node::Item(..) = parent {
115 let _ = tcx.check_well_formed(parent_id.owner.def_id);
116 break;
117 }
118 }
119
120 let msg = |_| fatal!(s[tcx.def_span(did)], "THIR not found for {:?}", did);
121 tcx.thir_body_safe(did).as_ref().unwrap_or_else(msg).clone()
122 }
123
124 pub trait IsBody: Sized + Clone + 'static {
125 fn body<'tcx, S: UnderOwnerState<'tcx>>(did: RLocalDefId, s: &S) -> Self;
126
127 fn from_mir<'tcx, S: UnderOwnerState<'tcx>>(
129 _s: &S,
130 _body: rustc_middle::mir::Body<'tcx>,
131 ) -> Self {
132 panic!("Can't convert MIR to the requested body type")
133 }
134 }
135
136 pub fn make_fn_def<'tcx, Body: IsBody, S: UnderOwnerState<'tcx>>(
137 fn_sig: &rustc_hir::FnSig,
138 body_id: &rustc_hir::BodyId,
139 s: &S,
140 ) -> FnDef<Body> {
141 let hir_id = body_id.hir_id;
142 let ldid = hir_id.owner.def_id;
143
144 let (thir, expr_entrypoint) = get_thir(ldid, s);
145 let s = &with_owner_id(s.base(), thir.clone(), (), ldid.to_def_id());
146 FnDef {
147 params: thir.params.raw.sinto(s),
148 ret: thir.exprs[expr_entrypoint].ty.sinto(s),
149 body: Body::body(ldid, s),
150 sig_span: fn_sig.span.sinto(s),
151 header: fn_sig.header.sinto(s),
152 }
153 }
154
155 pub fn body_from_id<'tcx, Body: IsBody, S: UnderOwnerState<'tcx>>(
156 id: rustc_hir::BodyId,
157 s: &S,
158 ) -> Body {
159 Body::body(s.base().tcx.hir_body_owner_def_id(id), s)
165 }
166
167 mod implementations {
168 use super::*;
169 impl IsBody for () {
170 fn body<'tcx, S: UnderOwnerState<'tcx>>(_did: RLocalDefId, _s: &S) -> Self {}
171 fn from_mir<'tcx, S: UnderOwnerState<'tcx>>(
172 _s: &S,
173 _body: rustc_middle::mir::Body<'tcx>,
174 ) -> Self {
175 ()
176 }
177 }
178 impl IsBody for ThirBody {
179 fn body<'tcx, S: UnderOwnerState<'tcx>>(did: RLocalDefId, s: &S) -> Self {
180 let (thir, expr) = get_thir(did, s);
181 if *CORE_EXTRACTION_MODE {
182 let expr = &thir.exprs[expr];
183 Decorated {
184 contents: Box::new(ExprKind::Tuple { fields: vec![] }),
185 hir_id: None,
186 attributes: vec![],
187 ty: expr.ty.sinto(s),
188 span: expr.span.sinto(s),
189 }
190 } else {
191 expr.sinto(&with_owner_id(s.base(), thir, (), did.to_def_id()))
192 }
193 }
194 }
195
196 impl<A: IsBody, B: IsBody> IsBody for (A, B) {
197 fn body<'tcx, S: UnderOwnerState<'tcx>>(did: RLocalDefId, s: &S) -> Self {
198 (A::body(did, s), B::body(did, s))
199 }
200 }
201
202 impl<MirKind: IsMirKind + Clone + 'static> IsBody for MirBody<MirKind> {
203 fn body<'tcx, S: UnderOwnerState<'tcx>>(did: RLocalDefId, s: &S) -> Self {
204 let (thir, _) = get_thir(did, s);
205 let mir = MirKind::get_mir(s.base().tcx, did, |body| {
206 let body = Rc::new(body.clone());
207 body.sinto(&with_owner_id(
208 s.base(),
209 thir,
210 body.clone(),
211 did.to_def_id(),
212 ))
213 });
214 mir.s_unwrap(s)
215 }
216 fn from_mir<'tcx, S: UnderOwnerState<'tcx>>(
217 s: &S,
218 body: rustc_middle::mir::Body<'tcx>,
219 ) -> Self {
220 let body = Rc::new(body.clone());
221 let s = &State {
222 base: s.base(),
223 owner_id: s.owner_id(),
224 mir: body.clone(),
225 binder: (),
226 thir: (),
227 };
228 body.sinto(s)
229 }
230 }
231 }
232
233 impl<'tcx, S: UnderOwnerState<'tcx>, Body: IsBody> SInto<S, Body> for rustc_hir::BodyId {
234 fn sinto(&self, s: &S) -> Body {
235 body_from_id::<Body, _>(*self, s)
236 }
237 }
238}