1use super::translate_crate::*;
2use super::translate_ctx::*;
3use charon_lib::ast::ullbc_ast_utils::BodyBuilder;
4use charon_lib::ast::*;
5use charon_lib::formatter::IntoFormatter;
6use charon_lib::pretty::FmtWithCtx;
7use derive_generic_visitor::Visitor;
8use hax::SInto;
9use itertools::Itertools;
10use rustc_span::sym;
11use std::mem;
12use std::ops::ControlFlow;
13
14impl<'tcx, 'ctx> TranslateCtx<'tcx> {
15 pub(crate) fn translate_item(&mut self, item_src: &TransItemSource) {
16 let trans_id = self.register_no_enqueue(&None, item_src);
17 let def_id = item_src.def_id();
18 if let Some(trans_id) = trans_id {
19 if self.translate_stack.contains(&trans_id) {
20 register_error!(
21 self,
22 Span::dummy(),
23 "Cycle detected while translating {def_id:?}! Stack: {:?}",
24 &self.translate_stack
25 );
26 return;
27 } else {
28 self.translate_stack.push(trans_id);
29 }
30 }
31 self.with_def_id(def_id, trans_id, |mut ctx| {
32 let span = ctx.def_span(def_id);
33 let res = {
35 let mut ctx = std::panic::AssertUnwindSafe(&mut ctx);
37 std::panic::catch_unwind(move || ctx.translate_item_aux(item_src, trans_id))
38 };
39 match res {
40 Ok(Ok(())) => return,
41 Ok(Err(_)) => {
43 register_error!(ctx, span, "Item `{def_id:?}` caused errors; ignoring.")
44 }
45 Err(_) => register_error!(
47 ctx,
48 span,
49 "Thread panicked when extracting item `{def_id:?}`."
50 ),
51 };
52 });
53 self.translate_stack.pop();
55 }
56
57 pub(crate) fn translate_item_aux(
58 &mut self,
59 item_src: &TransItemSource,
60 trans_id: Option<ItemId>,
61 ) -> Result<(), Error> {
62 let name = self.translate_name(item_src)?;
64 if let Some(trans_id) = trans_id {
65 self.translated.item_names.insert(trans_id, name.clone());
66 }
67 let opacity = self.opacity_for_name(&name);
68 if opacity.is_invisible() {
69 return Ok(());
71 }
72 let def = self.hax_def_for_item(&item_src.item)?;
73 let item_meta = self.translate_item_meta(&def, item_src, name, opacity);
74 if item_meta.opacity.is_invisible() {
75 return Ok(());
76 }
77
78 if !item_meta.opacity.is_opaque()
81 && let Some(def_id) = def.def_id().as_rust_def_id()
82 && let Some(ldid) = def_id.as_local()
83 && let node = self.tcx.hir_node_by_def_id(ldid)
84 && let Some(body_id) = node.body_id()
85 {
86 use rustc_hir::intravisit;
87 #[allow(non_local_definitions)]
88 impl<'tcx> intravisit::Visitor<'tcx> for TranslateCtx<'tcx> {
89 fn visit_nested_item(&mut self, id: rustc_hir::ItemId) {
90 let def_id = id.owner_id.def_id.to_def_id();
91 let def_id = def_id.sinto(&self.hax_state);
92 self.enqueue_module_item(&def_id);
93 }
94 }
95 let body = self.tcx.hir_body(body_id);
96 intravisit::walk_body(self, body);
97 }
98
99 let mut bt_ctx = ItemTransCtx::new(item_src.clone(), trans_id, self);
101 trace!(
102 "About to translate item `{:?}` as a {:?}; \
103 target_id={trans_id:?}, mono={}",
104 def.def_id(),
105 item_src.kind,
106 bt_ctx.monomorphize()
107 );
108 if !matches!(
109 &item_src.kind,
110 TransItemSourceKind::InherentImpl | TransItemSourceKind::Module,
111 ) {
112 bt_ctx.translate_item_generics(item_meta.span, &def, &item_src.kind)?;
113 }
114 match &item_src.kind {
115 TransItemSourceKind::InherentImpl | TransItemSourceKind::Module => {
116 bt_ctx.register_module(item_meta, &def);
117 }
118 TransItemSourceKind::Type => {
119 let Some(ItemId::Type(id)) = trans_id else {
120 unreachable!()
121 };
122 let ty = bt_ctx.translate_type_decl(id, item_meta, &def)?;
123 self.translated.type_decls.set_slot(id, ty);
124 }
125 TransItemSourceKind::Fun => {
126 let Some(ItemId::Fun(id)) = trans_id else {
127 unreachable!()
128 };
129 let fun_decl = bt_ctx.translate_fun_decl(id, item_meta, &def)?;
130 self.translated.fun_decls.set_slot(id, fun_decl);
131 }
132 TransItemSourceKind::Global => {
133 let Some(ItemId::Global(id)) = trans_id else {
134 unreachable!()
135 };
136 let global_decl = bt_ctx.translate_global(id, item_meta, &def)?;
137 self.translated.global_decls.set_slot(id, global_decl);
138 }
139 TransItemSourceKind::TraitDecl => {
140 let Some(ItemId::TraitDecl(id)) = trans_id else {
141 unreachable!()
142 };
143 let trait_decl = bt_ctx.translate_trait_decl(id, item_meta, &def)?;
144 self.translated.trait_decls.set_slot(id, trait_decl);
145 }
146 TransItemSourceKind::TraitImpl(kind) => {
147 let Some(ItemId::TraitImpl(id)) = trans_id else {
148 unreachable!()
149 };
150 let trait_impl = match kind {
151 TraitImplSource::Normal => bt_ctx.translate_trait_impl(id, item_meta, &def)?,
152 TraitImplSource::TraitAlias => {
153 bt_ctx.translate_trait_alias_blanket_impl(id, item_meta, &def)?
154 }
155 &TraitImplSource::Closure(kind) => {
156 bt_ctx.translate_closure_trait_impl(id, item_meta, &def, kind)?
157 }
158 TraitImplSource::ImplicitDestruct => {
159 bt_ctx.translate_implicit_destruct_impl(id, item_meta, &def)?
160 }
161 };
162 self.translated.trait_impls.set_slot(id, trait_impl);
163 }
164 &TransItemSourceKind::DefaultedMethod(impl_kind, name) => {
165 let Some(ItemId::Fun(id)) = trans_id else {
166 unreachable!()
167 };
168 let fun_decl =
169 bt_ctx.translate_defaulted_method(id, item_meta, &def, impl_kind, name)?;
170 self.translated.fun_decls.set_slot(id, fun_decl);
171 }
172 &TransItemSourceKind::ClosureMethod(kind) => {
173 let Some(ItemId::Fun(id)) = trans_id else {
174 unreachable!()
175 };
176 let fun_decl = bt_ctx.translate_closure_method(id, item_meta, &def, kind)?;
177 self.translated.fun_decls.set_slot(id, fun_decl);
178 }
179 TransItemSourceKind::ClosureAsFnCast => {
180 let Some(ItemId::Fun(id)) = trans_id else {
181 unreachable!()
182 };
183 let fun_decl = bt_ctx.translate_stateless_closure_as_fn(id, item_meta, &def)?;
184 self.translated.fun_decls.set_slot(id, fun_decl);
185 }
186 &TransItemSourceKind::DropInPlaceMethod(impl_kind) => {
187 let Some(ItemId::Fun(id)) = trans_id else {
188 unreachable!()
189 };
190 let fun_decl =
191 bt_ctx.translate_drop_in_place_method(id, item_meta, &def, impl_kind)?;
192 self.translated.fun_decls.set_slot(id, fun_decl);
193 }
194 TransItemSourceKind::VTable => {
195 let Some(ItemId::Type(id)) = trans_id else {
196 unreachable!()
197 };
198 let ty_decl = bt_ctx.translate_vtable_struct(id, item_meta, &def)?;
199 self.translated.type_decls.set_slot(id, ty_decl);
200 }
201 TransItemSourceKind::VTableInstance(impl_kind) => {
202 let Some(ItemId::Global(id)) = trans_id else {
203 unreachable!()
204 };
205 let global_decl =
206 bt_ctx.translate_vtable_instance(id, item_meta, &def, impl_kind)?;
207 self.translated.global_decls.set_slot(id, global_decl);
208 }
209 TransItemSourceKind::VTableInstanceInitializer(impl_kind) => {
210 let Some(ItemId::Fun(id)) = trans_id else {
211 unreachable!()
212 };
213 let fun_decl =
214 bt_ctx.translate_vtable_instance_init(id, item_meta, &def, impl_kind)?;
215 self.translated.fun_decls.set_slot(id, fun_decl);
216 }
217 TransItemSourceKind::VTableMethod => {
218 let Some(ItemId::Fun(id)) = trans_id else {
219 unreachable!()
220 };
221 let fun_decl = bt_ctx.translate_vtable_shim(id, item_meta, &def)?;
222 self.translated.fun_decls.set_slot(id, fun_decl);
223 }
224 TransItemSourceKind::VTableDropShim => {
225 let Some(ItemId::Fun(id)) = trans_id else {
226 unreachable!()
227 };
228 let fun_decl = bt_ctx.translate_vtable_drop_shim(id, item_meta, &def)?;
229 self.translated.fun_decls.set_slot(id, fun_decl);
230 }
231 }
232 Ok(())
233 }
234
235 pub(crate) fn get_or_translate(&mut self, id: ItemId) -> Result<krate::ItemRef<'_>, Error> {
238 if self.translated.get_item(id).is_none() {
241 let item_source = self.reverse_id_map.get(&id).unwrap().clone();
242 self.translate_item(&item_source);
243 if self.translated.get_item(id).is_none() {
244 let span = self.def_span(item_source.def_id());
245 let name = self
246 .translated
247 .item_name(id)
248 .map(|n| n.to_string_with_ctx(&self.into_fmt()))
249 .unwrap_or_else(|| id.to_string());
250 return Err(Error {
252 span,
253 msg: format!("Failed to translate item {name}."),
254 });
255 }
257 self.processed.insert(item_source.clone());
259 }
260 let item = self.translated.get_item(id);
261 Ok(item.unwrap())
262 }
263
264 pub fn translate_unit_metadata_const(&mut self) {
266 use charon_lib::ullbc_ast::*;
267 let name = Name::from_path(&["UNIT_METADATA"]);
268 let item_meta = ItemMeta {
269 name,
270 span: Span::dummy(),
271 source_text: None,
272 attr_info: AttrInfo::default(),
273 is_local: false,
274 opacity: ItemOpacity::Foreign,
275 lang_item: None,
276 };
277
278 let body = {
279 let mut builder = BodyBuilder::new(Span::dummy(), 0);
280 let _ = builder.new_var(None, Ty::mk_unit());
281 builder.build()
282 };
283
284 let global_id = self.translated.global_decls.reserve_slot();
285 let initializer = self.translated.fun_decls.push_with(|def_id| FunDecl {
286 def_id,
287 item_meta: item_meta.clone(),
288 src: ItemSource::TopLevel,
289 is_global_initializer: Some(global_id),
290 generics: Default::default(),
291 signature: FunSig {
292 is_unsafe: false,
293 inputs: vec![],
294 output: Ty::mk_unit(),
295 },
296 body: Body::Unstructured(body),
297 });
298 self.translated.global_decls.set_slot(
299 global_id,
300 GlobalDecl {
301 def_id: global_id,
302 item_meta,
303 generics: Default::default(),
304 ty: Ty::mk_unit(),
305 src: ItemSource::TopLevel,
306 global_kind: GlobalKind::NamedConst,
307 init: initializer,
308 },
309 );
310 self.translated.unit_metadata = Some(GlobalDeclRef {
311 id: global_id,
312 generics: Box::new(GenericArgs::empty()),
313 });
314 }
315
316 pub fn remove_unused_methods(&mut self) {
318 let method_is_used = |trait_id, name| {
319 self.method_status.get(trait_id).is_some_and(|map| {
320 map.get(&name)
321 .is_some_and(|status| matches!(status, MethodStatus::Used))
322 })
323 };
324 for tdecl in self.translated.trait_decls.iter_mut() {
325 tdecl
326 .methods
327 .retain(|m| method_is_used(tdecl.def_id, m.name()));
328 }
329 for timpl in self.translated.trait_impls.iter_mut() {
330 let trait_id = timpl.impl_trait.id;
331 timpl
332 .methods
333 .retain(|(name, _)| method_is_used(trait_id, *name));
334 }
335 }
336}
337
338impl ItemTransCtx<'_, '_> {
339 #[tracing::instrument(skip(self, item_meta, def))]
343 pub(crate) fn register_module(&mut self, item_meta: ItemMeta, def: &hax::FullDef) {
344 if !item_meta.opacity.is_transparent() {
345 return;
346 }
347 match def.kind() {
348 hax::FullDefKind::InherentImpl { items, .. } => {
349 for assoc in items {
350 self.t_ctx.enqueue_module_item(&assoc.def_id);
351 }
352 }
353 hax::FullDefKind::Mod { items, .. } => {
354 for (_, def_id) in items {
355 self.t_ctx.enqueue_module_item(def_id);
356 }
357 }
358 hax::FullDefKind::ForeignMod { items, .. } => {
359 for def_id in items {
360 self.t_ctx.enqueue_module_item(def_id);
361 }
362 }
363 _ => panic!("Item should be a module but isn't: {def:?}"),
364 }
365 }
366
367 pub(crate) fn get_item_source(
368 &mut self,
369 span: Span,
370 def: &hax::FullDef,
371 ) -> Result<ItemSource, Error> {
372 let assoc = match def.kind() {
373 hax::FullDefKind::AssocTy {
374 associated_item, ..
375 }
376 | hax::FullDefKind::AssocConst {
377 associated_item, ..
378 }
379 | hax::FullDefKind::AssocFn {
380 associated_item, ..
381 } => associated_item,
382 hax::FullDefKind::Closure { args, .. } => {
383 let info = self.translate_closure_info(span, args)?;
384 return Ok(ItemSource::Closure { info });
385 }
386 _ => return Ok(ItemSource::TopLevel),
387 };
388 Ok(match &assoc.container {
389 hax::AssocItemContainer::InherentImplContainer { .. } => ItemSource::TopLevel,
396 hax::AssocItemContainer::TraitImplContainer {
403 impl_,
404 implemented_trait_ref,
405 overrides_default,
406 ..
407 } => {
408 let impl_ref =
409 self.translate_trait_impl_ref(span, impl_, TraitImplSource::Normal)?;
410 let trait_ref = self.translate_trait_ref(span, implemented_trait_ref)?;
411 let item_name = self.t_ctx.translate_trait_item_name(def.def_id())?;
412 if matches!(def.kind(), hax::FullDefKind::AssocFn { .. }) {
413 self.mark_method_as_used(trait_ref.id, item_name);
416 }
417 ItemSource::TraitImpl {
418 impl_ref,
419 trait_ref,
420 item_name,
421 reuses_default: !overrides_default,
422 }
423 }
424 hax::AssocItemContainer::TraitContainer { trait_ref, .. } => {
432 let trait_ref = self.translate_trait_ref(span, trait_ref)?;
435 let item_name = self.t_ctx.translate_trait_item_name(def.def_id())?;
436 ItemSource::TraitDecl {
437 trait_ref,
438 item_name,
439 has_default: assoc.has_value,
440 }
441 }
442 })
443 }
444
445 #[tracing::instrument(skip(self, item_meta, def))]
451 pub fn translate_type_decl(
452 mut self,
453 trans_id: TypeDeclId,
454 item_meta: ItemMeta,
455 def: &hax::FullDef,
456 ) -> Result<TypeDecl, Error> {
457 let span = item_meta.span;
458
459 let src = self.get_item_source(span, def)?;
461
462 let mut repr: Option<ReprOptions> = None;
463
464 let kind = match &def.kind {
466 _ if item_meta.opacity.is_opaque() => Ok(TypeDeclKind::Opaque),
467 hax::FullDefKind::OpaqueTy | hax::FullDefKind::ForeignTy => Ok(TypeDeclKind::Opaque),
468 hax::FullDefKind::TyAlias { ty, .. } => {
469 self.error_on_impl_expr_error = false;
471 self.translate_ty(span, ty).map(TypeDeclKind::Alias)
472 }
473 hax::FullDefKind::Adt { repr: hax_repr, .. } => {
474 repr = Some(self.translate_repr_options(hax_repr));
475 self.translate_adt_def(trans_id, span, &item_meta, def)
476 }
477 hax::FullDefKind::Closure { args, .. } => self.translate_closure_adt(span, &args),
478 _ => panic!("Unexpected item when translating types: {def:?}"),
479 };
480
481 let kind = match kind {
482 Ok(kind) => kind,
483 Err(err) => TypeDeclKind::Error(err.msg),
484 };
485 let layout = self.translate_layout(def.this());
486 let ptr_metadata = self.translate_ptr_metadata(span, def.this())?;
487 let type_def = TypeDecl {
488 def_id: trans_id,
489 item_meta,
490 generics: self.into_generics(),
491 kind,
492 src,
493 layout,
494 ptr_metadata,
495 repr,
496 };
497
498 Ok(type_def)
499 }
500
501 #[tracing::instrument(skip(self, item_meta, def))]
503 pub fn translate_fun_decl(
504 mut self,
505 def_id: FunDeclId,
506 item_meta: ItemMeta,
507 def: &hax::FullDef,
508 ) -> Result<FunDecl, Error> {
509 let span = item_meta.span;
510
511 let src = self.get_item_source(span, def)?;
512
513 if let hax::FullDefKind::Ctor {
514 fields, output_ty, ..
515 } = def.kind()
516 {
517 let signature = FunSig {
518 inputs: fields
519 .iter()
520 .map(|field| self.translate_ty(span, &field.ty))
521 .try_collect()?,
522 output: self.translate_ty(span, output_ty)?,
523 is_unsafe: false,
524 };
525
526 let body = if item_meta.opacity.with_private_contents().is_opaque() {
527 Body::Opaque
528 } else {
529 self.build_ctor_body(span, def)?
530 };
531 return Ok(FunDecl {
532 def_id,
533 item_meta,
534 generics: self.into_generics(),
535 signature,
536 src,
537 is_global_initializer: None,
538 body,
539 });
540 }
541
542 trace!("Translating function signature");
544 let signature = match &def.kind {
545 hax::FullDefKind::Fn { sig, .. } | hax::FullDefKind::AssocFn { sig, .. } => {
546 self.translate_fun_sig(span, &sig.value)?
547 }
548 hax::FullDefKind::Const { ty, .. }
549 | hax::FullDefKind::AssocConst { ty, .. }
550 | hax::FullDefKind::Static { ty, .. } => FunSig {
551 inputs: vec![],
552 output: self.translate_ty(span, ty)?,
553 is_unsafe: false,
554 },
555 _ => panic!("Unexpected definition for function: {def:?}"),
556 };
557
558 let is_trait_method_decl_without_default = match &src {
561 ItemSource::TraitDecl { has_default, .. } => !has_default,
562 _ => false,
563 };
564
565 let is_global_initializer = matches!(
566 def.kind(),
567 hax::FullDefKind::Const { .. }
568 | hax::FullDefKind::AssocConst { .. }
569 | hax::FullDefKind::Static { .. }
570 );
571 let is_global_initializer = is_global_initializer
572 .then(|| self.register_item(span, def.this(), TransItemSourceKind::Global));
573
574 let body = if item_meta.opacity.with_private_contents().is_opaque() {
575 Body::Opaque
576 } else if is_trait_method_decl_without_default {
577 Body::TraitMethodWithoutDefault
578 } else {
579 self.translate_def_body(item_meta.span, def)
581 };
582 Ok(FunDecl {
583 def_id,
584 item_meta,
585 generics: self.into_generics(),
586 signature,
587 src,
588 is_global_initializer,
589 body,
590 })
591 }
592
593 #[tracing::instrument(skip(self, item_meta, def))]
595 pub fn translate_global(
596 mut self,
597 def_id: GlobalDeclId,
598 item_meta: ItemMeta,
599 def: &hax::FullDef,
600 ) -> Result<GlobalDecl, Error> {
601 let span = item_meta.span;
602
603 let item_source = self.get_item_source(span, def)?;
605
606 trace!("Translating global type");
607 let ty = match &def.kind {
608 hax::FullDefKind::Const { ty, .. }
609 | hax::FullDefKind::AssocConst { ty, .. }
610 | hax::FullDefKind::Static { ty, .. } => ty,
611 _ => panic!("Unexpected def for constant: {def:?}"),
612 };
613 let ty = self.translate_ty(span, ty)?;
614
615 let global_kind = match &def.kind {
616 hax::FullDefKind::Static { .. } => GlobalKind::Static,
617 hax::FullDefKind::Const {
618 kind: hax::ConstKind::TopLevel,
619 ..
620 }
621 | hax::FullDefKind::AssocConst { .. } => GlobalKind::NamedConst,
622 hax::FullDefKind::Const { .. } => GlobalKind::AnonConst,
623 _ => panic!("Unexpected def for constant: {def:?}"),
624 };
625
626 let initializer = self.register_item(span, def.this(), TransItemSourceKind::Fun);
627
628 Ok(GlobalDecl {
629 def_id,
630 item_meta,
631 generics: self.into_generics(),
632 ty,
633 src: item_source,
634 global_kind,
635 init: initializer,
636 })
637 }
638
639 #[tracing::instrument(skip(self, item_meta, def))]
640 pub fn translate_trait_decl(
641 mut self,
642 def_id: TraitDeclId,
643 item_meta: ItemMeta,
644 def: &hax::FullDef,
645 ) -> Result<TraitDecl, Error> {
646 let span = item_meta.span;
647
648 let (hax::FullDefKind::Trait {
649 implied_predicates, ..
650 }
651 | hax::FullDefKind::TraitAlias {
652 implied_predicates, ..
653 }) = def.kind()
654 else {
655 raise_error!(self, span, "Unexpected definition: {def:?}");
656 };
657
658 let mut preds =
660 self.translate_predicates(implied_predicates, PredicateOrigin::WhereClauseOnTrait)?;
661 let implied_clauses = mem::take(&mut preds.trait_clauses);
662 self.innermost_generics_mut().take_predicates_from(preds);
665
666 let vtable = self.translate_vtable_struct_ref_no_enqueue(span, def.this())?;
667
668 if let hax::FullDefKind::TraitAlias { .. } = def.kind() {
669 return Ok(TraitDecl {
671 def_id,
672 item_meta,
673 implied_clauses,
674 generics: self.into_generics(),
675 consts: Default::default(),
676 types: Default::default(),
677 methods: Default::default(),
678 vtable,
679 });
680 }
681
682 let hax::FullDefKind::Trait {
683 items,
684 self_predicate,
685 ..
686 } = &def.kind
687 else {
688 unreachable!()
689 };
690 let self_trait_ref = TraitRef::new(
691 TraitRefKind::SelfId,
692 RegionBinder::empty(self.translate_trait_predicate(span, self_predicate)?),
693 );
694 let items: Vec<(TraitItemName, &hax::AssocItem)> = items
695 .iter()
696 .map(|item| -> Result<_, Error> {
697 let name = self.t_ctx.translate_trait_item_name(&item.def_id)?;
698 Ok((name, item))
699 })
700 .try_collect()?;
701
702 let mut consts = Vec::new();
704 let mut types = Vec::new();
705 let mut methods = Vec::new();
706
707 for &(item_name, ref hax_item) in &items {
708 let item_def_id = &hax_item.def_id;
709 let item_span = self.def_span(item_def_id);
710
711 let trans_kind = match hax_item.kind {
714 hax::AssocKind::Fn { .. } => TransItemSourceKind::Fun,
715 hax::AssocKind::Const { .. } => TransItemSourceKind::Global,
716 hax::AssocKind::Type { .. } => TransItemSourceKind::Type,
717 };
718 let poly_item_def = self.poly_hax_def(item_def_id)?;
719 let (item_src, item_def) = if self.monomorphize() {
720 if poly_item_def.has_own_generics_or_predicates() {
721 continue;
726 } else {
727 let item = def.this().with_def_id(self.hax_state(), item_def_id);
728 let item_def = self.hax_def(&item)?;
729 let item_src = TransItemSource::monomorphic(&item, trans_kind);
730 (item_src, item_def)
731 }
732 } else {
733 let item_src = TransItemSource::polymorphic(item_def_id, trans_kind);
734 (item_src, poly_item_def)
735 };
736
737 match item_def.kind() {
738 hax::FullDefKind::AssocFn { .. } => {
739 let method_id = self.register_no_enqueue(item_span, &item_src);
740 self.register_method_impl(def_id, item_name, method_id);
742 if self.options.translate_all_methods
745 || item_meta.opacity.is_transparent()
746 || !hax_item.has_value
747 {
748 self.mark_method_as_used(def_id, item_name);
749 }
750
751 let binder_kind = BinderKind::TraitMethod(def_id, item_name);
752 let mut method = self.translate_binder_for_def(
753 item_span,
754 binder_kind,
755 &item_def,
756 |bt_ctx| {
757 assert_eq!(bt_ctx.binding_levels.len(), 2);
758 let fun_generics = bt_ctx
759 .outermost_binder()
760 .params
761 .identity_args_at_depth(DeBruijnId::one())
762 .concat(
763 &bt_ctx
764 .innermost_binder()
765 .params
766 .identity_args_at_depth(DeBruijnId::zero()),
767 );
768 let fn_ref = FunDeclRef {
769 id: method_id,
770 generics: Box::new(fun_generics),
771 };
772 Ok(TraitMethod {
773 name: item_name.clone(),
774 item: fn_ref,
775 })
776 },
777 )?;
778 if !self.monomorphize() {
783 struct ReplaceSelfVisitor;
784 impl VarsVisitor for ReplaceSelfVisitor {
785 fn visit_clause_var(&mut self, v: ClauseDbVar) -> Option<TraitRefKind> {
786 if let DeBruijnVar::Bound(DeBruijnId::ZERO, clause_id) = v {
787 Some(if let Some(new_id) = clause_id.index().checked_sub(1) {
789 TraitRefKind::Clause(DeBruijnVar::Bound(
790 DeBruijnId::ZERO,
791 TraitClauseId::new(new_id),
792 ))
793 } else {
794 TraitRefKind::SelfId
795 })
796 } else {
797 None
798 }
799 }
800 }
801 method.params.visit_vars(&mut ReplaceSelfVisitor);
802 method.skip_binder.visit_vars(&mut ReplaceSelfVisitor);
803 method
804 .params
805 .trait_clauses
806 .remove_and_shift_ids(TraitClauseId::ZERO);
807 method.params.trait_clauses.iter_mut().for_each(|clause| {
808 clause.clause_id -= 1;
809 });
810 }
811
812 methods.push(method);
815 }
816 hax::FullDefKind::AssocConst { ty, .. } => {
817 let default = hax_item.has_value.then(|| {
819 let id = self.register_and_enqueue(item_span, item_src);
822 let mut generics = self.the_only_binder().params.identity_args();
823 if !self.monomorphize() {
825 generics.trait_refs.push(self_trait_ref.clone());
826 }
827 GlobalDeclRef {
828 id,
829 generics: Box::new(generics),
830 }
831 });
832 let ty = self.translate_ty(item_span, ty)?;
833 consts.push(TraitAssocConst {
834 name: item_name.clone(),
835 ty,
836 default,
837 });
838 }
839 hax::FullDefKind::AssocTy { .. } if self.monomorphize() => continue,
841 hax::FullDefKind::AssocTy {
842 value,
843 implied_predicates,
844 ..
845 } => {
846 let binder_kind = BinderKind::TraitType(def_id, item_name.clone());
847 let assoc_ty =
848 self.translate_binder_for_def(item_span, binder_kind, &item_def, |ctx| {
849 let mut preds = ctx.translate_predicates(
851 &implied_predicates,
852 PredicateOrigin::TraitItem(item_name.clone()),
853 )?;
854 let implied_clauses = mem::take(&mut preds.trait_clauses);
855 ctx.innermost_generics_mut().take_predicates_from(preds);
858
859 let default = value
860 .as_ref()
861 .map(|ty| ctx.translate_ty(item_span, ty))
862 .transpose()?;
863 Ok(TraitAssocTy {
864 name: item_name.clone(),
865 default,
866 implied_clauses,
867 })
868 })?;
869 types.push(assoc_ty);
870 }
871 _ => panic!("Unexpected definition for trait item: {item_def:?}"),
872 }
873 }
874
875 if def.lang_item == Some(sym::destruct) {
876 let (method_name, method_binder) =
878 self.prepare_drop_in_place_method(def, span, def_id, None);
879 self.mark_method_as_used(def_id, method_name);
880 methods.push(method_binder.map(|fn_ref| TraitMethod {
881 name: method_name,
882 item: fn_ref,
883 }));
884 }
885
886 Ok(TraitDecl {
890 def_id,
891 item_meta,
892 implied_clauses,
893 generics: self.into_generics(),
894 consts,
895 types,
896 methods,
897 vtable,
898 })
899 }
900
901 #[tracing::instrument(skip(self, item_meta, def))]
902 pub fn translate_trait_impl(
903 mut self,
904 def_id: TraitImplId,
905 item_meta: ItemMeta,
906 def: &hax::FullDef,
907 ) -> Result<TraitImpl, Error> {
908 let span = item_meta.span;
909
910 let hax::FullDefKind::TraitImpl {
911 trait_pred,
912 implied_impl_exprs,
913 items: impl_items,
914 ..
915 } = &def.kind
916 else {
917 unreachable!()
918 };
919
920 let implemented_trait = self.translate_trait_ref(span, &trait_pred.trait_ref)?;
922 let trait_id = implemented_trait.id;
923 let self_predicate = TraitRef::new(
925 TraitRefKind::TraitImpl(TraitImplRef {
926 id: def_id,
927 generics: Box::new(self.the_only_binder().params.identity_args()),
928 }),
929 RegionBinder::empty(implemented_trait.clone()),
930 );
931
932 let vtable =
933 self.translate_vtable_instance_ref_no_enqueue(span, &trait_pred.trait_ref, def.this())?;
934
935 let implied_trait_refs = self.translate_trait_impl_exprs(span, &implied_impl_exprs)?;
937
938 {
939 let ctx = self.into_fmt();
941 let refs = implied_trait_refs
942 .iter()
943 .map(|c| c.with_ctx(&ctx))
944 .format("\n");
945 trace!(
946 "Trait impl: {:?}\n- implied_trait_refs:\n{}",
947 def.def_id(),
948 refs
949 );
950 }
951
952 let mut consts = Vec::new();
954 let mut types = Vec::new();
955 let mut methods = Vec::new();
956
957 for impl_item in impl_items {
958 use hax::ImplAssocItemValue::*;
959 let name = self
960 .t_ctx
961 .translate_trait_item_name(&impl_item.decl_def_id)?;
962 let item_def_id = impl_item.def_id();
963 let item_span = self.def_span(item_def_id);
964 let poly_item_def = self.poly_hax_def(item_def_id)?;
968 let trans_kind = match poly_item_def.kind() {
969 hax::FullDefKind::AssocFn { .. } => TransItemSourceKind::Fun,
970 hax::FullDefKind::AssocConst { .. } => TransItemSourceKind::Global,
971 hax::FullDefKind::AssocTy { .. } => TransItemSourceKind::Type,
972 _ => unreachable!(),
973 };
974 let (item_src, item_def) = if self.monomorphize() {
975 if poly_item_def.has_own_generics_or_predicates() {
976 continue;
977 } else {
978 let item = match &impl_item.value {
979 Provided { def_id, .. } => def.this().with_def_id(self.hax_state(), def_id),
981 _ => trait_pred
983 .trait_ref
984 .with_def_id(self.hax_state(), &impl_item.decl_def_id),
985 };
986 let item_src = TransItemSource::monomorphic(&item, trans_kind);
987 let item_def = self.hax_def_for_item(&item_src.item)?;
988 (item_src, item_def)
989 }
990 } else {
991 let item_src = TransItemSource::polymorphic(item_def_id, trans_kind);
992 (item_src, poly_item_def)
993 };
994
995 match item_def.kind() {
996 hax::FullDefKind::AssocFn { .. } => {
997 let method_id: FunDeclId = {
998 let method_src = match &impl_item.value {
999 Provided { .. } => item_src,
1000 DefaultedFn { .. } => TransItemSource::from_item(
1003 def.this(),
1004 TransItemSourceKind::DefaultedMethod(TraitImplSource::Normal, name),
1005 self.monomorphize(),
1006 ),
1007 _ => unreachable!(),
1008 };
1009 self.register_no_enqueue(item_span, &method_src)
1010 };
1011
1012 self.register_method_impl(trait_id, name, method_id);
1014 if matches!(impl_item.value, Provided { .. })
1017 && item_meta.opacity.is_transparent()
1018 {
1019 self.mark_method_as_used(trait_id, name);
1020 }
1021
1022 let binder_kind = BinderKind::TraitMethod(trait_id, name);
1023 let bound_fn_ref = match &impl_item.value {
1024 Provided { .. } => self.translate_binder_for_def(
1025 item_span,
1026 binder_kind,
1027 &item_def,
1028 |ctx| {
1029 let generics = ctx
1030 .outermost_generics()
1031 .identity_args_at_depth(DeBruijnId::one())
1032 .concat(
1033 &ctx.innermost_generics()
1034 .identity_args_at_depth(DeBruijnId::zero()),
1035 );
1036 Ok(FunDeclRef {
1037 id: method_id,
1038 generics: Box::new(generics),
1039 })
1040 },
1041 )?,
1042 DefaultedFn { .. } => {
1043 let decl_methods =
1045 match self.get_or_translate(implemented_trait.id.into()) {
1046 Ok(ItemRef::TraitDecl(tdecl)) => tdecl.methods.as_slice(),
1047 _ => &[],
1048 };
1049 let Some(bound_method) = decl_methods.iter().find(|m| m.name() == name)
1050 else {
1051 continue;
1052 };
1053 let method_params = bound_method
1054 .clone()
1055 .substitute_with_self(
1056 &implemented_trait.generics,
1057 &self_predicate.kind,
1058 )
1059 .params;
1060
1061 let generics = self
1062 .outermost_generics()
1063 .identity_args_at_depth(DeBruijnId::one())
1064 .concat(&method_params.identity_args_at_depth(DeBruijnId::zero()));
1065 let fn_ref = FunDeclRef {
1066 id: method_id,
1067 generics: Box::new(generics),
1068 };
1069 Binder::new(binder_kind, method_params, fn_ref)
1070 }
1071 _ => unreachable!(),
1072 };
1073
1074 methods.push((name, bound_fn_ref));
1077 }
1078 hax::FullDefKind::AssocConst { .. } => {
1079 let id = self.register_and_enqueue(item_span, item_src);
1080 let generics = match &impl_item.value {
1083 Provided { .. } => self.the_only_binder().params.identity_args(),
1084 _ => {
1085 let mut generics = implemented_trait.generics.as_ref().clone();
1086 if !self.monomorphize() {
1088 generics.trait_refs.push(self_predicate.clone());
1089 }
1090 generics
1091 }
1092 };
1093 let gref = GlobalDeclRef {
1094 id,
1095 generics: Box::new(generics),
1096 };
1097 consts.push((name, gref));
1098 }
1099 hax::FullDefKind::AssocTy { .. } if self.monomorphize() => continue,
1101 hax::FullDefKind::AssocTy { value, .. } => {
1102 let binder_kind = BinderKind::TraitType(trait_id, name.clone());
1103 let assoc_ty =
1104 self.translate_binder_for_def(item_span, binder_kind, &item_def, |ctx| {
1105 let ty = match &impl_item.value {
1106 Provided { .. } => value.as_ref().unwrap(),
1107 DefaultedTy { ty, .. } => ty,
1108 _ => unreachable!(),
1109 };
1110 let ty = ctx.translate_ty(item_span, &ty)?;
1111 let implied_trait_refs = ctx.translate_trait_impl_exprs(
1112 item_span,
1113 &impl_item.required_impl_exprs,
1114 )?;
1115 Ok(TraitAssocTyImpl {
1116 value: ty,
1117 implied_trait_refs,
1118 })
1119 })?;
1120 types.push((name.clone(), assoc_ty));
1121 }
1122 _ => panic!("Unexpected definition for trait item: {item_def:?}"),
1123 }
1124 }
1125
1126 let implemented_trait_def = self.poly_hax_def(&trait_pred.trait_ref.def_id)?;
1127 if implemented_trait_def.lang_item == Some(sym::destruct) {
1128 raise_error!(
1129 self,
1130 span,
1131 "found an explicit impl of `core::marker::Destruct`, this should not happen"
1132 );
1133 }
1134
1135 Ok(TraitImpl {
1136 def_id,
1137 item_meta,
1138 impl_trait: implemented_trait,
1139 generics: self.into_generics(),
1140 implied_trait_refs,
1141 consts,
1142 types,
1143 methods,
1144 vtable,
1145 })
1146 }
1147
1148 #[tracing::instrument(skip(self, item_meta, def))]
1158 pub fn translate_trait_alias_blanket_impl(
1159 mut self,
1160 def_id: TraitImplId,
1161 item_meta: ItemMeta,
1162 def: &hax::FullDef,
1163 ) -> Result<TraitImpl, Error> {
1164 let span = item_meta.span;
1165
1166 let hax::FullDefKind::TraitAlias {
1167 implied_predicates, ..
1168 } = &def.kind
1169 else {
1170 raise_error!(self, span, "Unexpected definition: {def:?}");
1171 };
1172
1173 let trait_id = self.register_item(span, def.this(), TransItemSourceKind::TraitDecl);
1174
1175 assert!(self.innermost_generics_mut().trait_clauses.is_empty());
1177 self.register_predicates(implied_predicates, PredicateOrigin::WhereClauseOnTrait)?;
1178
1179 let mut generics = self.the_only_binder().params.identity_args();
1180 let implied_trait_refs = mem::take(&mut generics.trait_refs);
1182 let implemented_trait = TraitDeclRef {
1183 id: trait_id,
1184 generics: Box::new(generics),
1185 };
1186
1187 let mut timpl = TraitImpl {
1188 def_id,
1189 item_meta,
1190 impl_trait: implemented_trait,
1191 generics: self.the_only_binder().params.clone(),
1192 implied_trait_refs,
1193 consts: Default::default(),
1194 types: Default::default(),
1195 methods: Default::default(),
1196 vtable: None,
1198 };
1199 {
1202 struct FixSelfVisitor {
1203 binder_depth: DeBruijnId,
1204 }
1205 struct UnhandledSelf;
1206 impl Visitor for FixSelfVisitor {
1207 type Break = UnhandledSelf;
1208 }
1209 impl VisitorWithBinderDepth for FixSelfVisitor {
1210 fn binder_depth_mut(&mut self) -> &mut DeBruijnId {
1211 &mut self.binder_depth
1212 }
1213 }
1214 impl VisitAstMut for FixSelfVisitor {
1215 fn visit<'a, T: AstVisitable>(&'a mut self, x: &mut T) -> ControlFlow<Self::Break> {
1216 VisitWithBinderDepth::new(self).visit(x)
1217 }
1218 fn visit_trait_ref_kind(
1219 &mut self,
1220 kind: &mut TraitRefKind,
1221 ) -> ControlFlow<Self::Break> {
1222 match kind {
1223 TraitRefKind::SelfId => return ControlFlow::Break(UnhandledSelf),
1224 TraitRefKind::ParentClause(sub, clause_id)
1225 if matches!(sub.kind, TraitRefKind::SelfId) =>
1226 {
1227 *kind = TraitRefKind::Clause(DeBruijnVar::bound(
1228 self.binder_depth,
1229 *clause_id,
1230 ))
1231 }
1232 _ => (),
1233 }
1234 self.visit_inner(kind)
1235 }
1236 }
1237 match timpl.drive_mut(&mut FixSelfVisitor {
1238 binder_depth: DeBruijnId::zero(),
1239 }) {
1240 ControlFlow::Continue(()) => {}
1241 ControlFlow::Break(UnhandledSelf) => {
1242 register_error!(
1243 self,
1244 span,
1245 "Found `Self` clause we can't handle \
1246 in a trait alias blanket impl."
1247 );
1248 }
1249 }
1250 };
1251
1252 Ok(timpl)
1253 }
1254
1255 #[tracing::instrument(skip(self, item_meta))]
1258 pub fn translate_virtual_trait_impl(
1259 &mut self,
1260 def_id: TraitImplId,
1261 item_meta: ItemMeta,
1262 vimpl: &hax::VirtualTraitImpl,
1263 ) -> Result<TraitImpl, Error> {
1264 let span = item_meta.span;
1265 let trait_def = self.hax_def(&vimpl.trait_pred.trait_ref)?;
1266 let hax::FullDefKind::Trait {
1267 items: trait_items, ..
1268 } = trait_def.kind()
1269 else {
1270 panic!()
1271 };
1272
1273 let implemented_trait = self.translate_trait_predicate(span, &vimpl.trait_pred)?;
1274 let implied_trait_refs =
1275 self.translate_trait_impl_exprs(span, &vimpl.implied_impl_exprs)?;
1276
1277 let mut types = vec![];
1278 if !self.monomorphize() {
1280 let type_items = trait_items.iter().filter(|assoc| match assoc.kind {
1281 hax::AssocKind::Type { .. } => true,
1282 _ => false,
1283 });
1284 for ((ty, impl_exprs), assoc) in vimpl.types.iter().zip(type_items) {
1285 let name = self.t_ctx.translate_trait_item_name(&assoc.def_id)?;
1286 let assoc_ty = TraitAssocTyImpl {
1287 value: self.translate_ty(span, ty)?,
1288 implied_trait_refs: self.translate_trait_impl_exprs(span, impl_exprs)?,
1289 };
1290 let binder_kind = BinderKind::TraitType(implemented_trait.id, name.clone());
1291 types.push((name, Binder::empty(binder_kind, assoc_ty)));
1292 }
1293 }
1294
1295 let generics = self.the_only_binder().params.clone();
1296 Ok(TraitImpl {
1297 def_id,
1298 item_meta,
1299 impl_trait: implemented_trait,
1300 generics,
1301 implied_trait_refs,
1302 consts: vec![],
1303 types,
1304 methods: vec![],
1305 vtable: None,
1307 })
1308 }
1309
1310 pub fn register_method_impl(
1314 &mut self,
1315 trait_id: TraitDeclId,
1316 method_name: TraitItemName,
1317 method_id: FunDeclId,
1318 ) {
1319 match self
1320 .method_status
1321 .get_or_extend_and_insert_default(trait_id)
1322 .entry(method_name)
1323 .or_default()
1324 {
1325 MethodStatus::Unused { implementors } => {
1326 implementors.insert(method_id);
1327 }
1328 MethodStatus::Used => {
1329 self.enqueue_id(method_id);
1330 }
1331 }
1332 }
1333
1334 pub fn mark_method_as_used(&mut self, trait_id: TraitDeclId, method_name: TraitItemName) {
1337 let method_status = self
1338 .method_status
1339 .get_or_extend_and_insert_default(trait_id)
1340 .entry(method_name)
1341 .or_default();
1342 match method_status {
1343 MethodStatus::Unused { implementors } => {
1344 let implementors = mem::take(implementors);
1345 *method_status = MethodStatus::Used;
1346 for fun_id in implementors {
1347 self.enqueue_id(fun_id);
1348 }
1349 }
1350 MethodStatus::Used => {}
1351 }
1352 }
1353
1354 #[tracing::instrument(skip(self, item_meta, def))]
1357 pub fn translate_defaulted_method(
1358 &mut self,
1359 def_id: FunDeclId,
1360 item_meta: ItemMeta,
1361 def: &hax::FullDef,
1362 impl_kind: TraitImplSource,
1363 method_name: TraitItemName,
1364 ) -> Result<FunDecl, Error> {
1365 let span = item_meta.span;
1366
1367 let hax::FullDefKind::TraitImpl { trait_pred, .. } = &def.kind else {
1368 unreachable!()
1369 };
1370
1371 let implemented_trait = self.translate_trait_ref(span, &trait_pred.trait_ref)?;
1373 let self_impl_ref = self.translate_trait_impl_ref(span, def.this(), impl_kind)?;
1375 let self_predicate_kind = TraitRefKind::TraitImpl(self_impl_ref.clone());
1376
1377 let ItemRef::TraitDecl(tdecl) = self.get_or_translate(implemented_trait.id.into())? else {
1379 panic!()
1380 };
1381 let Some(bound_method) = tdecl.methods.iter().find(|m| m.name() == method_name) else {
1382 raise_error!(
1383 self,
1384 span,
1385 "Could not find a method with name \
1386 `{method_name}` in trait `{:?}`",
1387 trait_pred.trait_ref.def_id,
1388 )
1389 };
1390 let bound_fn_ref: Binder<FunDeclRef> = bound_method
1391 .clone()
1392 .substitute_with_self(&implemented_trait.generics, &self_predicate_kind)
1393 .map(|m| m.item);
1394
1395 let bound_fn_ref: Binder<Binder<FunDeclRef>> = Binder {
1399 params: self.outermost_generics().clone(),
1400 skip_binder: bound_fn_ref,
1401 kind: BinderKind::Other,
1402 };
1403 let bound_fn_ref: Binder<FunDeclRef> = bound_fn_ref.flatten();
1404
1405 let original_method_id = bound_fn_ref.skip_binder.id;
1407 let ItemRef::Fun(fun_decl) = self.get_or_translate(original_method_id.into())? else {
1408 panic!()
1409 };
1410 let mut fun_decl = fun_decl
1411 .clone()
1412 .substitute_params(bound_fn_ref.map(|x| *x.generics));
1413
1414 fun_decl.def_id = def_id;
1416 fun_decl.item_meta = ItemMeta {
1419 name: item_meta.name,
1420 opacity: item_meta.opacity,
1421 is_local: item_meta.is_local,
1422 span: item_meta.span,
1423 source_text: fun_decl.item_meta.source_text,
1424 attr_info: fun_decl.item_meta.attr_info,
1425 lang_item: fun_decl.item_meta.lang_item,
1426 };
1427 fun_decl.src = if let ItemSource::TraitDecl {
1428 trait_ref,
1429 item_name,
1430 ..
1431 } = fun_decl.src
1432 {
1433 ItemSource::TraitImpl {
1434 impl_ref: self_impl_ref.clone(),
1435 trait_ref,
1436 item_name,
1437 reuses_default: true,
1438 }
1439 } else {
1440 unreachable!()
1441 };
1442 if !item_meta.opacity.is_transparent() {
1443 fun_decl.body = Body::Opaque;
1444 }
1445
1446 Ok(fun_decl)
1447 }
1448}