1use super::translate_crate::RustcItem;
3pub use super::translate_crate::{TraitImplSource, TransItemSource, TransItemSourceKind};
4use super::translate_generics::BindingLevel;
5use charon_lib::ast::*;
6use charon_lib::formatter::{FmtCtx, IntoFormatter};
7use charon_lib::options::TranslateOptions;
8use hax::SInto;
9use rustc_middle::ty::TyCtxt;
10use std::borrow::Cow;
11use std::cell::RefCell;
12use std::collections::{BTreeSet, HashMap, HashSet};
13use std::fmt::Debug;
14use std::ops::{Deref, DerefMut};
15use std::path::PathBuf;
16use std::sync::Arc;
17use std::{fmt, mem};
18
19pub(crate) use charon_lib::errors::{
21 DepSource, ErrorCtx, Level, error_assert, raise_error, register_error,
22};
23
24pub struct TranslateCtx<'tcx> {
26 pub tcx: TyCtxt<'tcx>,
28 pub sysroot: PathBuf,
30 pub hax_state: hax::StateWithBase<'tcx>,
32
33 pub options: TranslateOptions,
35 pub translated: TranslatedCrate,
37
38 pub method_status: Vector<TraitDeclId, HashMap<TraitItemName, MethodStatus>>,
47
48 pub id_map: HashMap<TransItemSource, ItemId>,
50 pub reverse_id_map: HashMap<ItemId, TransItemSource>,
52 pub file_to_id: HashMap<FileName, FileId>,
54
55 pub errors: RefCell<ErrorCtx>,
57 pub items_to_translate: BTreeSet<TransItemSource>,
60 pub processed: HashSet<TransItemSource>,
62 pub translate_stack: Vec<ItemId>,
64 pub cached_names: HashMap<RustcItem, Name>,
66 pub cached_item_metas: HashMap<TransItemSource, ItemMeta>,
68}
69
70#[derive(Debug)]
72pub enum MethodStatus {
73 Unused {
74 implementors: HashSet<FunDeclId>,
78 },
79 Used,
80}
81
82impl Default for MethodStatus {
83 fn default() -> Self {
84 Self::Unused {
85 implementors: Default::default(),
86 }
87 }
88}
89
90pub(crate) struct ItemTransCtx<'tcx, 'ctx> {
93 pub item_src: TransItemSource,
95 pub item_id: Option<ItemId>,
97 pub t_ctx: &'ctx mut TranslateCtx<'tcx>,
99 pub hax_state_with_id: hax::StateWithOwner<'tcx>,
101 pub error_on_impl_expr_error: bool,
104
105 pub binding_levels: BindingStack<BindingLevel>,
109}
110
111pub fn catch_sinto<S, T, U>(
113 s: &S,
114 err: &mut ErrorCtx,
115 krate: &TranslatedCrate,
116 span: Span,
117 x: &T,
118) -> Result<U, Error>
119where
120 T: Debug + SInto<S, U>,
121{
122 let unwind_safe_s = std::panic::AssertUnwindSafe(s);
123 let unwind_safe_x = std::panic::AssertUnwindSafe(x);
124 std::panic::catch_unwind(move || unwind_safe_x.sinto(*unwind_safe_s)).or_else(|_| {
125 raise_error!(
126 err,
127 crate(krate),
128 span,
129 "Hax panicked when translating `{x:?}`."
130 )
131 })
132}
133
134impl<'tcx, 'ctx> TranslateCtx<'tcx> {
135 pub fn span_err(&self, span: Span, msg: &str, level: Level) -> Error {
137 self.errors
138 .borrow_mut()
139 .span_err(&self.translated, span, msg, level)
140 }
141
142 pub fn catch_sinto<S, T, U>(&mut self, s: &S, span: Span, x: &T) -> Result<U, Error>
144 where
145 T: Debug + SInto<S, U>,
146 {
147 catch_sinto(s, &mut *self.errors.borrow_mut(), &self.translated, span, x)
148 }
149
150 pub fn poly_hax_def(&mut self, def_id: &hax::DefId) -> Result<Arc<hax::FullDef>, Error> {
155 self.hax_def_for_item(&RustcItem::Poly(def_id.clone()))
156 }
157
158 pub fn hax_def_for_item(&mut self, item: &RustcItem) -> Result<Arc<hax::FullDef>, Error> {
161 let def_id = item.def_id();
162 let span = self.def_span(def_id);
163 if let RustcItem::Mono(item_ref) = item
164 && item_ref.has_non_lt_param
165 {
166 raise_error!(self, span, "Item is not monomorphic: {item:?}")
167 }
168 let unwind_safe_s = std::panic::AssertUnwindSafe(&self.hax_state);
170 std::panic::catch_unwind(move || match item {
171 RustcItem::Poly(def_id) => def_id.full_def(*unwind_safe_s),
172 RustcItem::Mono(item_ref) => item_ref.instantiated_full_def(*unwind_safe_s),
173 })
174 .or_else(|_| raise_error!(self, span, "Hax panicked when translating `{def_id:?}`."))
175 }
176
177 pub(crate) fn with_def_id<F, T>(
178 &mut self,
179 def_id: &hax::DefId,
180 item_id: Option<ItemId>,
181 f: F,
182 ) -> T
183 where
184 F: FnOnce(&mut Self) -> T,
185 {
186 let mut errors = self.errors.borrow_mut();
187 let current_def_id = mem::replace(&mut errors.def_id, item_id);
188 let current_def_id_is_local = mem::replace(&mut errors.def_id_is_local, def_id.is_local);
189 drop(errors); let ret = f(self);
191 let mut errors = self.errors.borrow_mut();
192 errors.def_id = current_def_id;
193 errors.def_id_is_local = current_def_id_is_local;
194 ret
195 }
196}
197
198impl<'tcx, 'ctx> ItemTransCtx<'tcx, 'ctx> {
199 pub(crate) fn new(
201 item_src: TransItemSource,
202 item_id: Option<ItemId>,
203 t_ctx: &'ctx mut TranslateCtx<'tcx>,
204 ) -> Self {
205 use hax::BaseState;
206 let def_id = item_src.def_id().underlying_rust_def_id();
207 let hax_state_with_id = t_ctx.hax_state.clone().with_owner_id(def_id);
208 ItemTransCtx {
209 item_src,
210 item_id,
211 t_ctx,
212 hax_state_with_id,
213 error_on_impl_expr_error: true,
214 binding_levels: Default::default(),
215 }
216 }
217
218 pub fn monomorphize(&self) -> bool {
220 matches!(self.item_src.item, RustcItem::Mono(..))
221 }
222
223 pub fn span_err(&self, span: Span, msg: &str, level: Level) -> Error {
224 self.t_ctx.span_err(span, msg, level)
225 }
226
227 pub fn hax_state(&self) -> &hax::StateWithBase<'tcx> {
228 &self.t_ctx.hax_state
229 }
230
231 pub fn hax_state_with_id(&self) -> &hax::StateWithOwner<'tcx> {
232 &self.hax_state_with_id
233 }
234
235 pub fn hax_def(&mut self, item: &hax::ItemRef) -> Result<Arc<hax::FullDef>, Error> {
238 let item = if self.monomorphize() {
239 RustcItem::Mono(item.clone())
240 } else {
241 RustcItem::Poly(item.def_id.clone())
242 };
243 self.t_ctx.hax_def_for_item(&item)
244 }
245
246 pub(crate) fn poly_hax_def(&mut self, def_id: &hax::DefId) -> Result<Arc<hax::FullDef>, Error> {
247 self.t_ctx.poly_hax_def(def_id)
248 }
249}
250
251impl<'tcx> Deref for ItemTransCtx<'tcx, '_> {
252 type Target = TranslateCtx<'tcx>;
253 fn deref(&self) -> &Self::Target {
254 self.t_ctx
255 }
256}
257impl<'tcx> DerefMut for ItemTransCtx<'tcx, '_> {
258 fn deref_mut(&mut self) -> &mut Self::Target {
259 self.t_ctx
260 }
261}
262
263impl<'a> IntoFormatter for &'a TranslateCtx<'_> {
264 type C = FmtCtx<'a>;
265 fn into_fmt(self) -> Self::C {
266 self.translated.into_fmt()
267 }
268}
269
270impl<'a> IntoFormatter for &'a ItemTransCtx<'_, '_> {
271 type C = FmtCtx<'a>;
272 fn into_fmt(self) -> Self::C {
273 FmtCtx {
274 translated: Some(&self.t_ctx.translated),
275 generics: self.binding_levels.map_ref(|bl| Cow::Borrowed(&bl.params)),
276 locals: None,
277 indent_level: 0,
278 }
279 }
280}
281
282impl<'tcx, 'ctx> fmt::Display for TranslateCtx<'tcx> {
283 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
284 self.translated.fmt(f)
285 }
286}