1use super::translate_crate::RustcItem;
3pub use super::translate_crate::{TransImplSource, TransItemSource, TransItemSourceKind};
4use super::translate_generics::{BindingLevel, LifetimeMutabilityComputer};
5use crate::hax;
6use crate::hax::SInto;
7use charon_lib::ast::*;
8use charon_lib::formatter::{FmtCtx, IntoFormatter};
9use charon_lib::ids::IndexVec;
10use charon_lib::options::TranslateOptions;
11use rustc_hash::{FxHashMap as HashMap, FxHashSet as HashSet};
12use rustc_middle::ty::TyCtxt;
13use std::borrow::Cow;
14use std::cell::RefCell;
15use std::collections::VecDeque;
16use std::fmt::Debug;
17use std::ops::{Deref, DerefMut};
18use std::path::PathBuf;
19use std::sync::Arc;
20use std::{fmt, mem};
21
22pub(crate) use charon_lib::errors::{
24 DepSource, ErrorCtx, Level, error_assert, raise_error, register_error,
25};
26
27pub struct TranslateCtx<'tcx> {
29 pub tcx: TyCtxt<'tcx>,
31 pub sysroot: PathBuf,
33 pub hax_state: hax::StateWithBase<'tcx>,
35
36 pub options: TranslateOptions,
38 pub translated: TranslatedCrate,
40
41 pub method_status: IndexMap<TraitDeclId, IndexVec<TraitMethodId, MethodStatus>>,
50
51 pub id_map: HashMap<TransItemSource, ItemId>,
53 pub reverse_id_map: HashMap<ItemId, TransItemSource>,
55 pub assoc_item_id_map: HashMap<hax::DefId, AssocItemId>,
57 pub file_to_id: HashMap<FileName, FileId>,
59
60 pub errors: RefCell<ErrorCtx>,
62 pub items_to_translate: VecDeque<TransItemSource>,
64 pub processed: HashSet<TransItemSource>,
66 pub translate_stack: Vec<ItemId>,
68 pub cached_spans: HashMap<rustc_span::Span, meta::SpanData>,
70 pub cached_names: HashMap<RustcItem, Name>,
72 pub cached_item_metas: HashMap<TransItemSource, ItemMeta>,
74 pub lt_mutability_computer: LifetimeMutabilityComputer,
76}
77
78#[derive(Debug)]
80pub enum MethodStatus {
81 Unused {
82 implementors: HashSet<FunDeclId>,
86 },
87 Used,
88}
89
90impl Default for MethodStatus {
91 fn default() -> Self {
92 Self::Unused {
93 implementors: Default::default(),
94 }
95 }
96}
97
98pub(crate) struct ItemTransCtx<'tcx, 'ctx> {
101 pub item_src: TransItemSource,
103 pub item_id: Option<ItemId>,
105 pub t_ctx: &'ctx mut TranslateCtx<'tcx>,
107 pub hax_state: hax::StateWithOwner<'tcx>,
109 pub error_on_trait_proof_error: bool,
112
113 pub binding_levels: BindingStack<BindingLevel>,
117 pub lifetime_freshener: Option<IndexMap<RegionId, ()>>,
119}
120
121pub fn catch_sinto<S, T, U>(
123 s: &S,
124 err: &mut ErrorCtx,
125 krate: &TranslatedCrate,
126 span: Span,
127 x: &T,
128) -> Result<U, Error>
129where
130 T: Debug + SInto<S, U>,
131{
132 let unwind_safe_s = std::panic::AssertUnwindSafe(s);
133 let unwind_safe_x = std::panic::AssertUnwindSafe(x);
134 std::panic::catch_unwind(move || unwind_safe_x.sinto(*unwind_safe_s)).or_else(|_| {
135 raise_error!(
136 err,
137 crate(krate),
138 span,
139 "Hax panicked when translating `{x:?}`."
140 )
141 })
142}
143
144impl<'tcx> TranslateCtx<'tcx> {
145 pub fn span_err(&self, span: Span, msg: &str, level: Level) -> Error {
147 self.errors
148 .borrow_mut()
149 .span_err(&self.translated, span, msg, level)
150 }
151
152 pub fn get_target_triple(&self) -> TargetTriple {
153 self.tcx.sess.opts.target_triple.tuple().to_owned()
154 }
155
156 pub fn catch_sinto<S, T, U>(&mut self, s: &S, span: Span, x: &T) -> Result<U, Error>
158 where
159 T: Debug + SInto<S, U>,
160 {
161 catch_sinto(s, &mut self.errors.borrow_mut(), &self.translated, span, x)
162 }
163
164 pub fn poly_hax_def(&mut self, def_id: &hax::DefId) -> Result<Arc<hax::FullDef<'tcx>>, Error> {
169 self.hax_def_for_item(&RustcItem::Poly(def_id.clone()))
170 }
171
172 pub fn hax_def_for_item(&mut self, item: &RustcItem) -> Result<Arc<hax::FullDef<'tcx>>, Error> {
175 let def_id = item.def_id();
176 let span = self.def_span(def_id);
177 if let RustcItem::Mono(item_ref) = item
178 && item_ref.has_non_lt_param
179 {
180 raise_error!(self, span, "Item is not monomorphic: {item:?}")
181 }
182 let _guard = charon_lib::timing::scope("hax-full-def");
184 let unwind_safe_s = std::panic::AssertUnwindSafe(&self.hax_state);
185 std::panic::catch_unwind(move || match item {
186 RustcItem::Poly(def_id) => def_id.full_def(*unwind_safe_s),
187 RustcItem::Mono(item_ref) => item_ref.instantiated_full_def(*unwind_safe_s),
188 RustcItem::MonoTrait(def_id) => def_id.full_def(*unwind_safe_s),
189 })
190 .or_else(|_| raise_error!(self, span, "Hax panicked when translating `{def_id:?}`."))
191 }
192
193 pub(crate) fn with_def_id<F, T>(
194 &mut self,
195 def_id: &hax::DefId,
196 item_id: Option<ItemId>,
197 f: F,
198 ) -> T
199 where
200 F: FnOnce(&mut Self) -> T,
201 {
202 let mut errors = self.errors.borrow_mut();
203 let current_def_id = mem::replace(&mut errors.def_id, item_id);
204 let current_def_id_is_local = mem::replace(&mut errors.def_id_is_local, def_id.is_local());
205 drop(errors); let ret = f(self);
207 let mut errors = self.errors.borrow_mut();
208 errors.def_id = current_def_id;
209 errors.def_id_is_local = current_def_id_is_local;
210 ret
211 }
212}
213
214impl<'tcx, 'ctx> ItemTransCtx<'tcx, 'ctx> {
215 pub(crate) fn new(
217 item_src: TransItemSource,
218 item_id: Option<ItemId>,
219 t_ctx: &'ctx mut TranslateCtx<'tcx>,
220 ) -> Self {
221 use crate::hax::BaseState;
222 let hax_state_with_id = t_ctx.hax_state.clone().with_hax_owner(item_src.def_id());
223 ItemTransCtx {
224 item_src,
225 item_id,
226 t_ctx,
227 hax_state: hax_state_with_id,
228 error_on_trait_proof_error: true,
229 binding_levels: Default::default(),
230 lifetime_freshener: None,
231 }
232 }
233
234 pub fn monomorphize(&self) -> bool {
236 matches!(
237 self.item_src.item,
238 RustcItem::Mono(..) | RustcItem::MonoTrait(..)
239 )
240 }
241
242 pub fn span_err(&self, span: Span, msg: &str, level: Level) -> Error {
243 self.t_ctx.span_err(span, msg, level)
244 }
245
246 pub fn hax_state(&self) -> &hax::StateWithBase<'tcx> {
247 &self.t_ctx.hax_state
248 }
249
250 pub fn hax_state_with_id(&self) -> &hax::StateWithOwner<'tcx> {
251 &self.hax_state
252 }
253
254 pub fn catch_sinto<T, U>(&mut self, span: Span, x: &T) -> Result<U, Error>
255 where
256 T: Debug + SInto<hax::StateWithOwner<'tcx>, U>,
257 {
258 self.t_ctx.catch_sinto(&self.hax_state, span, x)
259 }
260
261 pub fn hax_def(&mut self, item: &hax::ItemRef) -> Result<Arc<hax::FullDef<'tcx>>, Error> {
264 let item = if self.monomorphize()
265 && !matches!(
266 self.item_src.kind,
267 TransItemSourceKind::TraitDecl | TransItemSourceKind::VTable
268 ) {
269 RustcItem::Mono(item.clone())
270 } else {
271 RustcItem::Poly(item.def_id.clone())
272 };
273 self.t_ctx.hax_def_for_item(&item)
274 }
275
276 pub(crate) fn poly_hax_def(
277 &mut self,
278 def_id: &hax::DefId,
279 ) -> Result<Arc<hax::FullDef<'tcx>>, Error> {
280 self.t_ctx.poly_hax_def(def_id)
281 }
282}
283
284impl<'tcx> Deref for ItemTransCtx<'tcx, '_> {
285 type Target = TranslateCtx<'tcx>;
286 fn deref(&self) -> &Self::Target {
287 self.t_ctx
288 }
289}
290impl<'tcx> DerefMut for ItemTransCtx<'tcx, '_> {
291 fn deref_mut(&mut self) -> &mut Self::Target {
292 self.t_ctx
293 }
294}
295
296impl<'a> IntoFormatter for &'a TranslateCtx<'_> {
297 type C = FmtCtx<'a>;
298 fn into_fmt(self) -> Self::C {
299 self.translated.into_fmt()
300 }
301}
302
303impl<'a> IntoFormatter for &'a ItemTransCtx<'_, '_> {
304 type C = FmtCtx<'a>;
305 fn into_fmt(self) -> Self::C {
306 FmtCtx {
307 translated: Some(&self.t_ctx.translated),
308 include_layouts: false,
309 hide_storage_statements: false,
310 current_type: None,
311 generics: self.binding_levels.map_ref(|bl| Cow::Borrowed(&bl.params)),
312 local_names: None,
313 indent_level: 0,
314 }
315 }
316}
317
318impl<'tcx> fmt::Display for TranslateCtx<'tcx> {
319 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
320 self.translated.fmt(f)
321 }
322}