1use super::translate_crate::RustcItem;
3pub use super::translate_crate::{TraitImplSource, 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_names: HashMap<RustcItem, Name>,
70 pub cached_item_metas: HashMap<TransItemSource, ItemMeta>,
72 pub lt_mutability_computer: LifetimeMutabilityComputer,
74}
75
76#[derive(Debug)]
78pub enum MethodStatus {
79 Unused {
80 implementors: HashSet<FunDeclId>,
84 },
85 Used,
86}
87
88impl Default for MethodStatus {
89 fn default() -> Self {
90 Self::Unused {
91 implementors: Default::default(),
92 }
93 }
94}
95
96pub(crate) struct ItemTransCtx<'tcx, 'ctx> {
99 pub item_src: TransItemSource,
101 pub item_id: Option<ItemId>,
103 pub t_ctx: &'ctx mut TranslateCtx<'tcx>,
105 pub hax_state: hax::StateWithOwner<'tcx>,
107 pub error_on_trait_proof_error: bool,
110
111 pub binding_levels: BindingStack<BindingLevel>,
115 pub lifetime_freshener: Option<IndexMap<RegionId, ()>>,
117}
118
119pub fn catch_sinto<S, T, U>(
121 s: &S,
122 err: &mut ErrorCtx,
123 krate: &TranslatedCrate,
124 span: Span,
125 x: &T,
126) -> Result<U, Error>
127where
128 T: Debug + SInto<S, U>,
129{
130 let unwind_safe_s = std::panic::AssertUnwindSafe(s);
131 let unwind_safe_x = std::panic::AssertUnwindSafe(x);
132 std::panic::catch_unwind(move || unwind_safe_x.sinto(*unwind_safe_s)).or_else(|_| {
133 raise_error!(
134 err,
135 crate(krate),
136 span,
137 "Hax panicked when translating `{x:?}`."
138 )
139 })
140}
141
142impl<'tcx> TranslateCtx<'tcx> {
143 pub fn span_err(&self, span: Span, msg: &str, level: Level) -> Error {
145 self.errors
146 .borrow_mut()
147 .span_err(&self.translated, span, msg, level)
148 }
149
150 pub fn get_target_triple(&self) -> TargetTriple {
151 self.tcx.sess.opts.target_triple.tuple().to_owned()
152 }
153
154 pub fn catch_sinto<S, T, U>(&mut self, s: &S, span: Span, x: &T) -> Result<U, Error>
156 where
157 T: Debug + SInto<S, U>,
158 {
159 catch_sinto(s, &mut self.errors.borrow_mut(), &self.translated, span, x)
160 }
161
162 pub fn poly_hax_def(&mut self, def_id: &hax::DefId) -> Result<Arc<hax::FullDef<'tcx>>, Error> {
167 self.hax_def_for_item(&RustcItem::Poly(def_id.clone()))
168 }
169
170 pub fn hax_def_for_item(&mut self, item: &RustcItem) -> Result<Arc<hax::FullDef<'tcx>>, Error> {
173 let def_id = item.def_id();
174 let span = self.def_span(def_id);
175 if let RustcItem::Mono(item_ref) = item
176 && item_ref.has_non_lt_param
177 {
178 raise_error!(self, span, "Item is not monomorphic: {item:?}")
179 }
180 let unwind_safe_s = std::panic::AssertUnwindSafe(&self.hax_state);
182 std::panic::catch_unwind(move || match item {
183 RustcItem::Poly(def_id) => def_id.full_def(*unwind_safe_s),
184 RustcItem::Mono(item_ref) => item_ref.instantiated_full_def(*unwind_safe_s),
185 RustcItem::MonoTrait(def_id) => def_id.full_def(*unwind_safe_s),
186 })
187 .or_else(|_| raise_error!(self, span, "Hax panicked when translating `{def_id:?}`."))
188 }
189
190 pub(crate) fn with_def_id<F, T>(
191 &mut self,
192 def_id: &hax::DefId,
193 item_id: Option<ItemId>,
194 f: F,
195 ) -> T
196 where
197 F: FnOnce(&mut Self) -> T,
198 {
199 let mut errors = self.errors.borrow_mut();
200 let current_def_id = mem::replace(&mut errors.def_id, item_id);
201 let current_def_id_is_local = mem::replace(&mut errors.def_id_is_local, def_id.is_local());
202 drop(errors); let ret = f(self);
204 let mut errors = self.errors.borrow_mut();
205 errors.def_id = current_def_id;
206 errors.def_id_is_local = current_def_id_is_local;
207 ret
208 }
209}
210
211impl<'tcx, 'ctx> ItemTransCtx<'tcx, 'ctx> {
212 pub(crate) fn new(
214 item_src: TransItemSource,
215 item_id: Option<ItemId>,
216 t_ctx: &'ctx mut TranslateCtx<'tcx>,
217 ) -> Self {
218 use crate::hax::BaseState;
219 let hax_state_with_id = t_ctx.hax_state.clone().with_hax_owner(item_src.def_id());
220 ItemTransCtx {
221 item_src,
222 item_id,
223 t_ctx,
224 hax_state: hax_state_with_id,
225 error_on_trait_proof_error: true,
226 binding_levels: Default::default(),
227 lifetime_freshener: None,
228 }
229 }
230
231 pub fn monomorphize(&self) -> bool {
233 matches!(
234 self.item_src.item,
235 RustcItem::Mono(..) | RustcItem::MonoTrait(..)
236 )
237 }
238
239 pub fn span_err(&self, span: Span, msg: &str, level: Level) -> Error {
240 self.t_ctx.span_err(span, msg, level)
241 }
242
243 pub fn hax_state(&self) -> &hax::StateWithBase<'tcx> {
244 &self.t_ctx.hax_state
245 }
246
247 pub fn hax_state_with_id(&self) -> &hax::StateWithOwner<'tcx> {
248 &self.hax_state
249 }
250
251 pub fn catch_sinto<T, U>(&mut self, span: Span, x: &T) -> Result<U, Error>
252 where
253 T: Debug + SInto<hax::StateWithOwner<'tcx>, U>,
254 {
255 self.t_ctx.catch_sinto(&self.hax_state, span, x)
256 }
257
258 pub fn hax_def(&mut self, item: &hax::ItemRef) -> Result<Arc<hax::FullDef<'tcx>>, Error> {
261 let item = if self.monomorphize()
262 && !matches!(
263 self.item_src.kind,
264 TransItemSourceKind::TraitDecl | TransItemSourceKind::VTable
265 ) {
266 RustcItem::Mono(item.clone())
267 } else {
268 RustcItem::Poly(item.def_id.clone())
269 };
270 self.t_ctx.hax_def_for_item(&item)
271 }
272
273 pub(crate) fn poly_hax_def(
274 &mut self,
275 def_id: &hax::DefId,
276 ) -> Result<Arc<hax::FullDef<'tcx>>, Error> {
277 self.t_ctx.poly_hax_def(def_id)
278 }
279}
280
281impl<'tcx> Deref for ItemTransCtx<'tcx, '_> {
282 type Target = TranslateCtx<'tcx>;
283 fn deref(&self) -> &Self::Target {
284 self.t_ctx
285 }
286}
287impl<'tcx> DerefMut for ItemTransCtx<'tcx, '_> {
288 fn deref_mut(&mut self) -> &mut Self::Target {
289 self.t_ctx
290 }
291}
292
293impl<'a> IntoFormatter for &'a TranslateCtx<'_> {
294 type C = FmtCtx<'a>;
295 fn into_fmt(self) -> Self::C {
296 self.translated.into_fmt()
297 }
298}
299
300impl<'a> IntoFormatter for &'a ItemTransCtx<'_, '_> {
301 type C = FmtCtx<'a>;
302 fn into_fmt(self) -> Self::C {
303 FmtCtx {
304 translated: Some(&self.t_ctx.translated),
305 generics: self.binding_levels.map_ref(|bl| Cow::Borrowed(&bl.params)),
306 locals: None,
307 indent_level: 0,
308 }
309 }
310}
311
312impl<'tcx> fmt::Display for TranslateCtx<'tcx> {
313 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
314 self.translated.fmt(f)
315 }
316}