1use charon_lib::ast::ullbc_ast_utils::BodyBuilder;
2use hax::{AssocItemContainer, GenericArg, TraitPredicate};
3use itertools::Itertools;
4use rustc_span::kw;
5use std::mem;
6
7use super::{
8 translate_crate::TransItemSourceKind, translate_ctx::*, translate_generics::BindingLevel,
9};
10use charon_lib::formatter::IntoFormatter;
11use charon_lib::ids::{IndexMap, IndexVec};
12use charon_lib::pretty::FmtWithCtx;
13use charon_lib::ullbc_ast::*;
14
15fn usize_ty() -> Ty {
16 Ty::new(TyKind::Literal(LiteralTy::UInt(UIntTy::Usize)))
17}
18
19enum VtableMethodValue {
25 Const(ConstantExprKind),
26 Cast((String, Ty, FnPtr)),
27}
28
29fn dynify<T: TyVisitable>(mut x: T, new_self: Option<Ty>, for_method: bool) -> T {
37 struct ReplaceSelfVisitor {
38 new_self: Option<Ty>,
39 for_method: bool,
40 }
41 impl VarsVisitor for ReplaceSelfVisitor {
42 fn visit_type_var(&mut self, v: TypeDbVar) -> Option<Ty> {
43 if let DeBruijnVar::Bound(DeBruijnId::ZERO, type_id) = v {
44 Some(if let Some(new_id) = type_id.index().checked_sub(1) {
46 TyKind::TypeVar(DeBruijnVar::Bound(DeBruijnId::ZERO, TypeVarId::new(new_id)))
47 .into_ty()
48 } else {
49 self.new_self.clone().expect(
50 "Found unexpected `Self`
51 type when constructing vtable",
52 )
53 })
54 } else {
55 None
56 }
57 }
58
59 fn visit_clause_var(&mut self, v: ClauseDbVar) -> Option<TraitRefKind> {
60 if let DeBruijnVar::Bound(DeBruijnId::ZERO, clause_id) = v {
61 if self.for_method && clause_id == TraitClauseId::ZERO {
62 Some(TraitRefKind::Dyn)
64 } else {
65 panic!("Found unexpected clause var when constructing vtable: {v}")
66 }
67 } else {
68 None
69 }
70 }
71
72 fn visit_self_clause(&mut self) -> Option<TraitRefKind> {
73 Some(TraitRefKind::Dyn)
74 }
75 }
76 x.visit_vars(&mut ReplaceSelfVisitor {
77 new_self,
78 for_method,
79 });
80 x
81}
82
83impl ItemTransCtx<'_, '_> {
85 pub fn check_at_most_one_pred_has_methods(
86 &mut self,
87 span: Span,
88 preds: &hax::GenericPredicates,
89 ) -> Result<(), Error> {
90 for pred in preds.predicates.iter().skip(1) {
92 if let hax::ClauseKind::Trait(trait_predicate) = pred.clause.kind.hax_skip_binder_ref()
93 {
94 let trait_def_id = &trait_predicate.trait_ref.def_id;
95 let trait_def = self.poly_hax_def(trait_def_id)?;
96 let has_methods = match trait_def.kind() {
97 hax::FullDefKind::Trait { items, .. } => items
98 .iter()
99 .any(|assoc| matches!(assoc.kind, hax::AssocKind::Fn { .. })),
100 hax::FullDefKind::TraitAlias { .. } => false,
101 _ => unreachable!(),
102 };
103 if has_methods {
104 raise_error!(
105 self,
106 span,
107 "`dyn Trait` with multiple method-bearing predicates is not supported"
108 );
109 }
110 }
111 }
112 Ok(())
113 }
114
115 pub fn translate_dyn_binder<T, U>(
116 &mut self,
117 span: Span,
118 binder: &hax::DynBinder<T>,
119 f: impl FnOnce(&mut Self, Ty, &T) -> Result<U, Error>,
120 ) -> Result<Binder<U>, Error> {
121 self.check_at_most_one_pred_has_methods(span, &binder.predicates)?;
125
126 self.binding_levels.push(BindingLevel::new());
128
129 let ty_id = self
131 .innermost_binder_mut()
132 .push_type_var(binder.existential_ty.index, binder.existential_ty.name);
133 let ty = TyKind::TypeVar(DeBruijnVar::new_at_zero(ty_id)).into_ty();
134
135 self.register_predicates(&binder.predicates, PredicateOrigin::Dyn)?;
136
137 let val = f(self, ty, &binder.val)?;
138
139 if self.monomorphize() {
144 struct ShiftDynClauseVars;
145 impl VarsVisitor for ShiftDynClauseVars {
146 fn visit_clause_var(&mut self, v: ClauseDbVar) -> Option<TraitRefKind> {
147 if let DeBruijnVar::Bound(DeBruijnId::ZERO, clause_id) = v
148 && let Some(new_id) = clause_id.index().checked_sub(1)
149 {
150 return Some(TraitRefKind::Clause(DeBruijnVar::Bound(
151 DeBruijnId::ZERO,
152 TraitClauseId::new(new_id),
153 )));
154 }
155 None
156 }
157 }
158
159 self.innermost_generics_mut()
160 .trait_type_constraints
161 .iter_mut()
162 .for_each(|pred| pred.visit_vars(&mut ShiftDynClauseVars));
163 }
164
165 let params = self.binding_levels.pop().unwrap().params;
166 Ok(Binder {
167 params: params,
168 skip_binder: val,
169 kind: BinderKind::Dyn,
170 })
171 }
172}
173
174#[derive(Debug)]
177pub enum TrVTableField {
178 Size,
179 Align,
180 Drop,
181 Method(TraitItemName, hax::Binder<hax::TyFnSig>),
182 SuperTrait(TraitClauseId, hax::Clause),
183}
184
185pub struct VTableData {
186 pub fields: IndexVec<FieldId, TrVTableField>,
187 pub supertrait_map: IndexMap<TraitClauseId, Option<FieldId>>,
188}
189
190impl ItemTransCtx<'_, '_> {
192 pub fn trait_is_dyn_compatible(&mut self, def_id: &hax::DefId) -> Result<bool, Error> {
196 let def = self.poly_hax_def(def_id)?;
197 Ok(match def.kind() {
198 hax::FullDefKind::Trait { dyn_self, .. }
199 | hax::FullDefKind::TraitAlias { dyn_self, .. } => dyn_self.is_some(),
200 _ => false,
201 })
202 }
203
204 fn pred_is_for_self(&self, tref: &hax::TraitRef) -> bool {
206 let first_ty = tref
207 .generic_args
208 .iter()
209 .filter_map(|arg| match arg {
210 hax::GenericArg::Type(ty) => Some(ty),
211 _ => None,
212 })
213 .next();
214 match first_ty {
215 None => false,
216 Some(first_ty) => match first_ty.kind() {
217 hax::TyKind::Param(param_ty) if param_ty.index == 0 => {
218 assert_eq!(param_ty.name, kw::SelfUpper);
219 true
220 }
221 _ => false,
222 },
223 }
224 }
225
226 pub fn translate_vtable_struct_ref(
227 &mut self,
228 span: Span,
229 tref: &hax::TraitRef,
230 ) -> Result<TypeDeclRef, Error> {
231 Ok(self
232 .translate_vtable_struct_ref_maybe_enqueue(true, span, tref)?
233 .expect("trait should be dyn-compatible"))
234 }
235
236 pub fn translate_vtable_struct_ref_no_enqueue(
237 &mut self,
238 span: Span,
239 tref: &hax::TraitRef,
240 ) -> Result<Option<TypeDeclRef>, Error> {
241 self.translate_vtable_struct_ref_maybe_enqueue(false, span, tref)
242 }
243
244 pub fn translate_vtable_struct_ref_maybe_enqueue(
246 &mut self,
247 enqueue: bool,
248 span: Span,
249 tref: &hax::TraitRef,
250 ) -> Result<Option<TypeDeclRef>, Error> {
251 if !self.trait_is_dyn_compatible(&tref.def_id)? {
252 return Ok(None);
253 }
254
255 if self.monomorphize() {
257 let item_src =
258 TransItemSource::monomorphic_trait(&tref.def_id, TransItemSourceKind::VTable);
259 let id: ItemId = self.register_and_enqueue(span, item_src);
260 let id = id
261 .try_into()
262 .expect("translated trait decl should be a trait decl id");
263 return Ok(Some(TypeDeclRef {
264 id,
265 generics: Box::new(GenericArgs::empty()),
266 }));
267 }
268
269 let mut vtable_ref: TypeDeclRef =
272 self.translate_item_maybe_enqueue(span, enqueue, tref, TransItemSourceKind::VTable)?;
273 vtable_ref
275 .generics
276 .types
277 .remove_and_shift_ids(TypeVarId::ZERO);
278
279 let assoc_tys: Vec<_> = tref
281 .trait_associated_types(self.hax_state_with_id())
282 .iter()
283 .map(|ty| self.translate_ty(span, ty))
284 .try_collect()?;
285 vtable_ref.generics.types.extend(assoc_tys);
286
287 Ok(Some(vtable_ref))
288 }
289
290 fn prepare_vtable_fields(
291 &mut self,
292 trait_def: &hax::FullDef,
293 implied_predicates: &hax::GenericPredicates,
294 ) -> Result<VTableData, Error> {
295 let mut supertrait_map: IndexMap<TraitClauseId, _> =
296 (0..implied_predicates.predicates.len())
297 .map(|_| None)
298 .collect();
299 let mut fields = IndexVec::new();
300
301 fields.push(TrVTableField::Size);
303 fields.push(TrVTableField::Align);
304 fields.push(TrVTableField::Drop);
305
306 if let hax::FullDefKind::Trait { items, .. } = trait_def.kind() {
308 for item in items {
309 let item_def_id = &item.def_id;
310 let item_def =
312 self.hax_def(&trait_def.this().with_def_id(self.hax_state(), item_def_id))?;
313 if let hax::FullDefKind::AssocFn {
314 sig,
315 vtable_sig: Some(_),
316 ..
317 } = item_def.kind()
318 {
319 let name = self.translate_trait_item_name(&item_def_id)?;
320 fields.push(TrVTableField::Method(name, sig.clone()));
321 }
322 }
323 }
324
325 for (i, pred) in implied_predicates.iter_trait_clauses().enumerate() {
327 let trait_clause_id = TraitClauseId::from_raw(i); let clause = &pred.clause;
329 let hax::ClauseKind::Trait(pred) = clause.kind.hax_skip_binder_ref() else {
330 unreachable!()
331 };
332 if self.pred_is_for_self(&pred.trait_ref) {
334 if !self.trait_is_dyn_compatible(&pred.trait_ref.def_id)? {
335 self.assert_is_destruct(&pred.trait_ref);
337 continue;
338 }
339 supertrait_map[trait_clause_id] = Some(fields.next_idx());
340 fields.push(TrVTableField::SuperTrait(trait_clause_id, clause.clone()));
341 }
342 }
343
344 Ok(VTableData {
345 fields,
346 supertrait_map,
347 })
348 }
349
350 fn assert_is_destruct(&self, tref: &hax::TraitRef) {
356 assert!(
357 tref.def_id
358 .as_rust_def_id()
359 .is_some_and(|id| self.tcx.is_lang_item(id, rustc_hir::LangItem::Destruct)),
360 "unexpected non-dyn compatible supertrait: {:?}",
361 tref.def_id
362 );
363 }
364
365 fn gen_vtable_struct_fields(
366 &mut self,
367 span: Span,
368 self_trait_ref: &TraitRef,
369 vtable_data: &VTableData,
370 ) -> Result<IndexVec<FieldId, Field>, Error> {
371 let mut fields = IndexVec::new();
372 let mut supertrait_counter = (0..).into_iter();
373 for field in &vtable_data.fields {
374 let (name, ty) = match field {
375 TrVTableField::Size => ("size".into(), usize_ty()),
376 TrVTableField::Align => ("align".into(), usize_ty()),
377 TrVTableField::Drop => {
378 if self.monomorphize() {
380 let erased_ptr_ty = Ty::new(TyKind::RawPtr(Ty::mk_unit(), RefKind::Shared));
381 ("drop".into(), erased_ptr_ty)
382 } else {
383 let self_ty =
384 TyKind::TypeVar(DeBruijnVar::new_at_zero(TypeVarId::ZERO)).into_ty();
385 let self_ptr = TyKind::RawPtr(self_ty, RefKind::Mut).into_ty();
386 let drop_ty = Ty::new(TyKind::FnPtr(RegionBinder::empty(FunSig {
387 is_unsafe: true,
388 inputs: [self_ptr].into(),
389 output: Ty::mk_unit(),
390 })));
391 ("drop".into(), drop_ty)
392 }
393 }
394 TrVTableField::Method(item_name, sig) => {
395 let field_name = format!("method_{}", item_name.0);
396 if self.monomorphize() {
398 let erased_ptr_ty = Ty::new(TyKind::RawPtr(Ty::mk_unit(), RefKind::Shared));
399 (field_name, erased_ptr_ty)
400 } else {
401 let bound_sig = self.inside_binder(BinderKind::Other, |ctx| {
404 ctx.innermost_binder_mut()
405 .trait_preds
406 .insert(hax::GenericPredicateId::TraitSelf, TraitClauseId::ZERO);
407 ctx.translate_poly_fun_sig(span, &sig)
408 })?;
409 let sig = bound_sig.apply(&{
410 let mut generics = GenericArgs::empty();
411 generics.trait_refs.push(self_trait_ref.clone());
413 generics
414 });
415 let ty = TyKind::FnPtr(sig).into_ty();
416 (field_name, ty)
417 }
418 }
419 TrVTableField::SuperTrait(_, clause) => {
420 let vtbl_struct =
421 self.translate_region_binder(span, &clause.kind, |ctx, kind| {
422 let hax::ClauseKind::Trait(pred) = kind else {
423 unreachable!()
424 };
425 ctx.translate_vtable_struct_ref(span, &pred.trait_ref)
426 })?;
427 let vtbl_struct = self.erase_region_binder(vtbl_struct);
428 let ty = Ty::new(TyKind::Ref(
429 Region::Static,
430 Ty::new(TyKind::Adt(vtbl_struct)),
431 RefKind::Shared,
432 ));
433 let name = format!("super_trait_{}", supertrait_counter.next().unwrap());
434 (name, ty)
435 }
436 };
437 fields.push(Field {
438 span,
439 attr_info: AttrInfo::dummy_public(),
440 name: Some(name),
441 ty,
442 });
443 }
444 Ok(fields)
445 }
446
447 #[tracing::instrument(skip(self, span))]
450 fn register_preshim(&mut self, span: Span, trait_def: &hax::FullDef) -> Result<(), Error> {
451 let item_src =
452 TransItemSource::monomorphic_trait(&trait_def.def_id(), TransItemSourceKind::TraitDecl);
453 let item_id = match self.t_ctx.id_map.get(&item_src) {
454 Some(tid) => *tid,
455 None => {
456 panic!("MONO: expected trait has not been translated");
457 }
458 };
459
460 let trait_id = item_id
461 .try_into()
462 .expect("MONO: The item_id should be a trait decl id");
463
464 let mut preshim_types = vec![];
465 for arg in trait_def.this().generic_args.iter().skip(1) {
466 if let GenericArg::Type(hax_ty) = arg {
467 preshim_types.push(self.translate_ty(span, hax_ty)?);
468 }
469 }
470 if let hax::FullDefKind::Trait {
471 dyn_self: Some(dyn_self),
472 ..
473 } = trait_def.kind()
474 {
475 let dyn_self = self.translate_ty(span, dyn_self)?;
476 if let TyKind::DynTrait(pred) = dyn_self.kind() {
477 for ttc in &pred.binder.params.trait_type_constraints {
478 preshim_types.push(ttc.skip_binder.ty.clone());
479 }
480 }
481 }
482
483 if !self
484 .t_ctx
485 .translated_preshims
486 .insert((trait_id, preshim_types))
487 {
488 return Ok(());
489 }
490
491 let _: FnPtr = self.translate_item(
493 span,
494 trait_def.this(),
495 TransItemSourceKind::VTableDropPreShim,
496 )?;
497
498 if let hax::FullDefKind::Trait { items, .. } = trait_def.kind() {
500 for item in items {
501 let item_def_id = &item.def_id;
502 let item_def =
504 self.hax_def(&trait_def.this().with_def_id(self.hax_state(), item_def_id))?;
505 if let hax::FullDefKind::AssocFn {
506 vtable_sig: Some(_),
507 ..
508 } = item_def.kind()
509 {
510 let name = self.translate_trait_item_name(&item_def_id)?;
511
512 let _: FnPtr = self.translate_item(
513 span,
514 trait_def.this(),
515 TransItemSourceKind::VTableMethodPreShim(trait_id, name),
516 )?;
517 }
518 }
519 }
520
521 Ok(())
522 }
523
524 pub(crate) fn translate_vtable_struct(
539 mut self,
540 type_id: TypeDeclId,
541 item_meta: ItemMeta,
542 trait_def: &hax::FullDef,
543 ) -> Result<TypeDecl, Error> {
544 let mono = self.monomorphize();
545 let span = item_meta.span;
546 if !self.trait_is_dyn_compatible(trait_def.def_id())? {
547 raise_error!(
548 self,
549 span,
550 "Trying to compute the vtable type \
551 for a non-dyn-compatible trait"
552 );
553 }
554
555 let (hax::FullDefKind::Trait {
556 self_predicate,
557 dyn_self,
558 implied_predicates,
559 ..
560 }
561 | hax::FullDefKind::TraitAlias {
562 self_predicate,
563 dyn_self,
564 implied_predicates,
565 ..
566 }) = trait_def.kind()
567 else {
568 panic!()
569 };
570 let Some(dyn_self) = dyn_self else {
571 panic!("Trying to generate a vtable for a non-dyn-compatible trait")
572 };
573
574 let self_trait_ref = TraitRef::new(
575 TraitRefKind::SelfId,
576 RegionBinder::empty(self.translate_trait_predicate(span, self_predicate)?),
577 );
578
579 let mut field_map = IndexVec::new();
580 let mut supertrait_map: IndexMap<TraitClauseId, _> =
581 (0..implied_predicates.predicates.len())
582 .map(|_| None)
583 .collect();
584 let (mut kind, layout) = if item_meta.opacity.with_private_contents().is_opaque() {
585 (TypeDeclKind::Opaque, None)
586 } else {
587 let vtable_data = self.prepare_vtable_fields(trait_def, implied_predicates)?;
590 let fields = self.gen_vtable_struct_fields(span, &self_trait_ref, &vtable_data)?;
591
592 let kind = TypeDeclKind::Struct(fields);
593 let layout = self.generate_naive_layout(span, &kind)?;
594 supertrait_map = vtable_data.supertrait_map;
595 field_map = vtable_data.fields.map_ref(|tr_field| match *tr_field {
596 TrVTableField::Size => VTableField::Size,
597 TrVTableField::Align => VTableField::Align,
598 TrVTableField::Drop => VTableField::Drop,
599 TrVTableField::Method(name, ..) => VTableField::Method(name),
600 TrVTableField::SuperTrait(clause_id, ..) => VTableField::SuperTrait(clause_id),
601 });
602 (kind, Some(layout))
603 };
604
605 let mut generics = Default::default();
606
607 let dyn_predicate = if mono {
608 DynPredicate {
609 binder: Binder {
610 params: GenericParams::empty(),
611 skip_binder: TyKind::Error(
612 "mono vtable dyn predicate is intentionally erased".to_string(),
613 )
614 .into_ty(),
615 kind: BinderKind::Dyn,
616 },
617 }
618 } else {
619 let mut dyn_self = {
622 let dyn_self = self.translate_ty(span, dyn_self)?;
623 let TyKind::DynTrait(mut dyn_pred) = dyn_self.kind().clone() else {
624 panic!("incorrect `dyn_self`")
625 };
626
627 for (i, ty_constraint) in dyn_pred
630 .binder
631 .params
632 .trait_type_constraints
633 .iter_mut()
634 .enumerate()
635 {
636 let name = format!("Ty{i}");
637 let new_ty = self
638 .the_only_binder_mut()
639 .params
640 .types
641 .push_with(|index| TypeParam { index, name });
642 let new_ty =
645 TyKind::TypeVar(DeBruijnVar::bound(DeBruijnId::new(2), new_ty)).into_ty();
646 ty_constraint.skip_binder.ty = new_ty;
647 }
648 TyKind::DynTrait(dyn_pred).into_ty()
649 };
650
651 generics = self.into_generics();
654 {
655 dyn_self = dynify(dyn_self, None, false);
656 generics = dynify(generics, Some(dyn_self.clone()), false);
657 kind = dynify(kind, Some(dyn_self.clone()), true);
658 generics.types.remove_and_shift_ids(TypeVarId::ZERO);
659 generics.types.iter_mut().for_each(|ty| {
660 ty.index -= 1;
661 });
662 }
663
664 dyn_self
665 .kind()
666 .as_dyn_trait()
667 .expect("incorrect `dyn_self`")
668 .clone()
669 };
670 Ok(TypeDecl {
671 def_id: type_id,
672 item_meta: item_meta,
673 generics: generics,
674 src: ItemSource::VTableTy {
675 dyn_predicate: dyn_predicate,
676 field_map,
677 supertrait_map,
678 },
679 kind,
680 layout,
681 ptr_metadata: PtrMetadata::None,
683 repr: None,
684 })
685 }
686}
687
688impl ItemTransCtx<'_, '_> {
690 pub fn translate_vtable_instance_const(
692 &mut self,
693 span: Span,
694 impl_expr: &hax::ImplExpr,
695 ) -> Result<Box<ConstantExpr>, Error> {
696 let tref = impl_expr.r#trait.hax_skip_binder_ref();
697 if !self.trait_is_dyn_compatible(&tref.def_id)? {
698 raise_error!(
699 self,
700 span,
701 "Trait {:?} should be dyn-compatible",
702 tref.def_id
703 );
704 }
705
706 let vtbl_ty = {
707 let vtbl_ty = self.translate_region_binder(span, &impl_expr.r#trait, |ctx, tref| {
708 ctx.translate_vtable_struct_ref(span, tref)
709 })?;
710 let vtbl_ty = self.erase_region_binder(vtbl_ty);
711 TyKind::Adt(vtbl_ty).into_ty()
712 };
713 let ty = TyKind::Ref(Region::Static, vtbl_ty.clone(), RefKind::Shared).into_ty();
714
715 let kind = {
716 if let hax::ImplExprAtom::Concrete(impl_item) = &impl_expr.r#impl {
717 let vtable_instance =
720 self.translate_region_binder(span, &impl_expr.r#trait, |ctx, tref| {
721 ctx.translate_vtable_instance_ref(span, tref, impl_item)
722 })?;
723 let vtable_instance = self.erase_region_binder(vtable_instance);
724 let vtable_instance = Box::new(ConstantExpr {
725 kind: ConstantExprKind::Global(vtable_instance),
726 ty: vtbl_ty,
727 });
728 ConstantExprKind::Ref(vtable_instance, None)
729 } else {
730 ConstantExprKind::VTableRef(self.translate_trait_impl_expr(span, impl_expr)?)
731 }
732 };
733
734 Ok(Box::new(ConstantExpr { kind, ty }))
735 }
736
737 pub fn translate_vtable_instance_ref(
739 &mut self,
740 span: Span,
741 trait_ref: &hax::TraitRef,
742 impl_ref: &hax::ItemRef,
743 ) -> Result<GlobalDeclRef, Error> {
744 Ok(self
745 .translate_vtable_instance_ref_maybe_enqueue(true, span, trait_ref, impl_ref)?
746 .expect("trait should be dyn-compatible"))
747 }
748
749 pub fn translate_vtable_instance_ref_no_enqueue(
750 &mut self,
751 span: Span,
752 trait_ref: &hax::TraitRef,
753 impl_ref: &hax::ItemRef,
754 ) -> Result<Option<GlobalDeclRef>, Error> {
755 self.translate_vtable_instance_ref_maybe_enqueue(false, span, trait_ref, impl_ref)
756 }
757
758 pub fn translate_vtable_instance_ref_maybe_enqueue(
759 &mut self,
760 enqueue: bool,
761 span: Span,
762 trait_ref: &hax::TraitRef,
763 impl_ref: &hax::ItemRef,
764 ) -> Result<Option<GlobalDeclRef>, Error> {
765 if !self.trait_is_dyn_compatible(&trait_ref.def_id)? {
766 return Ok(None);
767 }
768 let vtable_ref: GlobalDeclRef = self.translate_item_maybe_enqueue(
773 span,
774 enqueue,
775 impl_ref,
776 TransItemSourceKind::VTableInstance(TraitImplSource::Normal),
777 )?;
778 Ok(Some(vtable_ref))
779 }
780
781 fn get_vtable_instance_info<'a>(
783 &mut self,
784 span: Span,
785 impl_def: &'a hax::FullDef,
786 impl_kind: &TraitImplSource,
787 ) -> Result<(Option<TraitImplRef>, TypeDeclRef), Error> {
788 let implemented_trait = match impl_def.kind() {
789 hax::FullDefKind::TraitImpl { trait_pred, .. } => &trait_pred.trait_ref,
790 _ => unreachable!(),
791 };
792 let vtable_struct_ref = self.translate_vtable_struct_ref(span, implemented_trait)?;
793 if self.monomorphize() {
794 return Ok((None, vtable_struct_ref));
795 }
796 let impl_ref = self.translate_item(
797 span,
798 impl_def.this(),
799 TransItemSourceKind::TraitImpl(*impl_kind),
800 )?;
801 Ok((Some(impl_ref), vtable_struct_ref))
802 }
803
804 pub(crate) fn translate_vtable_instance(
819 mut self,
820 global_id: GlobalDeclId,
821 item_meta: ItemMeta,
822 impl_def: &hax::FullDef,
823 impl_kind: &TraitImplSource,
824 ) -> Result<GlobalDecl, Error> {
825 let span = item_meta.span;
826
827 let (src, vtable_struct_ref) =
828 match self.get_vtable_instance_info(span, impl_def, impl_kind)? {
829 (Some(impl_ref), vtable_struct_ref) => {
830 (ItemSource::VTableInstance { impl_ref }, vtable_struct_ref)
831 }
832 (None, vtable_struct_ref) => (ItemSource::VTableInstanceMono, vtable_struct_ref),
833 };
834
835 if self.monomorphize() {
837 let trait_pred = match impl_def.kind() {
838 hax::FullDefKind::TraitImpl { trait_pred, .. } => trait_pred,
839 _ => unreachable!(),
840 };
841 let trait_def = self.hax_def(&trait_pred.trait_ref)?;
842 self.register_preshim(span, &trait_def)?;
843 }
844
845 let init = self.register_item(
847 span,
848 impl_def.this(),
849 TransItemSourceKind::VTableInstanceInitializer(*impl_kind),
850 );
851
852 Ok(GlobalDecl {
853 def_id: global_id,
854 item_meta,
855 generics: self.into_generics(),
856 src,
857 global_kind: GlobalKind::Static,
859 ty: Ty::new(TyKind::Adt(vtable_struct_ref)),
860 init,
861 })
862 }
863
864 fn add_method_to_vtable_value(
865 &mut self,
866 span: Span,
867 impl_def: &hax::FullDef,
868 item: &hax::ImplAssocItem,
869 ) -> Result<Option<VtableMethodValue>, Error> {
870 let item_def = self.poly_hax_def(&item.decl_def_id)?;
872 let hax::FullDefKind::AssocFn {
873 vtable_sig: Some(_),
874 ..
875 } = item_def.kind()
876 else {
877 return Ok(None);
878 };
879
880 let vtable_value = match &item.value {
881 hax::ImplAssocItemValue::Provided {
882 def_id: item_def_id,
883 ..
884 } => {
885 let item_ref = impl_def.this().with_def_id(self.hax_state(), item_def_id);
888 let shim_ref =
889 self.translate_fn_ptr(span, &item_ref, TransItemSourceKind::VTableMethod)?;
890 if self.monomorphize() {
894 assert!(self.binding_levels.len() == 1);
898 let orginal_binding = self.binding_levels.pop();
899 let def = self.poly_hax_def(&item_ref.def_id)?;
900 self.translate_item_generics(span, &def, &TransItemSourceKind::VTableMethod)?;
901
902 let name = self.translate_trait_item_name(item.def_id())?;
903
904 let assoc_fun_def = self.hax_def(&item_ref)?;
905 let vtable_sig = match assoc_fun_def.kind() {
906 hax::FullDefKind::AssocFn {
907 vtable_sig: Some(vtable_sig),
908 ..
909 } => vtable_sig.clone(),
910 _ => unreachable!("MONO: only assoc fun is supported"),
911 };
912
913 let signature = self.translate_fun_sig(span, &vtable_sig.value)?;
914 let method_ty = Ty::new(TyKind::FnPtr(RegionBinder {
916 regions: self.outermost_generics().regions.clone(),
917 skip_binder: signature,
918 }));
919
920 self.binding_levels.pop();
922 if let Some(binding_level) = orginal_binding {
923 self.binding_levels.push(binding_level);
924 }
925
926 VtableMethodValue::Cast((name.to_string(), method_ty, shim_ref))
927 } else {
928 VtableMethodValue::Const(ConstantExprKind::FnDef(shim_ref))
929 }
930 }
931 hax::ImplAssocItemValue::DefaultedFn { .. } => VtableMethodValue::Const(
932 ConstantExprKind::Opaque("shim for default methods aren't yet supported".into()),
933 ),
934 _ => return Ok(None),
935 };
936
937 Ok(Some(vtable_value))
938 }
939
940 fn gen_vtable_instance_init_body(
948 &mut self,
949 span: Span,
950 impl_def: &hax::FullDef,
951 vtable_struct_ref: TypeDeclRef,
952 ) -> Result<Body, Error> {
953 let hax::FullDefKind::TraitImpl {
954 trait_pred,
955 implied_impl_exprs,
956 items,
957 ..
958 } = impl_def.kind()
959 else {
960 unreachable!()
961 };
962
963 let trait_def = self.hax_def(&trait_pred.trait_ref)?;
964 let poly_trait_def = self.poly_hax_def(&trait_pred.trait_ref.def_id)?;
966 let hax::FullDefKind::Trait {
967 implied_predicates: implied_preds,
968 ..
969 } = poly_trait_def.kind()
970 else {
971 unreachable!()
972 };
973
974 let implemented_trait = self.translate_trait_decl_ref(span, &trait_pred.trait_ref)?;
975 let self_ty = &implemented_trait.generics.types[0];
977
978 let mut builder = BodyBuilder::new(span, 0);
979 let ret_ty = Ty::new(TyKind::Adt(vtable_struct_ref.clone()));
980 let ret_place = builder.new_var(Some("ret".into()), ret_ty.clone());
981
982 let vtable_data = self.prepare_vtable_fields(&trait_def, implied_preds)?;
983 let field_tys = {
986 let vtable_decl_id = vtable_struct_ref.id.as_adt().unwrap().clone();
987 let ItemRef::Type(vtable_def) = self.t_ctx.get_or_translate(vtable_decl_id.into())?
988 else {
989 unreachable!()
990 };
991 let fields = match &vtable_def.kind {
992 TypeDeclKind::Struct(fields) => fields,
993 TypeDeclKind::Opaque => return Ok(Body::Opaque),
994 TypeDeclKind::Error(error) => return Err(Error::new(span, error.clone())),
995 _ => unreachable!(),
996 };
997 fields
998 .iter()
999 .map(|f| &f.ty)
1000 .cloned()
1001 .map(|ty| ty.substitute(&vtable_struct_ref.generics))
1002 .collect_vec()
1003 };
1004
1005 let mut aggregate_fields = vec![];
1007 let mut items_iter = items.iter();
1008 for (field, ty) in vtable_data.fields.into_iter().zip(field_tys) {
1009 let mk_const = |kind| {
1011 Operand::Const(Box::new(ConstantExpr {
1012 kind,
1013 ty: ty.clone(),
1014 }))
1015 };
1016 let mut mk_cast = |(method_name, method_ty, method_shim): (String, Ty, FnPtr)| {
1040 let method_local = builder.new_var(Some(method_name.clone()), method_ty.clone());
1041 let shim = Rvalue::Use(Operand::Const(Box::new(ConstantExpr {
1042 kind: ConstantExprKind::FnDef(method_shim.clone()),
1043 ty: method_ty.clone(),
1044 })));
1045 let cast_local = builder.new_var(
1046 Some("erased_".to_string() + method_name.as_str()),
1047 ty.clone(),
1048 );
1049 let cast = Rvalue::UnaryOp(
1050 UnOp::Cast(CastKind::RawPtr(
1051 method_local.ty().clone(),
1052 cast_local.ty().clone(),
1053 )),
1054 Operand::Move(method_local.clone()),
1055 );
1056
1057 builder.push_statement(StatementKind::Assign(method_local.clone(), shim));
1058 builder.push_statement(StatementKind::Assign(cast_local.clone(), cast));
1059 Operand::Move(cast_local)
1060 };
1061 let op = match field {
1062 TrVTableField::Size => {
1063 let size_local = builder.new_var(Some("size".to_string()), ty);
1064 builder.push_statement(StatementKind::Assign(
1065 size_local.clone(),
1066 Rvalue::NullaryOp(NullOp::SizeOf, self_ty.clone()),
1067 ));
1068 Operand::Move(size_local)
1069 }
1070 TrVTableField::Align => {
1071 let align_local = builder.new_var(Some("align".to_string()), ty);
1072 builder.push_statement(StatementKind::Assign(
1073 align_local.clone(),
1074 Rvalue::NullaryOp(NullOp::AlignOf, self_ty.clone()),
1075 ));
1076 Operand::Move(align_local)
1077 }
1078 TrVTableField::Drop => {
1079 let drop_shim = self.translate_item(
1080 span,
1081 impl_def.this(),
1082 TransItemSourceKind::VTableDropShim,
1083 )?;
1084 if self.monomorphize() {
1085 let hax::FullDefKind::Trait { dyn_self, .. } = trait_def.kind() else {
1087 panic!()
1088 };
1089
1090 let Some(dyn_self) = dyn_self else {
1091 panic!(
1092 "MONO: Trying to generate a vtable for a non-dyn-compatible trait"
1093 )
1094 };
1095 let ref_dyn_self =
1096 TyKind::RawPtr(self.translate_ty(span, dyn_self)?, RefKind::Mut)
1097 .into_ty();
1098 let signature = FunSig {
1099 is_unsafe: true,
1100 inputs: vec![ref_dyn_self.clone()],
1101 output: Ty::mk_unit(),
1102 };
1103 let drop_ty = Ty::new(TyKind::FnPtr(RegionBinder::empty(signature)));
1104
1105 mk_cast(("drop".to_string(), drop_ty.clone(), drop_shim))
1106 } else {
1107 mk_const(ConstantExprKind::FnDef(drop_shim))
1108 }
1109 }
1110 TrVTableField::Method(..) => 'a: {
1111 for item in items_iter.by_ref() {
1114 if let Some(kind) = self.add_method_to_vtable_value(span, impl_def, item)? {
1115 match kind {
1116 VtableMethodValue::Const(const_kind) => {
1117 break 'a mk_const(const_kind);
1118 }
1119 VtableMethodValue::Cast(method) => break 'a mk_cast(method),
1120 }
1121 }
1122 }
1123 unreachable!()
1124 }
1125 TrVTableField::SuperTrait(clause_id, _) => {
1126 let impl_expr = &implied_impl_exprs[clause_id.index()];
1127 let vtable = self.translate_vtable_instance_const(span, impl_expr)?;
1128 Operand::Const(vtable)
1129 }
1130 };
1131 aggregate_fields.push(op);
1132 }
1133
1134 builder.push_statement(StatementKind::Assign(
1136 ret_place,
1137 Rvalue::Aggregate(
1138 AggregateKind::Adt(vtable_struct_ref.clone(), None, None),
1139 aggregate_fields,
1140 ),
1141 ));
1142
1143 Ok(Body::Unstructured(builder.build()))
1144 }
1145
1146 pub(crate) fn translate_vtable_instance_init(
1147 mut self,
1148 init_func_id: FunDeclId,
1149 item_meta: ItemMeta,
1150 impl_def: &hax::FullDef,
1151 impl_kind: &TraitImplSource,
1152 ) -> Result<FunDecl, Error> {
1153 let span = item_meta.span;
1154
1155 let (src, vtable_struct_ref) =
1156 match self.get_vtable_instance_info(span, impl_def, impl_kind)? {
1157 (Some(impl_ref), vtable_struct_ref) => {
1158 (ItemSource::VTableInstance { impl_ref }, vtable_struct_ref)
1159 }
1160 (None, vtable_struct_ref) => (ItemSource::VTableInstanceMono, vtable_struct_ref),
1161 };
1162
1163 let init_for = self.register_item(
1164 span,
1165 impl_def.this(),
1166 TransItemSourceKind::VTableInstance(*impl_kind),
1167 );
1168
1169 let sig = FunSig {
1171 is_unsafe: false,
1172 inputs: vec![],
1173 output: Ty::new(TyKind::Adt(vtable_struct_ref.clone())),
1174 };
1175
1176 let body = match impl_kind {
1177 _ if item_meta.opacity.with_private_contents().is_opaque() => Body::Opaque,
1178 TraitImplSource::Normal => {
1179 self.gen_vtable_instance_init_body(span, impl_def, vtable_struct_ref)?
1180 }
1181 _ => {
1182 raise_error!(
1183 self,
1184 span,
1185 "Don't know how to generate a vtable for a virtual impl {impl_kind:?}"
1186 );
1187 }
1188 };
1189
1190 Ok(FunDecl {
1191 def_id: init_func_id,
1192 item_meta: item_meta,
1193 generics: self.into_generics(),
1194 signature: sig,
1195 src,
1196 is_global_initializer: Some(init_for),
1197 body,
1198 })
1199 }
1200
1201 fn translate_vtable_shim_body(
1219 &mut self,
1220 span: Span,
1221 target_receiver: &Ty,
1222 shim_signature: &FunSig,
1223 impl_func_def: &hax::FullDef,
1224 ) -> Result<Body, Error> {
1225 let mut builder = BodyBuilder::new(span, shim_signature.inputs.len());
1226
1227 let ret_place = builder.new_var(None, shim_signature.output.clone());
1228 let mut method_args = shim_signature
1229 .inputs
1230 .iter()
1231 .map(|ty| builder.new_var(None, ty.clone()))
1232 .collect_vec();
1233 let target_self = builder.new_var(None, target_receiver.clone());
1234
1235 let shim_self = mem::replace(&mut method_args[0], target_self.clone());
1237
1238 let rval = Rvalue::UnaryOp(
1242 UnOp::Cast(CastKind::Concretize(
1243 shim_self.ty().clone(),
1244 target_self.ty().clone(),
1245 )),
1246 Operand::Move(shim_self.clone()),
1247 );
1248 builder.push_statement(StatementKind::Assign(target_self.clone(), rval));
1249
1250 let fun_id = self.register_item(span, &impl_func_def.this(), TransItemSourceKind::Fun);
1251 let generics = self.outermost_binder().params.identity_args();
1252 builder.call(Call {
1253 func: FnOperand::Regular(FnPtr::new(FnPtrKind::Fun(fun_id), generics)),
1254 args: method_args
1255 .into_iter()
1256 .map(|arg| Operand::Move(arg))
1257 .collect(),
1258 dest: ret_place,
1259 });
1260
1261 Ok(Body::Unstructured(builder.build()))
1262 }
1263
1264 fn translate_vtable_drop_shim_body(
1276 &mut self,
1277 span: Span,
1278 shim_receiver: &Ty,
1279 target_receiver: &Ty,
1280 trait_pred: &TraitPredicate,
1281 ) -> Result<Body, Error> {
1282 let mut builder = BodyBuilder::new(span, 1);
1283
1284 builder.new_var(Some("ret".into()), Ty::mk_unit());
1285 let dyn_self = builder.new_var(Some("dyn_self".into()), shim_receiver.clone());
1286 let target_self = builder.new_var(Some("target_self".into()), target_receiver.clone());
1287
1288 let rval = Rvalue::UnaryOp(
1290 UnOp::Cast(CastKind::Concretize(
1291 dyn_self.ty().clone(),
1292 target_self.ty().clone(),
1293 )),
1294 Operand::Move(dyn_self.clone()),
1295 );
1296 builder.push_statement(StatementKind::Assign(target_self.clone(), rval));
1297
1298 let destruct_trait = self.tcx.lang_items().destruct_trait().unwrap();
1303 let impl_expr: hax::ImplExpr = {
1304 let s = self.hax_state_with_id();
1305 let rustc_trait_args = trait_pred.trait_ref.rustc_args(s);
1306 let generics = self.tcx.mk_args(&rustc_trait_args[..1]); let tref =
1308 rustc_middle::ty::TraitRef::new_from_args(self.tcx, destruct_trait, generics);
1309 hax::solve_trait(s, rustc_middle::ty::Binder::dummy(tref))
1310 };
1311 let tref = self.translate_trait_impl_expr(span, &impl_expr)?;
1312
1313 let drop_arg = target_self.clone().deref();
1315 builder.insert_drop(drop_arg, tref);
1316
1317 Ok(Body::Unstructured(builder.build()))
1318 }
1319
1320 pub(crate) fn translate_vtable_drop_shim(
1321 mut self,
1322 fun_id: FunDeclId,
1323 item_meta: ItemMeta,
1324 impl_def: &hax::FullDef,
1325 ) -> Result<FunDecl, Error> {
1326 let span = item_meta.span;
1327
1328 let hax::FullDefKind::TraitImpl {
1329 dyn_self: Some(dyn_self),
1330 trait_pred,
1331 ..
1332 } = impl_def.kind()
1333 else {
1334 raise_error!(
1335 self,
1336 span,
1337 "Trying to generate a vtable drop shim for a non-trait impl"
1338 );
1339 };
1340
1341 let ref_dyn_self =
1343 TyKind::RawPtr(self.translate_ty(span, dyn_self)?, RefKind::Mut).into_ty();
1344 let ref_target_self = {
1346 let impl_trait = self.translate_trait_ref(span, &trait_pred.trait_ref)?;
1347 TyKind::RawPtr(impl_trait.generics.types[0].clone(), RefKind::Mut).into_ty()
1348 };
1349
1350 let signature = FunSig {
1352 is_unsafe: true,
1353 inputs: vec![ref_dyn_self.clone()],
1354 output: Ty::mk_unit(),
1355 };
1356
1357 let body: Body = self.translate_vtable_drop_shim_body(
1358 span,
1359 &ref_dyn_self,
1360 &ref_target_self,
1361 trait_pred,
1362 )?;
1363
1364 Ok(FunDecl {
1365 def_id: fun_id,
1366 item_meta,
1367 generics: self.into_generics(),
1368 signature,
1369 src: ItemSource::VTableMethodShim,
1370 is_global_initializer: None,
1371 body,
1372 })
1373 }
1374
1375 pub(crate) fn translate_vtable_shim(
1376 mut self,
1377 fun_id: FunDeclId,
1378 item_meta: ItemMeta,
1379 impl_func_def: &hax::FullDef,
1380 ) -> Result<FunDecl, Error> {
1381 let span = item_meta.span;
1382
1383 let hax::FullDefKind::AssocFn {
1384 vtable_sig: Some(vtable_sig),
1385 sig: target_signature,
1386 ..
1387 } = impl_func_def.kind()
1388 else {
1389 raise_error!(
1390 self,
1391 span,
1392 "Trying to generate a vtable shim for a non-vtable-safe method"
1393 );
1394 };
1395
1396 let signature = self.translate_fun_sig(span, &vtable_sig.value)?;
1398 let target_receiver = self.translate_ty(span, &target_signature.value.inputs[0])?;
1400
1401 trace!(
1402 "[VtableShim] Obtained dyn signature with receiver type: {}",
1403 signature.inputs[0].with_ctx(&self.into_fmt())
1404 );
1405
1406 let body = if item_meta.opacity.with_private_contents().is_opaque() {
1407 Body::Opaque
1408 } else {
1409 self.translate_vtable_shim_body(span, &target_receiver, &signature, impl_func_def)?
1410 };
1411
1412 Ok(FunDecl {
1413 def_id: fun_id,
1414 item_meta,
1415 generics: self.into_generics(),
1416 signature,
1417 src: ItemSource::VTableMethodShim,
1418 is_global_initializer: None,
1419 body,
1420 })
1421 }
1422
1423 #[tracing::instrument(skip(self, item_meta))]
1428 pub(crate) fn translate_vtable_method_preshim(
1429 mut self,
1430 fun_id: FunDeclId,
1431 item_meta: ItemMeta,
1432 trait_def: &hax::FullDef,
1433 name: &TraitItemName,
1434 trait_id: &TraitDeclId,
1435 ) -> Result<FunDecl, Error> {
1436 let span = item_meta.span;
1437
1438 let mut assoc_func_def = None;
1439 let mut assoc_types = None;
1440
1441 if let hax::FullDefKind::Trait { items, .. } = trait_def.kind() {
1442 for item in items {
1443 let item_def_id = &item.def_id;
1444 let item_def =
1446 self.hax_def(&trait_def.this().with_def_id(self.hax_state(), item_def_id))?;
1447 if let hax::FullDefKind::AssocFn {
1448 ..
1451 } = item_def.kind()
1452 {
1453 let fun_name = self.translate_trait_item_name(&item_def_id)?;
1454 if fun_name == *name {
1455 assoc_func_def = Some(item_def);
1456 }
1457 }
1458 else if let hax::FullDefKind::AssocTy {
1459 implied_predicates, ..}
1460 = item_def.kind() {
1461 trace!("MONO: show:\n {:?}", item_def.kind());
1462 if let Some(pred) = implied_predicates.predicates.first() {
1463 if let hax::ClauseKind::Trait(p) = &pred.clause.kind.value {
1464 assoc_types = Some(p.trait_ref.generic_args.clone());
1465 }
1466 }
1467 }
1468 }
1469 }
1470
1471 let Some(assoc_func_def) = assoc_func_def else {
1472 panic!("MONO: assoc_func_def is not found");
1473 };
1474
1475 assert!(self.binding_levels.len() == 1);
1477 self.binding_levels.pop();
1478 let def = self.poly_hax_def(&assoc_func_def.def_id())?;
1479 self.translate_item_generics(span, &def, &TransItemSourceKind::VTableMethod)?;
1480
1481 let hax::FullDefKind::AssocFn {
1482 vtable_sig: Some(vtable_sig),
1483 associated_item,
1485 ..
1486 } = assoc_func_def.kind()
1487 else {
1488 raise_error!(self, span, "MONO: expected associative methods");
1489 };
1490
1491 let AssocItemContainer::TraitContainer {
1492 trait_ref: tref, ..
1493 } = &associated_item.container
1494 else {
1495 raise_error!(
1496 self,
1497 span,
1498 "MONO: expected trait ref of associative methods"
1499 );
1500 };
1501
1502 let trait_def = self.poly_hax_def(&tref.def_id)?;
1503
1504 let signature = self.translate_fun_sig(span, &vtable_sig.value)?;
1506
1507 let method_ty = Ty::new(TyKind::FnPtr(RegionBinder {
1509 regions: self.outermost_generics().regions.clone(),
1510 skip_binder: signature.clone(),
1511 }));
1512
1513 let body: Body = self.translate_vtable_method_preshim_body(
1514 span,
1515 &signature.inputs[0],
1516 &method_ty,
1517 &trait_def,
1518 format!("method_{}", name.to_string()).as_str(),
1519 )?;
1520
1521 let mut types = vec![];
1522 let generic_args = tref.generic_args.clone();
1523 for arg in generic_args.iter().skip(1) {
1524 if let GenericArg::Type(hax_ty) = arg {
1525 types.push(self.translate_ty(span, hax_ty)?);
1526 }
1527 }
1528 if let Some(assoc_types) = assoc_types {
1529 for arg in assoc_types.iter() {
1530 if let GenericArg::Type(hax_ty) = arg {
1531 types.push(self.translate_ty(span, hax_ty)?);
1532 }
1533 }
1534 }
1535
1536 Ok(FunDecl {
1537 def_id: fun_id,
1538 item_meta,
1539 generics: GenericParams {
1541 regions: self.into_generics().regions,
1542 ..GenericParams::empty()
1543 },
1544 signature: signature,
1545 src: ItemSource::VTableMethodPreShim(*trait_id, *name, types),
1546 is_global_initializer: None,
1547 body,
1548 })
1549 }
1550
1551 fn translate_vtable_method_preshim_body(
1552 &mut self,
1553 span: Span,
1554 shim_receiver: &Ty,
1555 drop_ty: &Ty,
1556 trait_def: &hax::FullDef,
1557 name: &str,
1558 ) -> Result<Body, Error> {
1559 let mut builder = BodyBuilder::new(span, 1);
1560
1561 let ret_var = builder.new_var(Some("ret".into()), Ty::mk_unit());
1562 let dyn_self = builder.new_var(Some("dyn_self".into()), shim_receiver.clone());
1563
1564 let erased_ptr_ty = Ty::new(TyKind::RawPtr(Ty::mk_unit(), RefKind::Shared));
1565 let erased_drop_shim_ptr = builder.new_var(
1566 Some(format!("erased_{}_shim_ptr", name).into()),
1567 erased_ptr_ty.clone(),
1568 );
1569 let drop_shim_ptr =
1570 builder.new_var(Some(format!("{}_shim_ptr", name).into()), drop_ty.clone());
1571 let vtable_decl_ref = self.translate_vtable_struct_ref(span, trait_def.this())?;
1575 let vtable_decl_id = *vtable_decl_ref.id.as_adt().unwrap();
1576 let vtable_ty = TyKind::Adt(vtable_decl_ref).into_ty();
1577 let ptr_to_vtable_ty = Ty::new(TyKind::RawPtr(vtable_ty.clone(), RefKind::Shared));
1578
1579 let Some(vtable_decl) = self.t_ctx.translated.type_decls.get(vtable_decl_id) else {
1580 panic!("MONO: vtable_decl not found");
1582 };
1583 let method_field_name = name;
1585 let Some((method_field_id, _)) = vtable_decl.get_field_by_name(None, &method_field_name)
1586 else {
1587 panic!(
1588 "Could not determine method index for {} in vtable",
1589 method_field_name
1590 );
1591 };
1592
1593 let drop_field_place = dyn_self
1595 .clone()
1596 .project(ProjectionElem::PtrMetadata, ptr_to_vtable_ty)
1597 .project(ProjectionElem::Deref, vtable_ty)
1598 .project(
1599 ProjectionElem::Field(FieldProjKind::Adt(vtable_decl_id, None), method_field_id),
1600 erased_ptr_ty.clone(),
1601 );
1602
1603 let drop_rval = Rvalue::Use(Operand::Copy(drop_field_place));
1604 builder.push_statement(StatementKind::Assign(
1605 erased_drop_shim_ptr.clone(),
1606 drop_rval,
1607 ));
1608
1609 let rval_cast = Rvalue::UnaryOp(
1611 UnOp::Cast(CastKind::RawPtr(
1612 erased_drop_shim_ptr.ty().clone(),
1613 drop_shim_ptr.ty().clone(),
1614 )),
1615 Operand::Move(erased_drop_shim_ptr.clone()),
1616 );
1617
1618 builder.push_statement(StatementKind::Assign(drop_shim_ptr.clone(), rval_cast));
1619
1620 builder.call(Call {
1621 func: FnOperand::Dynamic(Operand::Move(drop_shim_ptr)),
1622 args: vec![Operand::Move(dyn_self)],
1623 dest: ret_var,
1624 });
1625
1626 Ok(Body::Unstructured(builder.build()))
1627 }
1628
1629 pub(crate) fn translate_vtable_drop_preshim(
1630 mut self,
1631 fun_id: FunDeclId,
1632 item_meta: ItemMeta,
1633 trait_def: &hax::FullDef,
1634 ) -> Result<FunDecl, Error> {
1635 let span = item_meta.span;
1636
1637 let hax::FullDefKind::Trait { dyn_self, .. } = trait_def.kind() else {
1638 raise_error!(self, span, "MONO: Unsupported trait");
1639 };
1640 let Some(dyn_self) = dyn_self else {
1641 panic!("Trying to generate a vtable for a non-dyn-compatible trait")
1642 };
1643
1644 let ref_dyn_self =
1646 TyKind::RawPtr(self.translate_ty(span, dyn_self)?, RefKind::Mut).into_ty();
1647
1648 let signature = FunSig {
1650 is_unsafe: true,
1651 inputs: vec![ref_dyn_self.clone()],
1652 output: Ty::mk_unit(),
1653 };
1654
1655 let drop_ty = Ty::new(TyKind::FnPtr(RegionBinder::empty(signature.clone())));
1656
1657 let body: Body = self.translate_vtable_drop_preshim_body(
1658 span,
1659 &ref_dyn_self,
1660 &drop_ty,
1661 trait_def,
1662 )?;
1664
1665 Ok(FunDecl {
1666 def_id: fun_id,
1667 item_meta,
1668 generics: GenericParams::empty(),
1670 signature,
1671 src: ItemSource::VTableMethodShim,
1672 is_global_initializer: None,
1673 body,
1674 })
1675 }
1676
1677 fn translate_vtable_drop_preshim_body(
1678 &mut self,
1679 span: Span,
1680 shim_receiver: &Ty,
1681 drop_ty: &Ty,
1682 trait_def: &hax::FullDef,
1683 ) -> Result<Body, Error> {
1684 let mut builder = BodyBuilder::new(span, 1);
1685
1686 let ret_var = builder.new_var(Some("ret".into()), Ty::mk_unit());
1687 let dyn_self = builder.new_var(Some("dyn_self".into()), shim_receiver.clone());
1688
1689 let erased_ptr_ty = Ty::new(TyKind::RawPtr(Ty::mk_unit(), RefKind::Shared));
1690 let erased_drop_shim_ptr =
1691 builder.new_var(Some("erased_drop_shim_ptr".into()), erased_ptr_ty.clone());
1692 let drop_shim_ptr = builder.new_var(Some("drop_shim_ptr".into()), drop_ty.clone());
1693 let vtable_decl_ref = self.translate_vtable_struct_ref(span, trait_def.this())?;
1697 let vtable_decl_id = *vtable_decl_ref.id.as_adt().unwrap();
1698 let vtable_ty = TyKind::Adt(vtable_decl_ref).into_ty();
1699 let ptr_to_vtable_ty = Ty::new(TyKind::RawPtr(vtable_ty.clone(), RefKind::Shared));
1700
1701 let Some(vtable_decl) = self.t_ctx.translated.type_decls.get(vtable_decl_id) else {
1702 panic!("MONO: vtable_decl not found");
1704 };
1705 let method_field_name = format!("drop");
1707 let Some((method_field_id, _)) = vtable_decl.get_field_by_name(None, &method_field_name)
1708 else {
1709 panic!(
1710 "Could not determine method index for {} in vtable",
1711 method_field_name
1712 );
1713 };
1714
1715 let drop_field_place = dyn_self
1717 .clone()
1718 .project(ProjectionElem::PtrMetadata, ptr_to_vtable_ty)
1719 .project(ProjectionElem::Deref, vtable_ty)
1720 .project(
1721 ProjectionElem::Field(FieldProjKind::Adt(vtable_decl_id, None), method_field_id),
1722 erased_ptr_ty.clone(),
1723 );
1724
1725 let drop_rval = Rvalue::Use(Operand::Copy(drop_field_place));
1726 builder.push_statement(StatementKind::Assign(
1727 erased_drop_shim_ptr.clone(),
1728 drop_rval,
1729 ));
1730
1731 let rval_cast = Rvalue::UnaryOp(
1733 UnOp::Cast(CastKind::RawPtr(
1734 erased_drop_shim_ptr.ty().clone(),
1735 drop_shim_ptr.ty().clone(),
1736 )),
1737 Operand::Move(erased_drop_shim_ptr.clone()),
1738 );
1739
1740 builder.push_statement(StatementKind::Assign(drop_shim_ptr.clone(), rval_cast));
1741
1742 builder.call(Call {
1743 func: FnOperand::Dynamic(Operand::Move(drop_shim_ptr)),
1744 args: vec![Operand::Move(dyn_self)],
1745 dest: ret_var,
1746 });
1747
1748 Ok(Body::Unstructured(builder.build()))
1749 }
1750}