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 petgraph::graphmap::DiGraphMap;
12use rustc_hash::{FxHashMap as HashMap, FxHashSet as HashSet};
13use rustc_middle::ty::TyCtxt;
14use rustc_span::def_id::DefId as RDefId;
15use std::borrow::Cow;
16use std::cell::RefCell;
17use std::collections::VecDeque;
18use std::fmt::Debug;
19use std::ops::{Deref, DerefMut};
20use std::path::PathBuf;
21use std::sync::Arc;
22use std::{fmt, mem};
23
24pub(crate) use charon_lib::errors::{
26 DepSource, ErrorCtx, Level, error_assert, raise_error, register_error,
27};
28
29#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
30pub enum ItemOrModuleId {
31 Item(ItemId),
32 Module(RDefId),
34}
35
36impl Ord for ItemOrModuleId {
39 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
40 use std::cmp::Ordering;
41 match (self, other) {
42 (Self::Item(a), Self::Item(b)) => a.cmp(b),
43 (Self::Module(a), Self::Module(b)) => {
44 (a.krate.as_u32(), a.index.as_u32()).cmp(&(b.krate.as_u32(), b.index.as_u32()))
45 }
46 (Self::Item(_), Self::Module(_)) => Ordering::Less,
47 (Self::Module(_), Self::Item(_)) => Ordering::Greater,
48 }
49 }
50}
51
52impl PartialOrd for ItemOrModuleId {
53 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
54 Some(self.cmp(other))
55 }
56}
57
58impl ItemOrModuleId {
59 pub fn as_item(&self) -> Option<ItemId> {
60 match self {
61 Self::Item(id) => Some(*id),
62 Self::Module(_) => None,
63 }
64 }
65
66 pub fn expect_item<T: TryFrom<ItemId>>(&self) -> T {
67 self.as_item()
68 .expect("expected a translated item")
69 .try_into()
70 .ok()
71 .expect("unexpected item kind")
72 }
73}
74
75#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
77pub enum ContainmentNode {
78 Start,
79 Item(ItemOrModuleId),
80 TraitMethod(TraitDeclId, TraitMethodId),
81}
82
83impl From<ItemOrModuleId> for ContainmentNode {
84 fn from(id: ItemOrModuleId) -> Self {
85 Self::Item(id)
86 }
87}
88
89impl From<ItemId> for ContainmentNode {
90 fn from(id: ItemId) -> Self {
91 Self::Item(ItemOrModuleId::Item(id))
92 }
93}
94
95pub struct TranslateCtx<'tcx> {
97 pub tcx: TyCtxt<'tcx>,
99 pub sysroot: PathBuf,
101 pub hax_state: hax::StateWithBase<'tcx>,
103
104 pub options: TranslateOptions,
106 pub translated: TranslatedCrate,
108
109 pub method_status: IndexMap<TraitDeclId, IndexVec<TraitMethodId, MethodStatus>>,
118
119 pub id_map: HashMap<TransItemSource<'tcx>, ItemId>,
121 pub reverse_id_map: HashMap<ItemId, TransItemSource<'tcx>>,
123 pub assoc_item_id_map: HashMap<hax::DefId, AssocItemId>,
125 pub file_to_id: HashMap<FileName, FileId>,
127
128 pub errors: RefCell<ErrorCtx>,
130 pub items_to_translate: VecDeque<TransItemSource<'tcx>>,
132 pub processed: HashSet<TransItemSource<'tcx>>,
134 pub containment_graph: DiGraphMap<ContainmentNode, (), rustc_hash::FxBuildHasher>,
138 pub translate_stack: Vec<ItemOrModuleId>,
140 pub cached_spans: HashMap<rustc_span::Span, meta::SpanData>,
142 pub cached_file_ids: HashMap<rustc_span::StableSourceFileId, FileId>,
144 pub cached_names: HashMap<RustcItem<'tcx>, Name>,
146 pub cached_item_metas: HashMap<TransItemSource<'tcx>, ItemMeta>,
148 pub lt_mutability_computer: LifetimeMutabilityComputer,
150}
151
152#[derive(Debug)]
154pub enum MethodStatus {
155 Unused {
156 implementors: HashSet<FunDeclId>,
160 },
161 Used,
162}
163
164impl Default for MethodStatus {
165 fn default() -> Self {
166 Self::Unused {
167 implementors: Default::default(),
168 }
169 }
170}
171
172pub(crate) struct ItemTransCtx<'tcx, 'ctx> {
175 pub item_src: TransItemSource<'tcx>,
177 pub item_id: ItemOrModuleId,
179 pub t_ctx: &'ctx mut TranslateCtx<'tcx>,
181 pub hax_state: hax::StateWithOwner<'tcx>,
183 pub error_on_trait_proof_error: bool,
186
187 pub binding_levels: BindingStack<BindingLevel<'tcx>>,
191 pub lifetime_freshener: Option<IndexMap<RegionId, ()>>,
193}
194
195pub fn catch_sinto<S, T, U>(
197 s: &S,
198 err: &mut ErrorCtx,
199 krate: &TranslatedCrate,
200 span: Span,
201 x: &T,
202) -> Result<U, Error>
203where
204 T: Debug + SInto<S, U>,
205{
206 let unwind_safe_s = std::panic::AssertUnwindSafe(s);
207 let unwind_safe_x = std::panic::AssertUnwindSafe(x);
208 std::panic::catch_unwind(move || unwind_safe_x.sinto(*unwind_safe_s)).or_else(|_| {
209 raise_error!(
210 err,
211 crate(krate),
212 span,
213 "Hax panicked when translating `{x:?}`."
214 )
215 })
216}
217
218impl<'tcx> TranslateCtx<'tcx> {
219 pub fn span_err(&self, span: Span, msg: &str, level: Level) -> Error {
221 self.errors
222 .borrow_mut()
223 .span_err(&self.translated, span, msg, level)
224 }
225
226 pub fn get_target_triple(&self) -> TargetTriple {
227 self.tcx.sess.opts.target_triple.tuple().to_owned()
228 }
229
230 pub fn catch_sinto<S, T, U>(&mut self, s: &S, span: Span, x: &T) -> Result<U, Error>
232 where
233 T: Debug + SInto<S, U>,
234 {
235 catch_sinto(s, &mut self.errors.borrow_mut(), &self.translated, span, x)
236 }
237
238 pub fn poly_hax_def(&mut self, def_id: &hax::DefId) -> Result<Arc<hax::FullDef<'tcx>>, Error> {
243 self.hax_def_for_item(&RustcItem::Poly(def_id.clone()))
244 }
245
246 pub fn hax_def_for_item(
249 &mut self,
250 item: &RustcItem<'tcx>,
251 ) -> Result<Arc<hax::FullDef<'tcx>>, Error> {
252 let def_id = item.def_id();
253 let span = self.def_span(def_id);
254 if let RustcItem::Mono(item_ref) = item
255 && item_ref.has_non_lt_param
256 {
257 raise_error!(self, span, "Item is not monomorphic: {item:?}")
258 }
259 let _guard = charon_lib::timing::scope("hax-full-def");
261 let unwind_safe_s = std::panic::AssertUnwindSafe(&self.hax_state);
262 std::panic::catch_unwind(move || match item {
263 RustcItem::Poly(def_id) => def_id.full_def(*unwind_safe_s),
264 RustcItem::Mono(item_ref) => item_ref.instantiated_full_def(*unwind_safe_s),
265 RustcItem::MonoTrait(def_id) => def_id.full_def(*unwind_safe_s),
266 })
267 .or_else(|_| raise_error!(self, span, "Hax panicked when translating `{def_id:?}`."))
268 }
269
270 pub(crate) fn with_def_id<F, T>(
271 &mut self,
272 def_id: &hax::DefId,
273 item_id: &ItemOrModuleId,
274 f: F,
275 ) -> T
276 where
277 F: FnOnce(&mut Self) -> T,
278 {
279 let mut errors = self.errors.borrow_mut();
280 let current_def_id = mem::replace(&mut errors.def_id, item_id.as_item());
281 let current_def_id_is_local = mem::replace(&mut errors.def_id_is_local, def_id.is_local());
282 drop(errors); let ret = f(self);
284 let mut errors = self.errors.borrow_mut();
285 errors.def_id = current_def_id;
286 errors.def_id_is_local = current_def_id_is_local;
287 ret
288 }
289}
290
291impl<'tcx, 'ctx> ItemTransCtx<'tcx, 'ctx> {
292 pub(crate) fn new(
294 item_src: TransItemSource<'tcx>,
295 item_id: ItemOrModuleId,
296 t_ctx: &'ctx mut TranslateCtx<'tcx>,
297 ) -> Self {
298 use crate::hax::BaseState;
299 let hax_state_with_id = t_ctx.hax_state.clone().with_hax_owner(item_src.def_id());
300 ItemTransCtx {
301 item_src,
302 item_id,
303 t_ctx,
304 hax_state: hax_state_with_id,
305 error_on_trait_proof_error: true,
306 binding_levels: Default::default(),
307 lifetime_freshener: None,
308 }
309 }
310
311 pub fn monomorphize(&self) -> bool {
313 matches!(
314 self.item_src.item,
315 RustcItem::Mono(..) | RustcItem::MonoTrait(..)
316 )
317 }
318
319 pub fn should_monomorphize_item(&self, item: &hax::ItemRef, kind: TransItemSourceKind) -> bool {
321 self.options.monomorphize_with_hax && (kind.is_for_trait() || !item.has_non_lt_param)
324 }
325
326 pub fn span_err(&self, span: Span, msg: &str, level: Level) -> Error {
327 self.t_ctx.span_err(span, msg, level)
328 }
329
330 pub fn hax_state(&self) -> &hax::StateWithBase<'tcx> {
331 &self.t_ctx.hax_state
332 }
333
334 pub fn hax_state_with_id(&self) -> &hax::StateWithOwner<'tcx> {
335 &self.hax_state
336 }
337
338 pub fn catch_sinto<T, U>(&mut self, span: Span, x: &T) -> Result<U, Error>
339 where
340 T: Debug + SInto<hax::StateWithOwner<'tcx>, U>,
341 {
342 self.t_ctx.catch_sinto(&self.hax_state, span, x)
343 }
344
345 pub fn hax_def(&mut self, item: &hax::ItemRef<'tcx>) -> Result<Arc<hax::FullDef<'tcx>>, Error> {
348 let item = if self.monomorphize() && !self.item_src.kind.is_for_trait() {
349 RustcItem::Mono(item.clone())
350 } else {
351 RustcItem::Poly(item.def_id.clone())
352 };
353 self.t_ctx.hax_def_for_item(&item)
354 }
355
356 pub(crate) fn poly_hax_def(
357 &mut self,
358 def_id: &hax::DefId,
359 ) -> Result<Arc<hax::FullDef<'tcx>>, Error> {
360 self.t_ctx.poly_hax_def(def_id)
361 }
362}
363
364impl<'tcx> Deref for ItemTransCtx<'tcx, '_> {
365 type Target = TranslateCtx<'tcx>;
366 fn deref(&self) -> &Self::Target {
367 self.t_ctx
368 }
369}
370impl<'tcx> DerefMut for ItemTransCtx<'tcx, '_> {
371 fn deref_mut(&mut self) -> &mut Self::Target {
372 self.t_ctx
373 }
374}
375
376impl<'a> IntoFormatter for &'a TranslateCtx<'_> {
377 type C = FmtCtx<'a>;
378 fn into_fmt(self) -> Self::C {
379 self.translated.into_fmt()
380 }
381}
382
383impl<'a> IntoFormatter for &'a ItemTransCtx<'_, '_> {
384 type C = FmtCtx<'a>;
385 fn into_fmt(self) -> Self::C {
386 FmtCtx {
387 translated: Some(&self.t_ctx.translated),
388 include_layouts: false,
389 include_safety: false,
390 hide_storage_statements: false,
391 current_type: None,
392 generics: self.binding_levels.map_ref(|bl| Cow::Borrowed(&bl.params)),
393 local_names: None,
394 indent_level: 0,
395 }
396 }
397}
398
399impl<'tcx> fmt::Display for TranslateCtx<'tcx> {
400 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
401 self.translated.fmt(f)
402 }
403}