1use super::translate_types::translate_bound_region_kind_name;
3use charon_lib::ast::*;
4use charon_lib::common::hash_by_addr::HashByAddr;
5use charon_lib::formatter::{FmtCtx, IntoFormatter};
6use charon_lib::ids::Vector;
7use charon_lib::options::TranslateOptions;
8use hax_frontend_exporter::SInto;
9use hax_frontend_exporter::{self as hax, DefPathItem};
10use itertools::Itertools;
11use macros::VariantIndexArity;
12use rustc_middle::ty::TyCtxt;
13use std::borrow::Cow;
14use std::cell::RefCell;
15use std::cmp::Ord;
16use std::collections::{BTreeSet, HashMap, HashSet};
17use std::fmt::Debug;
18use std::path::{Component, PathBuf};
19use std::sync::Arc;
20use std::{fmt, mem};
21
22pub(crate) use charon_lib::errors::{
24 error_assert, raise_error, register_error, DepSource, ErrorCtx, Level,
25};
26
27#[derive(Clone, Debug, PartialEq, Eq, Hash, VariantIndexArity)]
31pub enum TransItemSource {
32 Global(hax::DefId),
33 TraitDecl(hax::DefId),
34 TraitImpl(hax::DefId),
35 Fun(hax::DefId),
36 Type(hax::DefId),
37}
38
39impl TransItemSource {
40 pub(crate) fn as_def_id(&self) -> &hax::DefId {
41 match self {
42 TransItemSource::Global(id)
43 | TransItemSource::TraitDecl(id)
44 | TransItemSource::TraitImpl(id)
45 | TransItemSource::Fun(id)
46 | TransItemSource::Type(id) => id,
47 }
48 }
49}
50
51impl TransItemSource {
52 fn sort_key(&self) -> impl Ord {
54 let (variant_index, _) = self.variant_index_arity();
55 let def_id = self.as_def_id();
56 (def_id.index, variant_index)
57 }
58}
59
60impl PartialOrd for TransItemSource {
62 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
63 Some(self.cmp(other))
64 }
65}
66impl Ord for TransItemSource {
67 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
68 self.sort_key().cmp(&other.sort_key())
69 }
70}
71
72pub struct TranslateCtx<'tcx> {
74 pub tcx: TyCtxt<'tcx>,
76 pub sysroot: PathBuf,
78 pub hax_state: hax::StateWithBase<'tcx>,
80
81 pub options: TranslateOptions,
83 pub translated: TranslatedCrate,
85
86 pub id_map: HashMap<TransItemSource, AnyTransId>,
88 pub reverse_id_map: HashMap<AnyTransId, TransItemSource>,
90 pub file_to_id: HashMap<FileName, FileId>,
92
93 pub errors: RefCell<ErrorCtx>,
95 pub items_to_translate: BTreeSet<TransItemSource>,
98 pub processed: HashSet<TransItemSource>,
100 pub cached_names: HashMap<hax::DefId, Name>,
102 pub cached_item_metas: HashMap<hax::DefId, ItemMeta>,
104}
105
106#[derive(Debug)]
118pub(crate) struct BindingLevel {
119 pub params: GenericParams,
121 pub is_item_binder: bool,
125 pub early_region_vars: std::collections::BTreeMap<hax::EarlyParamRegion, RegionId>,
132 pub bound_region_vars: Vec<RegionId>,
134 pub type_vars_map: HashMap<u32, TypeVarId>,
136 pub const_generic_vars_map: HashMap<u32, ConstGenericVarId>,
138 pub type_trans_cache: HashMap<HashByAddr<Arc<hax::TyKind>>, Ty>,
140}
141
142impl BindingLevel {
143 pub(crate) fn new(is_item_binder: bool) -> Self {
144 Self {
145 params: Default::default(),
146 is_item_binder,
147 early_region_vars: Default::default(),
148 bound_region_vars: Default::default(),
149 type_vars_map: Default::default(),
150 const_generic_vars_map: Default::default(),
151 type_trans_cache: Default::default(),
152 }
153 }
154
155 pub(crate) fn push_early_region(&mut self, region: hax::EarlyParamRegion) -> RegionId {
157 let name = super::translate_types::translate_region_name(®ion);
158 assert!(
160 self.bound_region_vars.is_empty(),
161 "Early regions must be tralsnated before late ones"
162 );
163 let rid = self
164 .params
165 .regions
166 .push_with(|index| RegionVar { index, name });
167 self.early_region_vars.insert(region, rid);
168 rid
169 }
170
171 pub(crate) fn push_bound_region(&mut self, region: hax::BoundRegionKind) -> RegionId {
173 let name = translate_bound_region_kind_name(®ion);
174 let rid = self
175 .params
176 .regions
177 .push_with(|index| RegionVar { index, name });
178 self.bound_region_vars.push(rid);
179 rid
180 }
181
182 pub(crate) fn push_type_var(&mut self, rid: u32, name: String) -> TypeVarId {
183 let var_id = self.params.types.push_with(|index| TypeVar { index, name });
184 self.type_vars_map.insert(rid, var_id);
185 var_id
186 }
187
188 pub(crate) fn push_const_generic_var(&mut self, rid: u32, ty: LiteralTy, name: String) {
189 let var_id = self
190 .params
191 .const_generics
192 .push_with(|index| ConstGenericVar { index, name, ty });
193 self.const_generic_vars_map.insert(rid, var_id);
194 }
195
196 pub(crate) fn push_params_from_binder(&mut self, binder: hax::Binder<()>) -> Result<(), Error> {
198 use hax::BoundVariableKind::*;
199 for p in binder.bound_vars {
200 match p {
201 Region(region) => {
202 self.push_bound_region(region);
203 }
204 Ty(_) => {
205 panic!("Unexpected locally bound type variable");
206 }
207 Const => {
208 panic!("Unexpected locally bound const generic variable");
209 }
210 }
211 }
212 Ok(())
213 }
214}
215
216pub(crate) struct ItemTransCtx<'tcx, 'ctx> {
219 pub def_id: hax::DefId,
222 pub item_id: Option<AnyTransId>,
224 pub t_ctx: &'ctx mut TranslateCtx<'tcx>,
226 pub error_on_impl_expr_error: bool,
229
230 pub binding_levels: BindingStack<BindingLevel>,
234 pub parent_trait_clauses: Vector<TraitClauseId, TraitClause>,
236 pub item_trait_clauses: HashMap<TraitItemName, Vector<TraitClauseId, TraitClause>>,
238}
239
240pub fn catch_sinto<S, T, U>(
242 s: &S,
243 err: &mut ErrorCtx,
244 krate: &TranslatedCrate,
245 span: Span,
246 x: &T,
247) -> Result<U, Error>
248where
249 T: Debug + SInto<S, U>,
250{
251 let unwind_safe_s = std::panic::AssertUnwindSafe(s);
252 let unwind_safe_x = std::panic::AssertUnwindSafe(x);
253 std::panic::catch_unwind(move || unwind_safe_x.sinto(*unwind_safe_s)).or_else(|_| {
254 raise_error!(
255 err,
256 crate(krate),
257 span,
258 "Hax panicked when translating `{x:?}`."
259 )
260 })
261}
262
263impl<'tcx, 'ctx> TranslateCtx<'tcx> {
264 pub fn span_err(&self, span: Span, msg: &str, level: Level) -> Error {
266 self.errors
267 .borrow_mut()
268 .span_err(&self.translated, span, msg, level)
269 }
270
271 fn register_file(&mut self, filename: FileName, span: rustc_span::Span) -> FileId {
274 match self.file_to_id.get(&filename) {
276 Some(id) => *id,
277 None => {
278 let source_file = self.tcx.sess.source_map().lookup_source_file(span.lo());
279 let file = File {
280 name: filename.clone(),
281 contents: source_file.src.as_deref().cloned(),
282 };
283 let id = self.translated.files.push(file);
284 self.file_to_id.insert(filename, id);
285 id
286 }
287 }
288 }
289
290 fn path_elem_for_def(
291 &mut self,
292 span: Span,
293 def_id: &hax::DefId,
294 ) -> Result<Option<PathElem>, Error> {
295 let path_elem = def_id.path_item();
296 let disambiguator = Disambiguator::new(path_elem.disambiguator as usize);
299 let path_elem = match path_elem.data {
301 DefPathItem::CrateRoot { name, .. } => {
302 error_assert!(self, span, path_elem.disambiguator == 0);
304 Some(PathElem::Ident(name.clone(), disambiguator))
305 }
306 DefPathItem::TypeNs(None) => None,
309 DefPathItem::TypeNs(Some(symbol))
310 | DefPathItem::ValueNs(symbol)
311 | DefPathItem::MacroNs(symbol) => Some(PathElem::Ident(symbol, disambiguator)),
312 DefPathItem::Impl => {
313 let full_def = self.hax_def(def_id)?;
314 let impl_elem = match full_def.kind() {
318 hax::FullDefKind::InherentImpl { ty, .. } => {
320 let mut bt_ctx = ItemTransCtx::new(def_id.clone(), None, self);
324 bt_ctx.translate_def_generics(span, &full_def)?;
325 let ty = bt_ctx.translate_ty(span, &ty)?;
326 ImplElem::Ty(Binder {
327 kind: BinderKind::InherentImplBlock,
328 params: bt_ctx.into_generics(),
329 skip_binder: ty,
330 })
331 }
332 hax::FullDefKind::TraitImpl { .. } => {
334 let impl_id = self.register_trait_impl_id(&None, def_id);
335 ImplElem::Trait(impl_id)
336 }
337 _ => unreachable!(),
338 };
339
340 Some(PathElem::Impl(impl_elem, disambiguator))
341 }
342 DefPathItem::OpaqueTy => None,
344 DefPathItem::Closure => Some(PathElem::Ident("closure".to_string(), disambiguator)),
348 DefPathItem::ForeignMod => None,
351 DefPathItem::Ctor => None,
354 DefPathItem::Use => Some(PathElem::Ident("{use}".to_string(), disambiguator)),
355 DefPathItem::AnonConst => Some(PathElem::Ident("{const}".to_string(), disambiguator)),
356 DefPathItem::PromotedConst => Some(PathElem::Ident(
357 "{promoted_const}".to_string(),
358 disambiguator,
359 )),
360 _ => {
361 raise_error!(
362 self,
363 span,
364 "Unexpected DefPathItem for `{def_id:?}`: {path_elem:?}"
365 );
366 }
367 };
368 Ok(path_elem)
369 }
370
371 pub fn hax_def_id_to_name(&mut self, def_id: &hax::DefId) -> Result<Name, Error> {
413 if let Some(name) = self.cached_names.get(&def_id) {
414 return Ok(name.clone());
415 }
416 trace!("Computing name for `{def_id:?}`");
417
418 let parent_name = if let Some(parent) = &def_id.parent {
419 self.hax_def_id_to_name(parent)?
420 } else {
421 Name { name: Vec::new() }
422 };
423 let span = self.def_span(def_id);
424 let mut name = parent_name;
425 if let Some(path_elem) = self.path_elem_for_def(span, &def_id)? {
426 name.name.push(path_elem);
427 }
428
429 trace!("Computed name for `{def_id:?}`: `{name:?}`");
430 self.cached_names.insert(def_id.clone(), name.clone());
431 Ok(name)
432 }
433
434 pub fn catch_sinto<S, T, U>(&mut self, s: &S, span: Span, x: &T) -> Result<U, Error>
436 where
437 T: Debug + SInto<S, U>,
438 {
439 catch_sinto(s, &mut *self.errors.borrow_mut(), &self.translated, span, x)
440 }
441
442 pub fn hax_def(&mut self, def_id: &hax::DefId) -> Result<Arc<hax::FullDef>, Error> {
443 let span = self.def_span(def_id);
444 let unwind_safe_s = std::panic::AssertUnwindSafe(&self.hax_state);
446 std::panic::catch_unwind(move || def_id.full_def(*unwind_safe_s))
447 .or_else(|_| raise_error!(self, span, "Hax panicked when translating `{def_id:?}`."))
448 }
449
450 pub(crate) fn translate_attr_info(&mut self, def: &hax::FullDef) -> AttrInfo {
451 let public = def.visibility.unwrap_or(false);
453 let inline = self.translate_inline(def);
454 let attributes = def
455 .attributes
456 .iter()
457 .filter_map(|attr| self.translate_attribute(&attr))
458 .collect_vec();
459
460 let rename = {
461 let mut renames = attributes.iter().filter_map(|a| a.as_rename()).cloned();
462 let rename = renames.next();
463 if renames.next().is_some() {
464 let span = self.translate_span_from_hax(&def.span);
465 register_error!(
466 self,
467 span,
468 "There should be at most one `charon::rename(\"...\")` \
469 or `aeneas::rename(\"...\")` attribute per declaration",
470 );
471 }
472 rename
473 };
474
475 AttrInfo {
476 attributes,
477 inline,
478 public,
479 rename,
480 }
481 }
482
483 pub(crate) fn translate_item_meta(
485 &mut self,
486 def: &hax::FullDef,
487 name: Name,
488 name_opacity: ItemOpacity,
489 ) -> ItemMeta {
490 if let Some(item_meta) = self.cached_item_metas.get(&def.def_id) {
491 return item_meta.clone();
492 }
493 let span = def.source_span.as_ref().unwrap_or(&def.span);
494 let span = self.translate_span_from_hax(span);
495 let attr_info = self.translate_attr_info(def);
496 let is_local = def.def_id.is_local;
497 let lang_item = def
498 .lang_item
499 .clone()
500 .or_else(|| def.diagnostic_item.clone());
501
502 let opacity = if self.is_extern_item(def)
503 || attr_info.attributes.iter().any(|attr| attr.is_opaque())
504 {
505 ItemOpacity::Opaque.max(name_opacity)
507 } else {
508 name_opacity
509 };
510
511 let item_meta = ItemMeta {
512 name,
513 span,
514 source_text: def.source_text.clone(),
515 attr_info,
516 is_local,
517 opacity,
518 lang_item,
519 };
520 self.cached_item_metas
521 .insert(def.def_id.clone(), item_meta.clone());
522 item_meta
523 }
524
525 pub fn translate_filename(&mut self, name: &hax::FileName) -> meta::FileName {
526 match name {
527 hax::FileName::Real(name) => {
528 use hax::RealFileName;
529 match name {
530 RealFileName::LocalPath(path) => {
531 let path = if let Ok(path) = path.strip_prefix(&self.sysroot) {
532 if let Ok(path) = path.strip_prefix("lib/rustlib/src/rust") {
537 let mut rewritten_path: PathBuf = "/rustc".into();
538 rewritten_path.extend(path);
539 rewritten_path
540 } else {
541 let mut rewritten_path: PathBuf = "/toolchain".into();
543 rewritten_path.extend(path);
544 rewritten_path
545 }
546 } else {
547 path.clone()
548 };
549 FileName::Local(path)
550 }
551 RealFileName::Remapped { virtual_name, .. } => {
552 let mut components_iter = virtual_name.components();
556 if let Some(
557 [Component::RootDir, Component::Normal(rustc), Component::Normal(hash)],
558 ) = components_iter.by_ref().array_chunks().next()
559 && rustc.to_str() == Some("rustc")
560 && hash.len() == 40
561 {
562 let path_without_hash = [Component::RootDir, Component::Normal(rustc)]
563 .into_iter()
564 .chain(components_iter)
565 .collect();
566 FileName::Virtual(path_without_hash)
567 } else {
568 FileName::Virtual(virtual_name.clone())
569 }
570 }
571 }
572 }
573 _ => FileName::NotReal(format!("{name:?}")),
576 }
577 }
578
579 pub fn translate_raw_span(&mut self, rspan: &hax::Span) -> meta::RawSpan {
580 let filename = self.translate_filename(&rspan.filename);
581 let rust_span = rspan.rust_span_data.unwrap().span();
582 let file_id = match &filename {
583 FileName::NotReal(_) => {
584 unimplemented!();
586 }
587 FileName::Virtual(_) | FileName::Local(_) => self.register_file(filename, rust_span),
588 };
589
590 fn convert_loc(loc: &hax::Loc) -> Loc {
591 Loc {
592 line: loc.line,
593 col: loc.col,
594 }
595 }
596 let beg = convert_loc(&rspan.lo);
597 let end = convert_loc(&rspan.hi);
598
599 meta::RawSpan { file_id, beg, end }
601 }
602
603 pub fn translate_span_from_source_info(
605 &mut self,
606 source_scopes: &hax::IndexVec<hax::SourceScope, hax::SourceScopeData>,
607 source_info: &hax::SourceInfo,
608 ) -> Span {
609 let span = self.translate_raw_span(&source_info.span);
611
612 let mut parent_span = None;
614 let mut scope_data = &source_scopes[source_info.scope];
615 while let Some(parent_scope) = scope_data.inlined_parent_scope {
616 scope_data = &source_scopes[parent_scope];
617 parent_span = Some(&scope_data.span);
618 }
619
620 if let Some(parent_span) = parent_span {
621 let parent_span = self.translate_raw_span(parent_span);
622 Span {
623 span: parent_span,
624 generated_from_span: Some(span),
625 }
626 } else {
627 Span {
628 span,
629 generated_from_span: None,
630 }
631 }
632 }
633
634 pub(crate) fn translate_span_from_hax(&mut self, span: &hax::Span) -> Span {
635 Span {
636 span: self.translate_raw_span(span),
637 generated_from_span: None,
638 }
639 }
640
641 pub(crate) fn def_span(&mut self, def_id: &hax::DefId) -> Span {
642 let span = def_id.def_span(&self.hax_state);
643 self.translate_span_from_hax(&span)
644 }
645
646 pub(crate) fn translate_attribute(&mut self, attr: &hax::Attribute) -> Option<Attribute> {
649 use hax::Attribute as Haxttribute;
650 use hax::AttributeKind as HaxttributeKind;
651 match attr {
652 Haxttribute::Parsed(HaxttributeKind::DocComment { comment, .. }) => {
653 Some(Attribute::DocComment(comment.to_string()))
654 }
655 Haxttribute::Parsed(_) => None,
656 Haxttribute::Unparsed(attr) => {
657 let raw_attr = RawAttribute {
658 path: attr.path.clone(),
659 args: match &attr.args {
660 hax::AttrArgs::Empty => None,
661 hax::AttrArgs::Delimited(args) => Some(args.tokens.clone()),
662 hax::AttrArgs::Eq { expr, .. } => self
663 .tcx
664 .sess
665 .source_map()
666 .span_to_snippet(expr.span.rust_span_data.unwrap().span())
667 .ok(),
668 },
669 };
670 match Attribute::parse_from_raw(raw_attr) {
671 Ok(a) => Some(a),
672 Err(msg) => {
673 let span = self.translate_span_from_hax(&attr.span);
674 register_error!(self, span, "Error parsing attribute: {msg}");
675 None
676 }
677 }
678 }
679 }
680 }
681
682 pub(crate) fn translate_inline(&self, def: &hax::FullDef) -> Option<InlineAttr> {
683 match def.kind() {
684 hax::FullDefKind::Fn { inline, .. } | hax::FullDefKind::AssocFn { inline, .. } => {
685 match inline {
686 hax::InlineAttr::None => None,
687 hax::InlineAttr::Hint => Some(InlineAttr::Hint),
688 hax::InlineAttr::Never => Some(InlineAttr::Never),
689 hax::InlineAttr::Always => Some(InlineAttr::Always),
690 hax::InlineAttr::Force { .. } => Some(InlineAttr::Always),
691 }
692 }
693 _ => None,
694 }
695 }
696
697 pub(crate) fn is_extern_item(&mut self, def: &hax::FullDef) -> bool {
699 def.parent.as_ref().is_some_and(|parent| {
700 self.hax_def(parent).is_ok_and(|parent_def| {
701 matches!(parent_def.kind(), hax::FullDefKind::ForeignMod { .. })
702 })
703 })
704 }
705
706 pub(crate) fn opacity_for_name(&self, name: &Name) -> ItemOpacity {
707 self.options.opacity_for_name(&self.translated, name)
708 }
709
710 pub(crate) fn register_id_no_enqueue(
711 &mut self,
712 src: &Option<DepSource>,
713 id: TransItemSource,
714 ) -> AnyTransId {
715 let item_id = match self.id_map.get(&id) {
716 Some(tid) => *tid,
717 None => {
718 let trans_id = match id {
719 TransItemSource::Type(_) => {
720 AnyTransId::Type(self.translated.type_decls.reserve_slot())
721 }
722 TransItemSource::TraitDecl(_) => {
723 AnyTransId::TraitDecl(self.translated.trait_decls.reserve_slot())
724 }
725 TransItemSource::TraitImpl(_) => {
726 AnyTransId::TraitImpl(self.translated.trait_impls.reserve_slot())
727 }
728 TransItemSource::Global(_) => {
729 AnyTransId::Global(self.translated.global_decls.reserve_slot())
730 }
731 TransItemSource::Fun(_) => {
732 AnyTransId::Fun(self.translated.fun_decls.reserve_slot())
733 }
734 };
735 self.id_map.insert(id.clone(), trans_id);
737 self.reverse_id_map.insert(trans_id, id.clone());
738 self.translated.all_ids.insert(trans_id);
739 if !matches!(id, TransItemSource::TraitImpl(_)) {
742 if let Ok(name) = self.hax_def_id_to_name(id.as_def_id()) {
743 self.translated.item_names.insert(trans_id, name);
744 }
745 }
746 trans_id
747 }
748 };
749 self.errors
750 .borrow_mut()
751 .register_dep_source(src, item_id, id.as_def_id().is_local);
752 item_id
753 }
754
755 pub(crate) fn register_and_enqueue_id(
757 &mut self,
758 src: &Option<DepSource>,
759 id: TransItemSource,
760 ) -> AnyTransId {
761 self.items_to_translate.insert(id.clone());
762 self.register_id_no_enqueue(src, id)
763 }
764
765 pub(crate) fn register_type_decl_id(
766 &mut self,
767 src: &Option<DepSource>,
768 id: &hax::DefId,
769 ) -> TypeDeclId {
770 *self
771 .register_and_enqueue_id(src, TransItemSource::Type(id.clone()))
772 .as_type()
773 .unwrap()
774 }
775
776 pub(crate) fn register_fun_decl_id(
777 &mut self,
778 src: &Option<DepSource>,
779 id: &hax::DefId,
780 ) -> FunDeclId {
781 *self
782 .register_and_enqueue_id(src, TransItemSource::Fun(id.clone()))
783 .as_fun()
784 .unwrap()
785 }
786
787 pub(crate) fn register_trait_decl_id(
788 &mut self,
789 src: &Option<DepSource>,
790 id: &hax::DefId,
791 ) -> TraitDeclId {
792 *self
793 .register_and_enqueue_id(src, TransItemSource::TraitDecl(id.clone()))
794 .as_trait_decl()
795 .unwrap()
796 }
797
798 pub(crate) fn register_trait_impl_id(
799 &mut self,
800 src: &Option<DepSource>,
801 id: &hax::DefId,
802 ) -> TraitImplId {
803 if let Ok(def) = self.hax_def(id) {
805 let hax::FullDefKind::TraitImpl { trait_pred, .. } = def.kind() else {
806 unreachable!()
807 };
808 let trait_rust_id = &trait_pred.trait_ref.def_id;
809 let _ = self.register_trait_decl_id(src, trait_rust_id);
810 }
811
812 *self
813 .register_and_enqueue_id(src, TransItemSource::TraitImpl(id.clone()))
814 .as_trait_impl()
815 .unwrap()
816 }
817
818 pub(crate) fn register_global_decl_id(
819 &mut self,
820 src: &Option<DepSource>,
821 id: &hax::DefId,
822 ) -> GlobalDeclId {
823 *self
824 .register_and_enqueue_id(src, TransItemSource::Global(id.clone()))
825 .as_global()
826 .unwrap()
827 }
828
829 pub(crate) fn with_def_id<F, T>(
830 &mut self,
831 def_id: &hax::DefId,
832 item_id: Option<AnyTransId>,
833 f: F,
834 ) -> T
835 where
836 F: FnOnce(&mut Self) -> T,
837 {
838 let mut errors = self.errors.borrow_mut();
839 let current_def_id = mem::replace(&mut errors.def_id, item_id);
840 let current_def_id_is_local = mem::replace(&mut errors.def_id_is_local, def_id.is_local);
841 drop(errors); let ret = f(self);
843 let mut errors = self.errors.borrow_mut();
844 errors.def_id = current_def_id;
845 errors.def_id_is_local = current_def_id_is_local;
846 ret
847 }
848}
849
850impl<'tcx, 'ctx> ItemTransCtx<'tcx, 'ctx> {
851 pub(crate) fn new(
853 def_id: hax::DefId,
854 item_id: Option<AnyTransId>,
855 t_ctx: &'ctx mut TranslateCtx<'tcx>,
856 ) -> Self {
857 ItemTransCtx {
858 def_id,
859 item_id,
860 t_ctx,
861 error_on_impl_expr_error: true,
862 binding_levels: Default::default(),
863 parent_trait_clauses: Default::default(),
864 item_trait_clauses: Default::default(),
865 }
866 }
867
868 pub fn span_err(&self, span: Span, msg: &str, level: Level) -> Error {
869 self.t_ctx.span_err(span, msg, level)
870 }
871
872 pub(crate) fn translate_span_from_hax(&mut self, rspan: &hax::Span) -> Span {
873 self.t_ctx.translate_span_from_hax(rspan)
874 }
875
876 pub(crate) fn hax_def(&mut self, def_id: &hax::DefId) -> Result<Arc<hax::FullDef>, Error> {
877 self.t_ctx.hax_def(def_id)
878 }
879
880 pub(crate) fn def_span(&mut self, def_id: &hax::DefId) -> Span {
881 self.t_ctx.def_span(def_id)
882 }
883
884 pub(crate) fn register_id_no_enqueue(&mut self, span: Span, id: TransItemSource) -> AnyTransId {
885 let src = self.make_dep_source(span);
886 self.t_ctx.register_id_no_enqueue(&src, id)
887 }
888
889 pub(crate) fn register_type_decl_id(&mut self, span: Span, id: &hax::DefId) -> TypeDeclId {
890 let src = self.make_dep_source(span);
891 self.t_ctx.register_type_decl_id(&src, id)
892 }
893
894 pub(crate) fn register_fun_decl_id(&mut self, span: Span, id: &hax::DefId) -> FunDeclId {
895 let src = self.make_dep_source(span);
896 self.t_ctx.register_fun_decl_id(&src, id)
897 }
898
899 pub(crate) fn register_fun_decl_id_no_enqueue(
900 &mut self,
901 span: Span,
902 id: &hax::DefId,
903 ) -> FunDeclId {
904 self.register_id_no_enqueue(span, TransItemSource::Fun(id.clone()))
905 .as_fun()
906 .copied()
907 .unwrap()
908 }
909
910 pub(crate) fn register_global_decl_id(&mut self, span: Span, id: &hax::DefId) -> GlobalDeclId {
911 let src = self.make_dep_source(span);
912 self.t_ctx.register_global_decl_id(&src, id)
913 }
914
915 pub(crate) fn register_trait_decl_id(&mut self, span: Span, id: &hax::DefId) -> TraitDeclId {
918 let src = self.make_dep_source(span);
919 self.t_ctx.register_trait_decl_id(&src, id)
920 }
921
922 pub(crate) fn register_trait_impl_id(&mut self, span: Span, id: &hax::DefId) -> TraitImplId {
925 let src = self.make_dep_source(span);
926 self.t_ctx.register_trait_impl_id(&src, id)
927 }
928
929 pub(crate) fn the_only_binder(&self) -> &BindingLevel {
931 assert_eq!(self.binding_levels.len(), 1);
932 &self.outermost_binder()
933 }
934
935 pub(crate) fn outermost_binder(&self) -> &BindingLevel {
936 self.binding_levels.outermost()
937 }
938
939 pub(crate) fn innermost_binder(&self) -> &BindingLevel {
940 self.binding_levels.innermost()
941 }
942
943 pub(crate) fn innermost_binder_mut(&mut self) -> &mut BindingLevel {
944 self.binding_levels.innermost_mut()
945 }
946
947 pub(crate) fn innermost_generics_mut(&mut self) -> &mut GenericParams {
948 &mut self.innermost_binder_mut().params
949 }
950
951 pub(crate) fn lookup_bound_region(
952 &mut self,
953 span: Span,
954 dbid: hax::DebruijnIndex,
955 var: hax::BoundVar,
956 ) -> Result<RegionDbVar, Error> {
957 let dbid = DeBruijnId::new(dbid);
958 if let Some(rid) = self
959 .binding_levels
960 .get(dbid)
961 .and_then(|bl| bl.bound_region_vars.get(var))
962 {
963 Ok(DeBruijnVar::bound(dbid, *rid))
964 } else {
965 raise_error!(
966 self,
967 span,
968 "Unexpected error: could not find region '{dbid}_{var}"
969 )
970 }
971 }
972
973 fn lookup_param<Id: Copy>(
974 &mut self,
975 span: Span,
976 f: impl for<'a> Fn(&'a BindingLevel) -> Option<Id>,
977 mk_err: impl FnOnce() -> String,
978 ) -> Result<DeBruijnVar<Id>, Error> {
979 for (dbid, bl) in self.binding_levels.iter_enumerated() {
980 if let Some(id) = f(bl) {
981 return Ok(DeBruijnVar::bound(dbid, id));
982 }
983 }
984 let err = mk_err();
985 raise_error!(self, span, "Unexpected error: could not find {}", err)
986 }
987
988 pub(crate) fn lookup_early_region(
989 &mut self,
990 span: Span,
991 region: &hax::EarlyParamRegion,
992 ) -> Result<RegionDbVar, Error> {
993 self.lookup_param(
994 span,
995 |bl| bl.early_region_vars.get(region).copied(),
996 || format!("the region variable {region:?}"),
997 )
998 }
999
1000 pub(crate) fn lookup_type_var(
1001 &mut self,
1002 span: Span,
1003 param: &hax::ParamTy,
1004 ) -> Result<TypeDbVar, Error> {
1005 self.lookup_param(
1006 span,
1007 |bl| bl.type_vars_map.get(¶m.index).copied(),
1008 || format!("the type variable {}", param.name),
1009 )
1010 }
1011
1012 pub(crate) fn lookup_const_generic_var(
1013 &mut self,
1014 span: Span,
1015 param: &hax::ParamConst,
1016 ) -> Result<ConstGenericDbVar, Error> {
1017 self.lookup_param(
1018 span,
1019 |bl| bl.const_generic_vars_map.get(¶m.index).copied(),
1020 || format!("the const generic variable {}", param.name),
1021 )
1022 }
1023
1024 pub(crate) fn lookup_clause_var(
1025 &mut self,
1026 span: Span,
1027 mut id: usize,
1028 ) -> Result<ClauseDbVar, Error> {
1029 let innermost_item_binder_id = self
1034 .binding_levels
1035 .iter_enumerated()
1036 .find(|(_, bl)| bl.is_item_binder)
1037 .unwrap()
1038 .0;
1039 for (dbid, bl) in self.binding_levels.iter_enumerated().rev() {
1041 let num_clauses_bound_at_this_level = bl.params.trait_clauses.elem_count();
1042 if id < num_clauses_bound_at_this_level || dbid == innermost_item_binder_id {
1043 let id = TraitClauseId::from_usize(id);
1044 return Ok(DeBruijnVar::bound(dbid, id));
1045 } else {
1046 id -= num_clauses_bound_at_this_level
1047 }
1048 }
1049 raise_error!(
1051 self,
1052 span,
1053 "Unexpected error: could not find clause variable {}",
1054 id
1055 )
1056 }
1057
1058 pub(crate) fn lookup_cached_type(
1059 &self,
1060 cache_key: &HashByAddr<Arc<hax::TyKind>>,
1061 ) -> Option<Ty> {
1062 self.innermost_binder()
1065 .type_trans_cache
1066 .get(&cache_key)
1067 .cloned()
1068 }
1069
1070 pub(crate) fn translate_region_binder<F, T, U>(
1074 &mut self,
1075 _span: Span,
1076 binder: &hax::Binder<T>,
1077 f: F,
1078 ) -> Result<RegionBinder<U>, Error>
1079 where
1080 F: FnOnce(&mut Self, &T) -> Result<U, Error>,
1081 {
1082 assert!(!self.binding_levels.is_empty());
1083
1084 let mut binding_level = BindingLevel::new(false);
1086 binding_level.push_params_from_binder(binder.rebind(()))?;
1087 self.binding_levels.push(binding_level);
1088
1089 let res = f(self, binder.hax_skip_binder_ref());
1091
1092 let regions = self.binding_levels.pop().unwrap().params.regions;
1094
1095 res.map(|skip_binder| RegionBinder {
1097 regions,
1098 skip_binder,
1099 })
1100 }
1101
1102 pub(crate) fn translate_binder_for_def<F, U>(
1105 &mut self,
1106 span: Span,
1107 kind: BinderKind,
1108 def: &hax::FullDef,
1109 f: F,
1110 ) -> Result<Binder<U>, Error>
1111 where
1112 F: FnOnce(&mut Self) -> Result<U, Error>,
1113 {
1114 assert!(!self.binding_levels.is_empty());
1115
1116 self.translate_def_generics_without_parents(span, def)?;
1118
1119 let res = f(self);
1121
1122 let params = self.binding_levels.pop().unwrap().params;
1124
1125 res.map(|skip_binder| Binder {
1127 kind,
1128 params,
1129 skip_binder,
1130 })
1131 }
1132
1133 pub(crate) fn make_dep_source(&self, span: Span) -> Option<DepSource> {
1134 Some(DepSource {
1135 src_id: self.item_id?,
1136 span: self.def_id.is_local.then_some(span),
1137 })
1138 }
1139}
1140
1141impl<'a> IntoFormatter for &'a TranslateCtx<'_> {
1142 type C = FmtCtx<'a>;
1143 fn into_fmt(self) -> Self::C {
1144 self.translated.into_fmt()
1145 }
1146}
1147
1148impl<'a> IntoFormatter for &'a ItemTransCtx<'_, '_> {
1149 type C = FmtCtx<'a>;
1150 fn into_fmt(self) -> Self::C {
1151 FmtCtx {
1152 translated: Some(&self.t_ctx.translated),
1153 generics: self.binding_levels.map_ref(|bl| Cow::Borrowed(&bl.params)),
1154 locals: None,
1155 }
1156 }
1157}
1158
1159impl<'tcx, 'ctx> fmt::Display for TranslateCtx<'tcx> {
1160 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1161 self.translated.fmt(f)
1162 }
1163}