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 use rustc_middle::ty;
17
18 mod store {
19 use rustc_hir::def_id::LocalDefId;
24 use rustc_middle::mir::Body;
25 use rustc_middle::query::plumbing::IntoQueryParam;
26 use rustc_middle::thir::{ExprId, Thir};
27 use std::cell::RefCell;
28 use std::collections::HashMap;
29 use std::rc::Rc;
30
31 thread_local! {
32 static THIR_BODY: RefCell<HashMap<LocalDefId, (Rc<Thir<'static>>, ExprId)>> = RefCell::new(HashMap::new());
33 static MIR_BUILT: RefCell<HashMap<LocalDefId, Rc<Body<'static>>>> = RefCell::new(HashMap::new());
34 }
35
36 pub fn override_queries_store_body(providers: &mut rustc_middle::query::Providers) {
39 providers.thir_body = |tcx, def_id| {
40 let (steal, expr_id) =
41 (rustc_interface::DEFAULT_QUERY_PROVIDERS.thir_body)(tcx, def_id)?;
42 let body = steal.borrow().clone();
43 let body: Thir<'static> = unsafe { std::mem::transmute(body) };
44 THIR_BODY.with(|map| map.borrow_mut().insert(def_id, (Rc::new(body), expr_id)));
45 Ok((steal, expr_id))
46 };
47 providers.mir_built = |tcx, def_id| {
48 let steal = (rustc_interface::DEFAULT_QUERY_PROVIDERS.mir_built)(tcx, def_id);
49 let body = steal.borrow().clone();
50 let body: Body<'static> = unsafe { std::mem::transmute(body) };
51 MIR_BUILT.with(|map| map.borrow_mut().insert(def_id, Rc::new(body)));
52 steal
53 };
54 }
55
56 #[extension_traits::extension(pub trait SafeTyCtxtBodies)]
59 impl<'tcx> rustc_middle::ty::TyCtxt<'tcx> {
60 fn thir_body_safe(
61 &self,
62 key: impl IntoQueryParam<rustc_span::def_id::LocalDefId>,
63 ) -> Result<(Rc<Thir<'tcx>>, ExprId), rustc_span::ErrorGuaranteed> {
64 let key = key.into_query_param();
65 if !THIR_BODY.with(|map| map.borrow().contains_key(&key)) {
66 let _ = self.thir_body(key);
68 }
69 THIR_BODY.with(|map| {
70 let (body, expr) = map
71 .borrow_mut()
72 .get(&key)
73 .expect("Did we forgot to call `register`?")
74 .clone();
75 let body: Rc<Thir<'tcx>> = unsafe { std::mem::transmute(body) };
76 Ok((body, expr))
77 })
78 }
79 fn mir_built_safe(
80 &self,
81 key: impl IntoQueryParam<rustc_span::def_id::LocalDefId>,
82 ) -> Rc<Body<'tcx>> {
83 let key = key.into_query_param();
84 if !MIR_BUILT.with(|map| map.borrow().contains_key(&key)) {
85 let _ = self.mir_built(key);
87 }
88 MIR_BUILT.with(|map| {
89 let body = map
90 .borrow_mut()
91 .get(&key)
92 .expect("Did we forgot to call `register`?")
93 .clone();
94 unsafe { std::mem::transmute(body) }
95 })
96 }
97 }
98 }
99 pub use store::*;
100
101 pub fn get_thir<'tcx, S: BaseState<'tcx>>(
102 did: RLocalDefId,
103 s: &S,
104 ) -> (
105 Rc<rustc_middle::thir::Thir<'tcx>>,
106 rustc_middle::thir::ExprId,
107 ) {
108 let tcx = s.base().tcx;
109
110 let hir_id = tcx.local_def_id_to_hir_id(did);
114 for (parent_id, parent) in tcx.hir_parent_iter(hir_id) {
115 if let rustc_hir::Node::Item(..) = parent {
116 let _ = tcx.check_well_formed(parent_id.owner.def_id);
117 break;
118 }
119 }
120
121 let msg = |_| fatal!(s[tcx.def_span(did)], "THIR not found for {:?}", did);
122 tcx.thir_body_safe(did).as_ref().unwrap_or_else(msg).clone()
123 }
124
125 pub trait IsBody: Sized + std::fmt::Debug + Clone + 'static {
126 fn body<'tcx, S: UnderOwnerState<'tcx>>(
127 s: &S,
128 did: RDefId,
129 instantiate: Option<ty::GenericArgsRef<'tcx>>,
130 ) -> Option<Self>;
131
132 fn from_mir<'tcx, S: UnderOwnerState<'tcx>>(
134 _s: &S,
135 _body: rustc_middle::mir::Body<'tcx>,
136 ) -> Option<Self> {
137 None
138 }
139 }
140
141 pub fn make_fn_def<'tcx, Body: IsBody, S: BaseState<'tcx>>(
142 fn_sig: &rustc_hir::FnSig,
143 body_id: &rustc_hir::BodyId,
144 s: &S,
145 ) -> FnDef<Body> {
146 let hir_id = body_id.hir_id;
147 let ldid = hir_id.owner.def_id;
148
149 let (thir, expr_entrypoint) = get_thir(ldid, s);
150 let s = &s.with_owner_id(ldid.to_def_id()).with_thir(thir.clone());
151 FnDef {
152 params: thir.params.raw.sinto(s),
153 ret: thir.exprs[expr_entrypoint].ty.sinto(s),
154 body: Body::body(s, ldid.to_def_id(), None).s_unwrap(s),
155 sig_span: fn_sig.span.sinto(s),
156 header: fn_sig.header.sinto(s),
157 }
158 }
159
160 pub fn body_from_id<'tcx, Body: IsBody, S: UnderOwnerState<'tcx>>(
161 id: rustc_hir::BodyId,
162 s: &S,
163 ) -> Body {
164 Body::body(s, s.base().tcx.hir_body_owner_def_id(id).to_def_id(), None).s_unwrap(s)
170 }
171
172 mod implementations {
173 use super::*;
174 impl IsBody for () {
175 fn body<'tcx, S: UnderOwnerState<'tcx>>(
176 _s: &S,
177 _did: RDefId,
178 _instantiate: Option<ty::GenericArgsRef<'tcx>>,
179 ) -> Option<Self> {
180 Some(())
181 }
182 fn from_mir<'tcx, S: UnderOwnerState<'tcx>>(
183 _s: &S,
184 _body: rustc_middle::mir::Body<'tcx>,
185 ) -> Option<Self> {
186 Some(())
187 }
188 }
189 impl IsBody for ThirBody {
190 fn body<'tcx, S: BaseState<'tcx>>(
191 s: &S,
192 did: RDefId,
193 instantiate: Option<ty::GenericArgsRef<'tcx>>,
194 ) -> Option<Self> {
195 let did = did.as_local()?;
196 let (thir, expr) = get_thir(did, s);
197 assert!(instantiate.is_none(), "monomorphized thir isn't supported");
198 let s = &s.with_owner_id(did.to_def_id());
199 Some(if *CORE_EXTRACTION_MODE {
200 let expr = &thir.exprs[expr];
201 Decorated {
202 contents: Box::new(ExprKind::Tuple { fields: vec![] }),
203 hir_id: None,
204 attributes: vec![],
205 ty: expr.ty.sinto(s),
206 span: expr.span.sinto(s),
207 }
208 } else {
209 expr.sinto(&s.with_thir(thir))
210 })
211 }
212 }
213
214 impl<A: IsBody, B: IsBody> IsBody for (A, B) {
215 fn body<'tcx, S: UnderOwnerState<'tcx>>(
216 s: &S,
217 did: RDefId,
218 instantiate: Option<ty::GenericArgsRef<'tcx>>,
219 ) -> Option<Self> {
220 Some((A::body(s, did, instantiate)?, B::body(s, did, instantiate)?))
221 }
222 }
223
224 impl<MirKind: IsMirKind + Clone + 'static> IsBody for MirBody<MirKind> {
225 fn body<'tcx, S: UnderOwnerState<'tcx>>(
226 s: &S,
227 did: RDefId,
228 instantiate: Option<ty::GenericArgsRef<'tcx>>,
229 ) -> Option<Self> {
230 let tcx = s.base().tcx;
231 let typing_env = s.typing_env();
232 MirKind::get_mir(tcx, did, |body| {
233 let body = substitute(tcx, typing_env, instantiate, body.clone());
234 let body = Rc::new(body);
235 body.sinto(&s.with_mir(body.clone()))
236 })
237 }
238 fn from_mir<'tcx, S: UnderOwnerState<'tcx>>(
239 s: &S,
240 body: rustc_middle::mir::Body<'tcx>,
241 ) -> Option<Self> {
242 let body = Rc::new(body.clone());
243 let s = &s.with_mir(body.clone());
244 Some(body.sinto(s))
245 }
246 }
247 }
248
249 impl<'tcx, S: UnderOwnerState<'tcx>, Body: IsBody> SInto<S, Body> for rustc_hir::BodyId {
250 fn sinto(&self, s: &S) -> Body {
251 body_from_id::<Body, _>(*self, s)
252 }
253 }
254}