1use charon_lib::ast::ullbc_ast_utils::BodyBuilder;
2use hax::TraitPredicate;
3use itertools::Itertools;
4use std::mem;
5
6use super::{
7 translate_crate::TransItemSourceKind, translate_ctx::*, translate_generics::BindingLevel,
8};
9use charon_lib::formatter::IntoFormatter;
10use charon_lib::ids::Vector;
11use charon_lib::pretty::FmtWithCtx;
12use charon_lib::ullbc_ast::*;
13
14fn dummy_public_attr_info() -> AttrInfo {
15 AttrInfo {
16 public: true,
17 ..Default::default()
18 }
19}
20
21fn usize_ty() -> Ty {
22 Ty::new(TyKind::Literal(LiteralTy::UInt(UIntTy::Usize)))
23}
24
25fn dynify<T: TyVisitable>(mut x: T, new_self: Option<Ty>, for_method: bool) -> T {
33 struct ReplaceSelfVisitor {
34 new_self: Option<Ty>,
35 for_method: bool,
36 }
37 impl VarsVisitor for ReplaceSelfVisitor {
38 fn visit_type_var(&mut self, v: TypeDbVar) -> Option<Ty> {
39 if let DeBruijnVar::Bound(DeBruijnId::ZERO, type_id) = v {
40 Some(if let Some(new_id) = type_id.index().checked_sub(1) {
42 TyKind::TypeVar(DeBruijnVar::Bound(DeBruijnId::ZERO, TypeVarId::new(new_id)))
43 .into_ty()
44 } else {
45 self.new_self.clone().expect(
46 "Found unexpected `Self`
47 type when constructing vtable",
48 )
49 })
50 } else {
51 None
52 }
53 }
54
55 fn visit_clause_var(&mut self, v: ClauseDbVar) -> Option<TraitRefKind> {
56 if let DeBruijnVar::Bound(DeBruijnId::ZERO, clause_id) = v {
57 if self.for_method && clause_id == TraitClauseId::ZERO {
58 Some(TraitRefKind::Dyn)
60 } else {
61 panic!("Found unexpected clause var when constructing vtable: {v}")
62 }
63 } else {
64 None
65 }
66 }
67
68 fn visit_self_clause(&mut self) -> Option<TraitRefKind> {
69 Some(TraitRefKind::Dyn)
70 }
71 }
72 x.visit_vars(&mut ReplaceSelfVisitor {
73 new_self,
74 for_method,
75 });
76 x
77}
78
79impl ItemTransCtx<'_, '_> {
81 pub fn check_at_most_one_pred_has_methods(
82 &mut self,
83 span: Span,
84 preds: &hax::GenericPredicates,
85 ) -> Result<(), Error> {
86 for (clause, _) in preds.predicates.iter().skip(1) {
88 if let hax::ClauseKind::Trait(trait_predicate) = clause.kind.hax_skip_binder_ref() {
89 let trait_def_id = &trait_predicate.trait_ref.def_id;
90 let trait_def = self.poly_hax_def(trait_def_id)?;
91 let has_methods = match trait_def.kind() {
92 hax::FullDefKind::Trait { items, .. } => items
93 .iter()
94 .any(|assoc| matches!(assoc.kind, hax::AssocKind::Fn { .. })),
95 hax::FullDefKind::TraitAlias { .. } => false,
96 _ => unreachable!(),
97 };
98 if has_methods {
99 raise_error!(
100 self,
101 span,
102 "`dyn Trait` with multiple method-bearing predicates is not supported"
103 );
104 }
105 }
106 }
107 Ok(())
108 }
109
110 pub fn translate_existential_predicates(
111 &mut self,
112 span: Span,
113 self_ty: &hax::ParamTy,
114 preds: &hax::GenericPredicates,
115 region: &hax::Region,
116 ) -> Result<DynPredicate, Error> {
117 self.check_at_most_one_pred_has_methods(span, preds)?;
121
122 let region = self.translate_region(span, region)?;
124 let region = region.move_under_binder();
125
126 self.binding_levels.push(BindingLevel::new(true));
128
129 let ty_id = self
131 .innermost_binder_mut()
132 .push_type_var(self_ty.index, self_ty.name.clone());
133 let ty = TyKind::TypeVar(DeBruijnVar::new_at_zero(ty_id)).into_ty();
134
135 self.innermost_binder_mut()
136 .params
137 .types_outlive
138 .push(RegionBinder::empty(OutlivesPred(ty.clone(), region)));
139 self.register_predicates(preds, PredicateOrigin::Dyn)?;
140
141 let params = self.binding_levels.pop().unwrap().params;
142 let binder = Binder {
143 params: params,
144 skip_binder: ty,
145 kind: BinderKind::Dyn,
146 };
147 Ok(DynPredicate { binder })
148 }
149}
150
151impl ItemTransCtx<'_, '_> {
153 pub fn trait_is_dyn_compatible(&mut self, def_id: &hax::DefId) -> Result<bool, Error> {
157 let def = self.poly_hax_def(def_id)?;
158 Ok(match def.kind() {
159 hax::FullDefKind::Trait { dyn_self, .. }
160 | hax::FullDefKind::TraitAlias { dyn_self, .. } => dyn_self.is_some(),
161 _ => false,
162 })
163 }
164
165 fn pred_is_for_self(&self, tref: &hax::TraitRef) -> bool {
167 let first_ty = tref
168 .generic_args
169 .iter()
170 .filter_map(|arg| match arg {
171 hax::GenericArg::Type(ty) => Some(ty),
172 _ => None,
173 })
174 .next();
175 match first_ty {
176 None => false,
177 Some(first_ty) => match first_ty.kind() {
178 hax::TyKind::Param(param_ty) if param_ty.index == 0 => {
179 assert_eq!(param_ty.name, "Self");
180 true
181 }
182 _ => false,
183 },
184 }
185 }
186
187 pub fn translate_vtable_struct_ref(
188 &mut self,
189 span: Span,
190 tref: &hax::TraitRef,
191 ) -> Result<Option<TypeDeclRef>, Error> {
192 self.translate_vtable_struct_ref_maybe_enqueue(true, span, tref)
193 }
194
195 pub fn translate_vtable_struct_ref_no_enqueue(
196 &mut self,
197 span: Span,
198 tref: &hax::TraitRef,
199 ) -> Result<Option<TypeDeclRef>, Error> {
200 self.translate_vtable_struct_ref_maybe_enqueue(false, span, tref)
201 }
202
203 pub fn translate_vtable_struct_ref_maybe_enqueue(
205 &mut self,
206 enqueue: bool,
207 span: Span,
208 tref: &hax::TraitRef,
209 ) -> Result<Option<TypeDeclRef>, Error> {
210 if !self.trait_is_dyn_compatible(&tref.def_id)? {
211 return Ok(None);
212 }
213 let mut vtable_ref: TypeDeclRef =
216 self.translate_item_maybe_enqueue(span, enqueue, tref, TransItemSourceKind::VTable)?;
217 vtable_ref
219 .generics
220 .types
221 .remove_and_shift_ids(TypeVarId::ZERO);
222
223 let assoc_tys: Vec<_> = tref
225 .trait_associated_types(self.hax_state_with_id())
226 .iter()
227 .map(|ty| self.translate_ty(span, ty))
228 .try_collect()?;
229 vtable_ref.generics.types.extend(assoc_tys);
230
231 Ok(Some(vtable_ref))
232 }
233
234 fn add_method_to_vtable_def(
236 &mut self,
237 span: Span,
238 trait_def: &hax::FullDef,
239 mut mk_field: impl FnMut(String, Ty),
240 item: &hax::AssocItem,
241 ) -> Result<(), Error> {
242 let item_def_id = &item.def_id;
243 let item_def = self.hax_def(
244 &trait_def
245 .this()
246 .with_def_id(&self.t_ctx.hax_state, item_def_id),
247 )?;
248 let hax::FullDefKind::AssocFn {
249 sig,
250 vtable_sig: Some(_),
251 ..
252 } = item_def.kind()
253 else {
254 return Ok(());
255 };
256
257 let item_name = self.t_ctx.translate_trait_item_name(item_def_id)?;
258 let sig = self.translate_fun_sig(span, sig)?;
261 let ty = TyKind::FnPtr(sig).into_ty();
262
263 mk_field(format!("method_{}", item_name.0), ty);
264 Ok(())
265 }
266
267 fn add_supertraits_to_vtable_def(
269 &mut self,
270 span: Span,
271 mut mk_field: impl FnMut(String, Ty),
272 implied_predicates: &hax::GenericPredicates,
273 ) -> Result<(), Error> {
274 let mut counter = (0..).into_iter();
275 for (clause, _span) in &implied_predicates.predicates {
276 if let hax::ClauseKind::Trait(pred) = clause.kind.hax_skip_binder_ref() {
277 if !self.pred_is_for_self(&pred.trait_ref) {
279 continue;
280 }
281 let vtbl_struct = self
282 .translate_region_binder(span, &clause.kind, |ctx, _| {
283 ctx.translate_vtable_struct_ref(span, &pred.trait_ref)
284 })?
285 .erase()
286 .expect("parent trait should be dyn compatible");
287 let ty = Ty::new(TyKind::Ref(
288 Region::Static,
289 Ty::new(TyKind::Adt(vtbl_struct)),
290 RefKind::Shared,
291 ));
292 mk_field(format!("super_trait_{}", counter.next().unwrap()), ty);
293 }
294 }
295 Ok(())
296 }
297
298 fn gen_vtable_struct_fields(
299 &mut self,
300 span: Span,
301 trait_def: &hax::FullDef,
302 implied_predicates: &hax::GenericPredicates,
303 ) -> Result<Vector<FieldId, Field>, Error> {
304 let mut fields = Vector::new();
305 let mut mk_field = |name, ty| {
306 fields.push(Field {
307 span,
308 attr_info: dummy_public_attr_info(),
309 name: Some(name),
310 ty,
311 });
312 };
313
314 mk_field("size".into(), usize_ty());
317 mk_field("align".into(), usize_ty());
319 mk_field("drop".into(), {
321 let self_ty = TyKind::TypeVar(DeBruijnVar::new_at_zero(TypeVarId::ZERO)).into_ty();
322 let self_ptr = TyKind::RawPtr(self_ty, RefKind::Mut).into_ty();
323 Ty::new(TyKind::FnPtr(RegionBinder::empty((
324 [self_ptr].into(),
325 Ty::mk_unit(),
326 ))))
327 });
328
329 if let hax::FullDefKind::Trait { items, .. } = trait_def.kind() {
331 for item in items {
332 self.add_method_to_vtable_def(span, trait_def, &mut mk_field, item)?;
333 }
334 }
335
336 self.add_supertraits_to_vtable_def(span, &mut mk_field, implied_predicates)?;
338
339 Ok(fields)
340 }
341
342 pub(crate) fn check_no_monomorphize(&self, span: Span) -> Result<(), Error> {
344 if self.monomorphize() {
345 raise_error!(
346 self,
347 span,
348 "`dyn Trait` is not yet supported with `--monomorphize`"
349 )
350 }
351 Ok(())
352 }
353
354 pub(crate) fn translate_vtable_struct(
369 mut self,
370 type_id: TypeDeclId,
371 item_meta: ItemMeta,
372 trait_def: &hax::FullDef,
373 ) -> Result<TypeDecl, Error> {
374 let span = item_meta.span;
375 if !self.trait_is_dyn_compatible(trait_def.def_id())? {
376 raise_error!(
377 self,
378 span,
379 "Trying to compute the vtable type \
380 for a non-dyn-compatible trait"
381 );
382 }
383 self.check_no_monomorphize(span)?;
384
385 self.translate_def_generics(span, trait_def)?;
386
387 let (hax::FullDefKind::Trait {
388 dyn_self,
389 implied_predicates,
390 ..
391 }
392 | hax::FullDefKind::TraitAlias {
393 dyn_self,
394 implied_predicates,
395 ..
396 }) = trait_def.kind()
397 else {
398 panic!()
399 };
400 let Some(dyn_self) = dyn_self else {
401 panic!("Trying to generate a vtable for a non-dyn-compatible trait")
402 };
403
404 let mut dyn_self = {
406 let dyn_self = self.translate_ty(span, dyn_self)?;
407 let TyKind::DynTrait(mut dyn_pred) = dyn_self.kind().clone() else {
408 panic!("incorrect `dyn_self`")
409 };
410
411 for (i, ty_constraint) in dyn_pred
414 .binder
415 .params
416 .trait_type_constraints
417 .iter_mut()
418 .enumerate()
419 {
420 let name = format!("Ty{i}");
421 let new_ty = self
422 .the_only_binder_mut()
423 .params
424 .types
425 .push_with(|index| TypeParam { index, name });
426 let new_ty =
429 TyKind::TypeVar(DeBruijnVar::bound(DeBruijnId::new(2), new_ty)).into_ty();
430 ty_constraint.skip_binder.ty = new_ty;
431 }
432 TyKind::DynTrait(dyn_pred).into_ty()
433 };
434
435 let (mut kind, layout) = if item_meta.opacity.with_private_contents().is_opaque() {
436 (TypeDeclKind::Opaque, None)
437 } else {
438 let fields = self.gen_vtable_struct_fields(span, trait_def, implied_predicates)?;
441 let kind = TypeDeclKind::Struct(fields);
442 let layout = self.generate_naive_layout(span, &kind)?;
443 (kind, Some(layout))
444 };
445
446 let mut generics = self.into_generics();
449 {
450 dyn_self = dynify(dyn_self, None, false);
451 generics = dynify(generics, Some(dyn_self.clone()), false);
452 kind = dynify(kind, Some(dyn_self.clone()), true);
453 generics.types.remove_and_shift_ids(TypeVarId::ZERO);
454 generics.types.iter_mut().for_each(|ty| {
455 ty.index -= 1;
456 });
457 }
458
459 let dyn_predicate = dyn_self
460 .kind()
461 .as_dyn_trait()
462 .expect("incorrect `dyn_self`");
463 Ok(TypeDecl {
464 def_id: type_id,
465 item_meta: item_meta,
466 generics: generics,
467 src: ItemSource::VTableTy {
468 dyn_predicate: dyn_predicate.clone(),
469 },
470 kind,
471 layout,
472 ptr_metadata: PtrMetadata::None,
474 repr: None,
475 })
476 }
477}
478
479impl ItemTransCtx<'_, '_> {
481 pub fn translate_vtable_instance_ref(
482 &mut self,
483 span: Span,
484 trait_ref: &hax::TraitRef,
485 impl_ref: &hax::ItemRef,
486 ) -> Result<Option<GlobalDeclRef>, Error> {
487 self.translate_vtable_instance_ref_maybe_enqueue(true, span, trait_ref, impl_ref)
488 }
489
490 pub fn translate_vtable_instance_ref_no_enqueue(
491 &mut self,
492 span: Span,
493 trait_ref: &hax::TraitRef,
494 impl_ref: &hax::ItemRef,
495 ) -> Result<Option<GlobalDeclRef>, Error> {
496 self.translate_vtable_instance_ref_maybe_enqueue(false, span, trait_ref, impl_ref)
497 }
498
499 pub fn translate_vtable_instance_ref_maybe_enqueue(
500 &mut self,
501 enqueue: bool,
502 span: Span,
503 trait_ref: &hax::TraitRef,
504 impl_ref: &hax::ItemRef,
505 ) -> Result<Option<GlobalDeclRef>, Error> {
506 if !self.trait_is_dyn_compatible(&trait_ref.def_id)? {
507 return Ok(None);
508 }
509 let vtable_ref: GlobalDeclRef = self.translate_item_maybe_enqueue(
514 span,
515 enqueue,
516 impl_ref,
517 TransItemSourceKind::VTableInstance(TraitImplSource::Normal),
518 )?;
519 Ok(Some(vtable_ref))
520 }
521
522 fn get_vtable_instance_info<'a>(
524 &mut self,
525 span: Span,
526 impl_def: &'a hax::FullDef,
527 impl_kind: &TraitImplSource,
528 ) -> Result<(TraitImplRef, TypeDeclRef), Error> {
529 let implemented_trait = match impl_def.kind() {
530 hax::FullDefKind::TraitImpl { trait_pred, .. } => &trait_pred.trait_ref,
531 _ => unreachable!(),
532 };
533 let vtable_struct_ref = self
534 .translate_vtable_struct_ref(span, implemented_trait)?
535 .expect("trait should be dyn-compatible");
536 let impl_ref = self.translate_item(
537 span,
538 impl_def.this(),
539 TransItemSourceKind::TraitImpl(*impl_kind),
540 )?;
541 Ok((impl_ref, vtable_struct_ref))
542 }
543
544 pub(crate) fn translate_vtable_instance(
559 mut self,
560 global_id: GlobalDeclId,
561 item_meta: ItemMeta,
562 impl_def: &hax::FullDef,
563 impl_kind: &TraitImplSource,
564 ) -> Result<GlobalDecl, Error> {
565 let span = item_meta.span;
566 self.translate_def_generics(span, impl_def)?;
567 self.check_no_monomorphize(span)?;
568
569 let (impl_ref, vtable_struct_ref) =
570 self.get_vtable_instance_info(span, impl_def, impl_kind)?;
571 let init = self.register_item(
573 span,
574 impl_def.this(),
575 TransItemSourceKind::VTableInstanceInitializer(*impl_kind),
576 );
577
578 Ok(GlobalDecl {
579 def_id: global_id,
580 item_meta,
581 generics: self.into_generics(),
582 src: ItemSource::VTableInstance { impl_ref },
583 global_kind: GlobalKind::Static,
585 ty: Ty::new(TyKind::Adt(vtable_struct_ref)),
586 init,
587 })
588 }
589
590 fn add_method_to_vtable_value(
591 &mut self,
592 span: Span,
593 impl_def: &hax::FullDef,
594 item: &hax::ImplAssocItem,
595 mut mk_field: impl FnMut(ConstantExprKind),
596 ) -> Result<(), Error> {
597 match self.poly_hax_def(&item.decl_def_id)?.kind() {
599 hax::FullDefKind::AssocFn {
600 vtable_sig: Some(_),
601 ..
602 } => {}
603 _ => return Ok(()),
604 }
605
606 let const_kind = match &item.value {
607 hax::ImplAssocItemValue::Provided {
608 def_id: item_def_id,
609 ..
610 } => {
611 let item_ref = impl_def.this().with_def_id(self.hax_state(), item_def_id);
614 let shim_ref = self
615 .translate_fn_ptr(span, &item_ref, TransItemSourceKind::VTableMethod)?
616 .erase();
617 ConstantExprKind::FnPtr(shim_ref)
618 }
619 hax::ImplAssocItemValue::DefaultedFn { .. } => ConstantExprKind::Opaque(
620 "shim for default methods \
621 aren't yet supported"
622 .to_string(),
623 ),
624 _ => return Ok(()),
625 };
626
627 mk_field(const_kind);
628
629 Ok(())
630 }
631
632 fn add_supertraits_to_vtable_value(
633 &mut self,
634 span: Span,
635 trait_def: &hax::FullDef,
636 impl_def: &hax::FullDef,
637 mut mk_field: impl FnMut(ConstantExprKind),
638 ) -> Result<(), Error> {
639 let hax::FullDefKind::TraitImpl {
640 implied_impl_exprs, ..
641 } = impl_def.kind()
642 else {
643 unreachable!()
644 };
645 let hax::FullDefKind::Trait {
646 implied_predicates, ..
647 } = trait_def.kind()
648 else {
649 unreachable!()
650 };
651 for ((clause, _), impl_expr) in implied_predicates.predicates.iter().zip(implied_impl_exprs)
652 {
653 let hax::ClauseKind::Trait(pred) = clause.kind.hax_skip_binder_ref() else {
654 continue;
655 };
656 if !self.pred_is_for_self(&pred.trait_ref) {
658 continue;
659 }
660
661 let vtable_def_ref = self
662 .translate_region_binder(span, &impl_expr.r#trait, |ctx, tref| {
663 ctx.translate_vtable_struct_ref(span, tref)
664 })?
665 .erase()
666 .expect("parent trait should be dyn compatible");
667 let fn_ptr_ty = TyKind::Adt(vtable_def_ref).into_ty();
668 let kind = match &impl_expr.r#impl {
669 hax::ImplExprAtom::Concrete(impl_item) => {
670 let vtable_instance_ref = self
671 .translate_region_binder(span, &impl_expr.r#trait, |ctx, tref| {
672 ctx.translate_vtable_instance_ref(span, tref, impl_item)
673 })?
674 .erase()
675 .expect("parent trait should be dyn compatible");
676 let global = Box::new(ConstantExpr {
677 kind: ConstantExprKind::Global(vtable_instance_ref),
678 ty: fn_ptr_ty,
679 });
680 ConstantExprKind::Ref(global)
681 }
682 _ => ConstantExprKind::Opaque("missing supertrait vtable".into()),
684 };
685 mk_field(kind);
686 }
687 Ok(())
688 }
689
690 fn gen_vtable_instance_init_body(
698 &mut self,
699 span: Span,
700 impl_def: &hax::FullDef,
701 vtable_struct_ref: TypeDeclRef,
702 ) -> Result<Body, Error> {
703 let hax::FullDefKind::TraitImpl {
704 trait_pred, items, ..
705 } = impl_def.kind()
706 else {
707 unreachable!()
708 };
709 let trait_def = self.hax_def(&trait_pred.trait_ref)?;
710 let implemented_trait = self.translate_trait_decl_ref(span, &trait_pred.trait_ref)?;
711 let self_ty = &implemented_trait.generics.types[0];
713
714 let mut builder = BodyBuilder::new(span, 0);
715 let ret_ty = Ty::new(TyKind::Adt(vtable_struct_ref.clone()));
716 let ret_place = builder.new_var(Some("ret".into()), ret_ty.clone());
717
718 let field_tys = {
721 let vtable_decl_id = vtable_struct_ref.id.as_adt().unwrap().clone();
722 let ItemRef::Type(vtable_def) = self.t_ctx.get_or_translate(vtable_decl_id.into())?
723 else {
724 unreachable!()
725 };
726 let TypeDeclKind::Struct(fields) = &vtable_def.kind else {
727 unreachable!()
728 };
729 fields
730 .iter()
731 .map(|f| &f.ty)
732 .cloned()
733 .map(|ty| ty.substitute(&vtable_struct_ref.generics))
734 .collect_vec()
735 };
736
737 let mut aggregate_fields = vec![];
738 let mut field_ty_iter = field_tys.into_iter();
740
741 let size_ty = field_ty_iter.next().unwrap();
742 let size_local = builder.new_var(Some("size".to_string()), size_ty);
743 builder.push_statement(StatementKind::Assign(
744 size_local.clone(),
745 Rvalue::NullaryOp(NullOp::SizeOf, self_ty.clone()),
746 ));
747 aggregate_fields.push(Operand::Move(size_local));
748
749 let align_ty = field_ty_iter.next().unwrap();
750 let align_local = builder.new_var(Some("align".to_string()), align_ty);
751 builder.push_statement(StatementKind::Assign(
752 align_local.clone(),
753 Rvalue::NullaryOp(NullOp::AlignOf, self_ty.clone()),
754 ));
755 aggregate_fields.push(Operand::Move(align_local));
756
757 let mut mk_field = |kind| {
759 let ty = field_ty_iter.next().unwrap();
760 aggregate_fields.push(Operand::Const(Box::new(ConstantExpr { kind, ty })));
761 };
762
763 let drop_shim =
764 self.translate_item(span, impl_def.this(), TransItemSourceKind::VTableDropShim)?;
765
766 mk_field(ConstantExprKind::FnPtr(drop_shim));
767
768 for item in items {
769 self.add_method_to_vtable_value(span, impl_def, item, &mut mk_field)?;
770 }
771
772 self.add_supertraits_to_vtable_value(span, &trait_def, impl_def, &mut mk_field)?;
773
774 if field_ty_iter.next().is_some() {
775 raise_error!(
776 self,
777 span,
778 "Missed some fields in vtable value construction"
779 )
780 }
781
782 builder.push_statement(StatementKind::Assign(
784 ret_place,
785 Rvalue::Aggregate(
786 AggregateKind::Adt(vtable_struct_ref.clone(), None, None),
787 aggregate_fields,
788 ),
789 ));
790
791 Ok(Body::Unstructured(builder.build()))
792 }
793
794 pub(crate) fn translate_vtable_instance_init(
795 mut self,
796 init_func_id: FunDeclId,
797 item_meta: ItemMeta,
798 impl_def: &hax::FullDef,
799 impl_kind: &TraitImplSource,
800 ) -> Result<FunDecl, Error> {
801 let span = item_meta.span;
802 self.translate_def_generics(span, impl_def)?;
803 self.check_no_monomorphize(span)?;
804
805 let (impl_ref, vtable_struct_ref) =
806 self.get_vtable_instance_info(span, impl_def, impl_kind)?;
807 let init_for = self.register_item(
808 span,
809 impl_def.this(),
810 TransItemSourceKind::VTableInstance(*impl_kind),
811 );
812
813 let sig = FunSig {
815 is_unsafe: false,
816 generics: self.the_only_binder().params.clone(),
817 inputs: vec![],
818 output: Ty::new(TyKind::Adt(vtable_struct_ref.clone())),
819 };
820
821 let body = match impl_kind {
822 _ if item_meta.opacity.with_private_contents().is_opaque() => Body::Opaque,
823 TraitImplSource::Normal => {
824 self.gen_vtable_instance_init_body(span, impl_def, vtable_struct_ref)?
825 }
826 _ => {
827 raise_error!(
828 self,
829 span,
830 "Don't know how to generate a vtable for a virtual impl {impl_kind:?}"
831 );
832 }
833 };
834
835 Ok(FunDecl {
836 def_id: init_func_id,
837 item_meta: item_meta,
838 signature: sig,
839 src: ItemSource::VTableInstance { impl_ref },
840 is_global_initializer: Some(init_for),
841 body,
842 })
843 }
844
845 fn translate_vtable_shim_body(
863 &mut self,
864 span: Span,
865 target_receiver: &Ty,
866 shim_signature: &FunSig,
867 impl_func_def: &hax::FullDef,
868 ) -> Result<Body, Error> {
869 let mut builder = BodyBuilder::new(span, shim_signature.inputs.len());
870
871 let ret_place = builder.new_var(None, shim_signature.output.clone());
872 let mut method_args = shim_signature
873 .inputs
874 .iter()
875 .map(|ty| builder.new_var(None, ty.clone()))
876 .collect_vec();
877 let target_self = builder.new_var(None, target_receiver.clone());
878
879 let shim_self = mem::replace(&mut method_args[0], target_self.clone());
881
882 let rval = Rvalue::UnaryOp(
886 UnOp::Cast(CastKind::Concretize(
887 shim_self.ty().clone(),
888 target_self.ty().clone(),
889 )),
890 Operand::Move(shim_self.clone()),
891 );
892 builder.push_statement(StatementKind::Assign(target_self.clone(), rval));
893
894 let fun_id = self.register_item(span, &impl_func_def.this(), TransItemSourceKind::Fun);
895 let generics = self.outermost_binder().params.identity_args();
896 builder.call(Call {
897 func: FnOperand::Regular(FnPtr::new(FnPtrKind::Fun(fun_id), generics)),
898 args: method_args
899 .into_iter()
900 .map(|arg| Operand::Move(arg))
901 .collect(),
902 dest: ret_place,
903 });
904
905 Ok(Body::Unstructured(builder.build()))
906 }
907
908 fn translate_vtable_drop_shim_body(
920 &mut self,
921 span: Span,
922 shim_receiver: &Ty,
923 target_receiver: &Ty,
924 trait_pred: &TraitPredicate,
925 ) -> Result<Body, Error> {
926 let mut builder = BodyBuilder::new(span, 1);
927
928 builder.new_var(Some("ret".into()), Ty::mk_unit());
929 let dyn_self = builder.new_var(Some("dyn_self".into()), shim_receiver.clone());
930 let target_self = builder.new_var(Some("target_self".into()), target_receiver.clone());
931
932 let rval = Rvalue::UnaryOp(
934 UnOp::Cast(CastKind::Concretize(
935 dyn_self.ty().clone(),
936 target_self.ty().clone(),
937 )),
938 Operand::Move(dyn_self.clone()),
939 );
940 builder.push_statement(StatementKind::Assign(target_self.clone(), rval));
941
942 let destruct_trait = self.tcx.lang_items().destruct_trait().unwrap();
947 let impl_expr: hax::ImplExpr = {
948 let s = self.hax_state_with_id();
949 let rustc_trait_args = trait_pred.trait_ref.rustc_args(s);
950 let generics = self.tcx.mk_args(&rustc_trait_args[..1]); let tref =
952 rustc_middle::ty::TraitRef::new_from_args(self.tcx, destruct_trait, generics);
953 hax::solve_trait(s, rustc_middle::ty::Binder::dummy(tref))
954 };
955 let tref = self.translate_trait_impl_expr(span, &impl_expr)?;
956
957 let drop_arg = target_self.clone().deref();
959 builder.insert_drop(drop_arg, tref);
960
961 Ok(Body::Unstructured(builder.build()))
962 }
963
964 pub(crate) fn translate_vtable_drop_shim(
965 mut self,
966 fun_id: FunDeclId,
967 item_meta: ItemMeta,
968 impl_def: &hax::FullDef,
969 ) -> Result<FunDecl, Error> {
970 let span = item_meta.span;
971 self.translate_def_generics(span, impl_def)?;
972
973 let hax::FullDefKind::TraitImpl {
974 dyn_self: Some(dyn_self),
975 trait_pred,
976 ..
977 } = impl_def.kind()
978 else {
979 raise_error!(
980 self,
981 span,
982 "Trying to generate a vtable drop shim for a non-trait impl"
983 );
984 };
985
986 let ref_dyn_self =
988 TyKind::RawPtr(self.translate_ty(span, dyn_self)?, RefKind::Mut).into_ty();
989 let ref_target_self = {
991 let impl_trait = self.translate_trait_ref(span, &trait_pred.trait_ref)?;
992 TyKind::RawPtr(impl_trait.generics.types[0].clone(), RefKind::Mut).into_ty()
993 };
994
995 let signature = FunSig {
997 is_unsafe: false,
998 generics: self.the_only_binder().params.clone(),
999 inputs: vec![ref_dyn_self.clone()],
1000 output: Ty::mk_unit(),
1001 };
1002
1003 let body: Body = self.translate_vtable_drop_shim_body(
1004 span,
1005 &ref_dyn_self,
1006 &ref_target_self,
1007 trait_pred,
1008 )?;
1009
1010 Ok(FunDecl {
1011 def_id: fun_id,
1012 item_meta,
1013 signature,
1014 src: ItemSource::VTableMethodShim,
1015 is_global_initializer: None,
1016 body,
1017 })
1018 }
1019
1020 pub(crate) fn translate_vtable_shim(
1021 mut self,
1022 fun_id: FunDeclId,
1023 item_meta: ItemMeta,
1024 impl_func_def: &hax::FullDef,
1025 ) -> Result<FunDecl, Error> {
1026 let span = item_meta.span;
1027 self.check_no_monomorphize(span)?;
1028
1029 let hax::FullDefKind::AssocFn {
1030 vtable_sig: Some(vtable_sig),
1031 sig: target_signature,
1032 ..
1033 } = impl_func_def.kind()
1034 else {
1035 raise_error!(
1036 self,
1037 span,
1038 "Trying to generate a vtable shim for a non-vtable-safe method"
1039 );
1040 };
1041
1042 let shim_func_def = {
1046 let mut def = impl_func_def.clone();
1047 let hax::FullDefKind::AssocFn { sig, .. } = &mut def.kind else {
1048 unreachable!()
1049 };
1050 *sig = vtable_sig.clone();
1051 def
1052 };
1053
1054 let signature = self.translate_function_signature(&shim_func_def, &item_meta)?;
1056
1057 let target_receiver = self.translate_ty(span, &target_signature.value.inputs[0])?;
1058
1059 trace!(
1060 "[VtableShim] Obtained dyn signature with receiver type: {}",
1061 signature.inputs[0].with_ctx(&self.into_fmt())
1062 );
1063
1064 let body = if item_meta.opacity.with_private_contents().is_opaque() {
1065 Body::Opaque
1066 } else {
1067 self.translate_vtable_shim_body(span, &target_receiver, &signature, impl_func_def)?
1068 };
1069
1070 Ok(FunDecl {
1071 def_id: fun_id,
1072 item_meta,
1073 signature,
1074 src: ItemSource::VTableMethodShim,
1075 is_global_initializer: None,
1076 body,
1077 })
1078 }
1079}