1use charon_lib::ast::ullbc_ast_utils::BodyBuilder;
2use hax::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
19fn dynify<T: TyVisitable>(mut x: T, new_self: Option<Ty>, for_method: bool) -> T {
27 struct ReplaceSelfVisitor {
28 new_self: Option<Ty>,
29 for_method: bool,
30 }
31 impl VarsVisitor for ReplaceSelfVisitor {
32 fn visit_type_var(&mut self, v: TypeDbVar) -> Option<Ty> {
33 if let DeBruijnVar::Bound(DeBruijnId::ZERO, type_id) = v {
34 Some(if let Some(new_id) = type_id.index().checked_sub(1) {
36 TyKind::TypeVar(DeBruijnVar::Bound(DeBruijnId::ZERO, TypeVarId::new(new_id)))
37 .into_ty()
38 } else {
39 self.new_self.clone().expect(
40 "Found unexpected `Self`
41 type when constructing vtable",
42 )
43 })
44 } else {
45 None
46 }
47 }
48
49 fn visit_clause_var(&mut self, v: ClauseDbVar) -> Option<TraitRefKind> {
50 if let DeBruijnVar::Bound(DeBruijnId::ZERO, clause_id) = v {
51 if self.for_method && clause_id == TraitClauseId::ZERO {
52 Some(TraitRefKind::Dyn)
54 } else {
55 panic!("Found unexpected clause var when constructing vtable: {v}")
56 }
57 } else {
58 None
59 }
60 }
61
62 fn visit_self_clause(&mut self) -> Option<TraitRefKind> {
63 Some(TraitRefKind::Dyn)
64 }
65 }
66 x.visit_vars(&mut ReplaceSelfVisitor {
67 new_self,
68 for_method,
69 });
70 x
71}
72
73impl ItemTransCtx<'_, '_> {
75 pub fn check_at_most_one_pred_has_methods(
76 &mut self,
77 span: Span,
78 preds: &hax::GenericPredicates,
79 ) -> Result<(), Error> {
80 for (clause, _) in preds.predicates.iter().skip(1) {
82 if let hax::ClauseKind::Trait(trait_predicate) = clause.kind.hax_skip_binder_ref() {
83 let trait_def_id = &trait_predicate.trait_ref.def_id;
84 let trait_def = self.poly_hax_def(trait_def_id)?;
85 let has_methods = match trait_def.kind() {
86 hax::FullDefKind::Trait { items, .. } => items
87 .iter()
88 .any(|assoc| matches!(assoc.kind, hax::AssocKind::Fn { .. })),
89 hax::FullDefKind::TraitAlias { .. } => false,
90 _ => unreachable!(),
91 };
92 if has_methods {
93 raise_error!(
94 self,
95 span,
96 "`dyn Trait` with multiple method-bearing predicates is not supported"
97 );
98 }
99 }
100 }
101 Ok(())
102 }
103
104 pub fn translate_dyn_binder<T, U>(
105 &mut self,
106 span: Span,
107 binder: &hax::DynBinder<T>,
108 f: impl FnOnce(&mut Self, Ty, &T) -> Result<U, Error>,
109 ) -> Result<Binder<U>, Error> {
110 self.check_at_most_one_pred_has_methods(span, &binder.predicates)?;
114
115 self.binding_levels.push(BindingLevel::new(true));
117
118 let ty_id = self
120 .innermost_binder_mut()
121 .push_type_var(binder.existential_ty.index, binder.existential_ty.name);
122 let ty = TyKind::TypeVar(DeBruijnVar::new_at_zero(ty_id)).into_ty();
123 let val = f(self, ty, &binder.val)?;
124
125 self.register_predicates(&binder.predicates, PredicateOrigin::Dyn)?;
126
127 let params = self.binding_levels.pop().unwrap().params;
128 Ok(Binder {
129 params: params,
130 skip_binder: val,
131 kind: BinderKind::Dyn,
132 })
133 }
134}
135
136pub enum TrVTableField {
139 Size,
140 Align,
141 Drop,
142 Method(TraitItemName, hax::Binder<hax::TyFnSig>),
143 SuperTrait(TraitClauseId, hax::Clause),
144}
145
146pub struct VTableData {
147 pub fields: IndexVec<FieldId, TrVTableField>,
148 pub supertrait_map: IndexMap<TraitClauseId, Option<FieldId>>,
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, kw::SelfUpper);
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 prepare_vtable_fields(
235 &mut self,
236 trait_def: &hax::FullDef,
237 implied_predicates: &hax::GenericPredicates,
238 ) -> Result<VTableData, Error> {
239 let mut supertrait_map: IndexMap<TraitClauseId, _> =
240 (0..implied_predicates.predicates.len())
241 .map(|_| None)
242 .collect();
243 let mut fields = IndexVec::new();
244
245 fields.push(TrVTableField::Size);
247 fields.push(TrVTableField::Align);
248 fields.push(TrVTableField::Drop);
249
250 if let hax::FullDefKind::Trait { items, .. } = trait_def.kind() {
252 for item in items {
253 let item_def_id = &item.def_id;
254 let item_def =
256 self.hax_def(&trait_def.this().with_def_id(self.hax_state(), item_def_id))?;
257 if let hax::FullDefKind::AssocFn {
258 sig,
259 vtable_sig: Some(_),
260 ..
261 } = item_def.kind()
262 {
263 let name = self.translate_trait_item_name(&item_def_id)?;
264 fields.push(TrVTableField::Method(name, sig.clone()));
265 }
266 }
267 }
268
269 for (i, (clause, _span)) in implied_predicates.predicates.iter().enumerate() {
271 if let hax::ClauseKind::Trait(pred) = clause.kind.hax_skip_binder_ref()
273 && self.pred_is_for_self(&pred.trait_ref)
274 {
275 let trait_clause_id = TraitClauseId::from_raw(i);
276 supertrait_map[trait_clause_id] = Some(fields.next_idx());
277 fields.push(TrVTableField::SuperTrait(trait_clause_id, clause.clone()));
278 }
279 }
280
281 Ok(VTableData {
282 fields,
283 supertrait_map,
284 })
285 }
286
287 fn gen_vtable_struct_fields(
288 &mut self,
289 span: Span,
290 vtable_data: &VTableData,
291 ) -> Result<IndexVec<FieldId, Field>, Error> {
292 let mut fields = IndexVec::new();
293 let mut supertrait_counter = (0..).into_iter();
294 for field in &vtable_data.fields {
295 let (name, ty) = match field {
296 TrVTableField::Size => ("size".into(), usize_ty()),
297 TrVTableField::Align => ("align".into(), usize_ty()),
298 TrVTableField::Drop => {
299 let self_ty =
300 TyKind::TypeVar(DeBruijnVar::new_at_zero(TypeVarId::ZERO)).into_ty();
301 let self_ptr = TyKind::RawPtr(self_ty, RefKind::Mut).into_ty();
302 let drop_ty = Ty::new(TyKind::FnPtr(RegionBinder::empty(FunSig {
303 is_unsafe: true,
304 inputs: [self_ptr].into(),
305 output: Ty::mk_unit(),
306 })));
307 ("drop".into(), drop_ty)
308 }
309 TrVTableField::Method(item_name, sig) => {
310 let sig = self.translate_poly_fun_sig(span, &sig)?;
313 let ty = TyKind::FnPtr(sig).into_ty();
314 let field_name = format!("method_{}", item_name.0);
315 (field_name, ty)
316 }
317 TrVTableField::SuperTrait(_, clause) => {
318 let vtbl_struct =
319 self.translate_region_binder(span, &clause.kind, |ctx, kind| {
320 let hax::ClauseKind::Trait(pred) = kind else {
321 unreachable!()
322 };
323 let tyref = ctx
324 .translate_vtable_struct_ref(span, &pred.trait_ref)?
325 .expect("parent trait should be dyn compatible");
326 Ok(tyref)
327 })?;
328 let vtbl_struct = self.erase_region_binder(vtbl_struct);
329 let ty = Ty::new(TyKind::Ref(
330 Region::Static,
331 Ty::new(TyKind::Adt(vtbl_struct)),
332 RefKind::Shared,
333 ));
334 let name = format!("super_trait_{}", supertrait_counter.next().unwrap());
335 (name, ty)
336 }
337 };
338 fields.push(Field {
339 span,
340 attr_info: AttrInfo::dummy_public(),
341 name: Some(name),
342 ty,
343 });
344 }
345 Ok(fields)
346 }
347
348 pub(crate) fn check_no_monomorphize(&self, span: Span) -> Result<(), Error> {
350 if self.monomorphize() {
351 raise_error!(
352 self,
353 span,
354 "`dyn Trait` is not yet supported with `--monomorphize`"
355 )
356 }
357 Ok(())
358 }
359
360 pub(crate) fn translate_vtable_struct(
375 mut self,
376 type_id: TypeDeclId,
377 item_meta: ItemMeta,
378 trait_def: &hax::FullDef,
379 ) -> Result<TypeDecl, Error> {
380 let span = item_meta.span;
381 if !self.trait_is_dyn_compatible(trait_def.def_id())? {
382 raise_error!(
383 self,
384 span,
385 "Trying to compute the vtable type \
386 for a non-dyn-compatible trait"
387 );
388 }
389 self.check_no_monomorphize(span)?;
390
391 let (hax::FullDefKind::Trait {
392 dyn_self,
393 implied_predicates,
394 ..
395 }
396 | hax::FullDefKind::TraitAlias {
397 dyn_self,
398 implied_predicates,
399 ..
400 }) = trait_def.kind()
401 else {
402 panic!()
403 };
404 let Some(dyn_self) = dyn_self else {
405 panic!("Trying to generate a vtable for a non-dyn-compatible trait")
406 };
407
408 let mut dyn_self = {
410 let dyn_self = self.translate_ty(span, dyn_self)?;
411 let TyKind::DynTrait(mut dyn_pred) = dyn_self.kind().clone() else {
412 panic!("incorrect `dyn_self`")
413 };
414
415 for (i, ty_constraint) in dyn_pred
418 .binder
419 .params
420 .trait_type_constraints
421 .iter_mut()
422 .enumerate()
423 {
424 let name = format!("Ty{i}");
425 let new_ty = self
426 .the_only_binder_mut()
427 .params
428 .types
429 .push_with(|index| TypeParam { index, name });
430 let new_ty =
433 TyKind::TypeVar(DeBruijnVar::bound(DeBruijnId::new(2), new_ty)).into_ty();
434 ty_constraint.skip_binder.ty = new_ty;
435 }
436 TyKind::DynTrait(dyn_pred).into_ty()
437 };
438
439 let mut field_map = IndexVec::new();
440 let mut supertrait_map: IndexMap<TraitClauseId, _> =
441 (0..implied_predicates.predicates.len())
442 .map(|_| None)
443 .collect();
444 let (mut kind, layout) = if item_meta.opacity.with_private_contents().is_opaque() {
445 (TypeDeclKind::Opaque, None)
446 } else {
447 let vtable_data = self.prepare_vtable_fields(trait_def, implied_predicates)?;
450 let fields = self.gen_vtable_struct_fields(span, &vtable_data)?;
451 let kind = TypeDeclKind::Struct(fields);
452 let layout = self.generate_naive_layout(span, &kind)?;
453 supertrait_map = vtable_data.supertrait_map;
454 field_map = vtable_data.fields.map_ref(|tr_field| match *tr_field {
455 TrVTableField::Size => VTableField::Size,
456 TrVTableField::Align => VTableField::Align,
457 TrVTableField::Drop => VTableField::Drop,
458 TrVTableField::Method(name, ..) => VTableField::Method(name),
459 TrVTableField::SuperTrait(clause_id, ..) => VTableField::SuperTrait(clause_id),
460 });
461 (kind, Some(layout))
462 };
463
464 let mut generics = self.into_generics();
467 {
468 dyn_self = dynify(dyn_self, None, false);
469 generics = dynify(generics, Some(dyn_self.clone()), false);
470 kind = dynify(kind, Some(dyn_self.clone()), true);
471 generics.types.remove_and_shift_ids(TypeVarId::ZERO);
472 generics.types.iter_mut().for_each(|ty| {
473 ty.index -= 1;
474 });
475 }
476
477 let dyn_predicate = dyn_self
478 .kind()
479 .as_dyn_trait()
480 .expect("incorrect `dyn_self`");
481 Ok(TypeDecl {
482 def_id: type_id,
483 item_meta: item_meta,
484 generics: generics,
485 src: ItemSource::VTableTy {
486 dyn_predicate: dyn_predicate.clone(),
487 field_map,
488 supertrait_map,
489 },
490 kind,
491 layout,
492 ptr_metadata: PtrMetadata::None,
494 repr: None,
495 })
496 }
497}
498
499impl ItemTransCtx<'_, '_> {
501 pub fn translate_vtable_instance_ref(
502 &mut self,
503 span: Span,
504 trait_ref: &hax::TraitRef,
505 impl_ref: &hax::ItemRef,
506 ) -> Result<Option<GlobalDeclRef>, Error> {
507 self.translate_vtable_instance_ref_maybe_enqueue(true, span, trait_ref, impl_ref)
508 }
509
510 pub fn translate_vtable_instance_ref_no_enqueue(
511 &mut self,
512 span: Span,
513 trait_ref: &hax::TraitRef,
514 impl_ref: &hax::ItemRef,
515 ) -> Result<Option<GlobalDeclRef>, Error> {
516 self.translate_vtable_instance_ref_maybe_enqueue(false, span, trait_ref, impl_ref)
517 }
518
519 pub fn translate_vtable_instance_ref_maybe_enqueue(
520 &mut self,
521 enqueue: bool,
522 span: Span,
523 trait_ref: &hax::TraitRef,
524 impl_ref: &hax::ItemRef,
525 ) -> Result<Option<GlobalDeclRef>, Error> {
526 if !self.trait_is_dyn_compatible(&trait_ref.def_id)? {
527 return Ok(None);
528 }
529 let vtable_ref: GlobalDeclRef = self.translate_item_maybe_enqueue(
534 span,
535 enqueue,
536 impl_ref,
537 TransItemSourceKind::VTableInstance(TraitImplSource::Normal),
538 )?;
539 Ok(Some(vtable_ref))
540 }
541
542 fn get_vtable_instance_info<'a>(
544 &mut self,
545 span: Span,
546 impl_def: &'a hax::FullDef,
547 impl_kind: &TraitImplSource,
548 ) -> Result<(TraitImplRef, TypeDeclRef), Error> {
549 let implemented_trait = match impl_def.kind() {
550 hax::FullDefKind::TraitImpl { trait_pred, .. } => &trait_pred.trait_ref,
551 _ => unreachable!(),
552 };
553 let vtable_struct_ref = self
554 .translate_vtable_struct_ref(span, implemented_trait)?
555 .expect("trait should be dyn-compatible");
556 let impl_ref = self.translate_item(
557 span,
558 impl_def.this(),
559 TransItemSourceKind::TraitImpl(*impl_kind),
560 )?;
561 Ok((impl_ref, vtable_struct_ref))
562 }
563
564 pub(crate) fn translate_vtable_instance(
579 mut self,
580 global_id: GlobalDeclId,
581 item_meta: ItemMeta,
582 impl_def: &hax::FullDef,
583 impl_kind: &TraitImplSource,
584 ) -> Result<GlobalDecl, Error> {
585 let span = item_meta.span;
586 self.check_no_monomorphize(span)?;
587
588 let (impl_ref, vtable_struct_ref) =
589 self.get_vtable_instance_info(span, impl_def, impl_kind)?;
590 let init = self.register_item(
592 span,
593 impl_def.this(),
594 TransItemSourceKind::VTableInstanceInitializer(*impl_kind),
595 );
596
597 Ok(GlobalDecl {
598 def_id: global_id,
599 item_meta,
600 generics: self.into_generics(),
601 src: ItemSource::VTableInstance { impl_ref },
602 global_kind: GlobalKind::Static,
604 ty: Ty::new(TyKind::Adt(vtable_struct_ref)),
605 init,
606 })
607 }
608
609 fn add_method_to_vtable_value(
610 &mut self,
611 span: Span,
612 impl_def: &hax::FullDef,
613 item: &hax::ImplAssocItem,
614 mut mk_field: impl FnMut(ConstantExprKind),
615 ) -> Result<(), Error> {
616 match self.poly_hax_def(&item.decl_def_id)?.kind() {
618 hax::FullDefKind::AssocFn {
619 vtable_sig: Some(_),
620 ..
621 } => {}
622 _ => return Ok(()),
623 }
624
625 let const_kind = match &item.value {
626 hax::ImplAssocItemValue::Provided {
627 def_id: item_def_id,
628 ..
629 } => {
630 let item_ref = impl_def.this().with_def_id(self.hax_state(), item_def_id);
633 let shim_ref =
634 self.translate_fn_ptr(span, &item_ref, TransItemSourceKind::VTableMethod)?;
635 ConstantExprKind::FnDef(shim_ref)
636 }
637 hax::ImplAssocItemValue::DefaultedFn { .. } => ConstantExprKind::Opaque(
638 "shim for default methods \
639 aren't yet supported"
640 .to_string(),
641 ),
642 _ => return Ok(()),
643 };
644
645 mk_field(const_kind);
646
647 Ok(())
648 }
649
650 fn add_supertraits_to_vtable_value(
651 &mut self,
652 span: Span,
653 trait_def: &hax::FullDef,
654 impl_def: &hax::FullDef,
655 mut mk_field: impl FnMut(ConstantExprKind),
656 ) -> Result<(), Error> {
657 let hax::FullDefKind::TraitImpl {
658 implied_impl_exprs, ..
659 } = impl_def.kind()
660 else {
661 unreachable!()
662 };
663 let hax::FullDefKind::Trait {
664 implied_predicates, ..
665 } = trait_def.kind()
666 else {
667 unreachable!()
668 };
669 for ((clause, _), impl_expr) in implied_predicates.predicates.iter().zip(implied_impl_exprs)
670 {
671 let hax::ClauseKind::Trait(pred) = clause.kind.hax_skip_binder_ref() else {
672 continue;
673 };
674 if !self.pred_is_for_self(&pred.trait_ref) {
676 continue;
677 }
678
679 let bound_tyref =
680 self.translate_region_binder(span, &impl_expr.r#trait, |ctx, tref| {
681 let tyref = ctx
682 .translate_vtable_struct_ref(span, tref)?
683 .expect("parent trait should be dyn compatible");
684 Ok(tyref)
685 })?;
686 let vtable_def_ref = self.erase_region_binder(bound_tyref);
687 let fn_ptr_ty = TyKind::Adt(vtable_def_ref).into_ty();
688 let kind = match &impl_expr.r#impl {
689 hax::ImplExprAtom::Concrete(impl_item) => {
690 let bound_gref: RegionBinder<GlobalDeclRef> =
691 self.translate_region_binder(span, &impl_expr.r#trait, |ctx, tref| {
692 let gref = ctx
693 .translate_vtable_instance_ref(span, tref, impl_item)?
694 .expect("parent trait should be dyn compatible");
695 Ok(gref)
696 })?;
697 let vtable_instance_ref = self.erase_region_binder(bound_gref);
698 let global = Box::new(ConstantExpr {
699 kind: ConstantExprKind::Global(vtable_instance_ref),
700 ty: fn_ptr_ty,
701 });
702 ConstantExprKind::Ref(global)
703 }
704 _ => ConstantExprKind::Opaque("missing supertrait vtable".into()),
706 };
707 mk_field(kind);
708 }
709 Ok(())
710 }
711
712 fn gen_vtable_instance_init_body(
720 &mut self,
721 span: Span,
722 impl_def: &hax::FullDef,
723 vtable_struct_ref: TypeDeclRef,
724 ) -> Result<Body, Error> {
725 let hax::FullDefKind::TraitImpl {
726 trait_pred, items, ..
727 } = impl_def.kind()
728 else {
729 unreachable!()
730 };
731 let trait_def = self.hax_def(&trait_pred.trait_ref)?;
732 let implemented_trait = self.translate_trait_decl_ref(span, &trait_pred.trait_ref)?;
733 let self_ty = &implemented_trait.generics.types[0];
735
736 let mut builder = BodyBuilder::new(span, 0);
737 let ret_ty = Ty::new(TyKind::Adt(vtable_struct_ref.clone()));
738 let ret_place = builder.new_var(Some("ret".into()), ret_ty.clone());
739
740 let field_tys = {
743 let vtable_decl_id = vtable_struct_ref.id.as_adt().unwrap().clone();
744 let ItemRef::Type(vtable_def) = self.t_ctx.get_or_translate(vtable_decl_id.into())?
745 else {
746 unreachable!()
747 };
748 let TypeDeclKind::Struct(fields) = &vtable_def.kind else {
749 unreachable!()
750 };
751 fields
752 .iter()
753 .map(|f| &f.ty)
754 .cloned()
755 .map(|ty| ty.substitute(&vtable_struct_ref.generics))
756 .collect_vec()
757 };
758
759 let mut aggregate_fields = vec![];
760 let mut field_ty_iter = field_tys.into_iter();
762
763 let size_ty = field_ty_iter.next().unwrap();
764 let size_local = builder.new_var(Some("size".to_string()), size_ty);
765 builder.push_statement(StatementKind::Assign(
766 size_local.clone(),
767 Rvalue::NullaryOp(NullOp::SizeOf, self_ty.clone()),
768 ));
769 aggregate_fields.push(Operand::Move(size_local));
770
771 let align_ty = field_ty_iter.next().unwrap();
772 let align_local = builder.new_var(Some("align".to_string()), align_ty);
773 builder.push_statement(StatementKind::Assign(
774 align_local.clone(),
775 Rvalue::NullaryOp(NullOp::AlignOf, self_ty.clone()),
776 ));
777 aggregate_fields.push(Operand::Move(align_local));
778
779 let mut mk_field = |kind| {
781 let ty = field_ty_iter.next().unwrap();
782 aggregate_fields.push(Operand::Const(Box::new(ConstantExpr { kind, ty })));
783 };
784
785 let drop_shim =
786 self.translate_item(span, impl_def.this(), TransItemSourceKind::VTableDropShim)?;
787
788 mk_field(ConstantExprKind::FnDef(drop_shim));
789
790 for item in items {
791 self.add_method_to_vtable_value(span, impl_def, item, &mut mk_field)?;
792 }
793
794 self.add_supertraits_to_vtable_value(span, &trait_def, impl_def, &mut mk_field)?;
795
796 if field_ty_iter.next().is_some() {
797 raise_error!(
798 self,
799 span,
800 "Missed some fields in vtable value construction"
801 )
802 }
803
804 builder.push_statement(StatementKind::Assign(
806 ret_place,
807 Rvalue::Aggregate(
808 AggregateKind::Adt(vtable_struct_ref.clone(), None, None),
809 aggregate_fields,
810 ),
811 ));
812
813 Ok(Body::Unstructured(builder.build()))
814 }
815
816 pub(crate) fn translate_vtable_instance_init(
817 mut self,
818 init_func_id: FunDeclId,
819 item_meta: ItemMeta,
820 impl_def: &hax::FullDef,
821 impl_kind: &TraitImplSource,
822 ) -> Result<FunDecl, Error> {
823 let span = item_meta.span;
824 self.check_no_monomorphize(span)?;
825
826 let (impl_ref, vtable_struct_ref) =
827 self.get_vtable_instance_info(span, impl_def, impl_kind)?;
828 let init_for = self.register_item(
829 span,
830 impl_def.this(),
831 TransItemSourceKind::VTableInstance(*impl_kind),
832 );
833
834 let sig = FunSig {
836 is_unsafe: false,
837 inputs: vec![],
838 output: Ty::new(TyKind::Adt(vtable_struct_ref.clone())),
839 };
840
841 let body = match impl_kind {
842 _ if item_meta.opacity.with_private_contents().is_opaque() => Body::Opaque,
843 TraitImplSource::Normal => {
844 self.gen_vtable_instance_init_body(span, impl_def, vtable_struct_ref)?
845 }
846 _ => {
847 raise_error!(
848 self,
849 span,
850 "Don't know how to generate a vtable for a virtual impl {impl_kind:?}"
851 );
852 }
853 };
854
855 Ok(FunDecl {
856 def_id: init_func_id,
857 item_meta: item_meta,
858 generics: self.into_generics(),
859 signature: sig,
860 src: ItemSource::VTableInstance { impl_ref },
861 is_global_initializer: Some(init_for),
862 body,
863 })
864 }
865
866 fn translate_vtable_shim_body(
884 &mut self,
885 span: Span,
886 target_receiver: &Ty,
887 shim_signature: &FunSig,
888 impl_func_def: &hax::FullDef,
889 ) -> Result<Body, Error> {
890 let mut builder = BodyBuilder::new(span, shim_signature.inputs.len());
891
892 let ret_place = builder.new_var(None, shim_signature.output.clone());
893 let mut method_args = shim_signature
894 .inputs
895 .iter()
896 .map(|ty| builder.new_var(None, ty.clone()))
897 .collect_vec();
898 let target_self = builder.new_var(None, target_receiver.clone());
899
900 let shim_self = mem::replace(&mut method_args[0], target_self.clone());
902
903 let rval = Rvalue::UnaryOp(
907 UnOp::Cast(CastKind::Concretize(
908 shim_self.ty().clone(),
909 target_self.ty().clone(),
910 )),
911 Operand::Move(shim_self.clone()),
912 );
913 builder.push_statement(StatementKind::Assign(target_self.clone(), rval));
914
915 let fun_id = self.register_item(span, &impl_func_def.this(), TransItemSourceKind::Fun);
916 let generics = self.outermost_binder().params.identity_args();
917 builder.call(Call {
918 func: FnOperand::Regular(FnPtr::new(FnPtrKind::Fun(fun_id), generics)),
919 args: method_args
920 .into_iter()
921 .map(|arg| Operand::Move(arg))
922 .collect(),
923 dest: ret_place,
924 });
925
926 Ok(Body::Unstructured(builder.build()))
927 }
928
929 fn translate_vtable_drop_shim_body(
941 &mut self,
942 span: Span,
943 shim_receiver: &Ty,
944 target_receiver: &Ty,
945 trait_pred: &TraitPredicate,
946 ) -> Result<Body, Error> {
947 let mut builder = BodyBuilder::new(span, 1);
948
949 builder.new_var(Some("ret".into()), Ty::mk_unit());
950 let dyn_self = builder.new_var(Some("dyn_self".into()), shim_receiver.clone());
951 let target_self = builder.new_var(Some("target_self".into()), target_receiver.clone());
952
953 let rval = Rvalue::UnaryOp(
955 UnOp::Cast(CastKind::Concretize(
956 dyn_self.ty().clone(),
957 target_self.ty().clone(),
958 )),
959 Operand::Move(dyn_self.clone()),
960 );
961 builder.push_statement(StatementKind::Assign(target_self.clone(), rval));
962
963 let destruct_trait = self.tcx.lang_items().destruct_trait().unwrap();
968 let impl_expr: hax::ImplExpr = {
969 let s = self.hax_state_with_id();
970 let rustc_trait_args = trait_pred.trait_ref.rustc_args(s);
971 let generics = self.tcx.mk_args(&rustc_trait_args[..1]); let tref =
973 rustc_middle::ty::TraitRef::new_from_args(self.tcx, destruct_trait, generics);
974 hax::solve_trait(s, rustc_middle::ty::Binder::dummy(tref))
975 };
976 let tref = self.translate_trait_impl_expr(span, &impl_expr)?;
977
978 let drop_arg = target_self.clone().deref();
980 builder.insert_drop(drop_arg, tref);
981
982 Ok(Body::Unstructured(builder.build()))
983 }
984
985 pub(crate) fn translate_vtable_drop_shim(
986 mut self,
987 fun_id: FunDeclId,
988 item_meta: ItemMeta,
989 impl_def: &hax::FullDef,
990 ) -> Result<FunDecl, Error> {
991 let span = item_meta.span;
992
993 let hax::FullDefKind::TraitImpl {
994 dyn_self: Some(dyn_self),
995 trait_pred,
996 ..
997 } = impl_def.kind()
998 else {
999 raise_error!(
1000 self,
1001 span,
1002 "Trying to generate a vtable drop shim for a non-trait impl"
1003 );
1004 };
1005
1006 let ref_dyn_self =
1008 TyKind::RawPtr(self.translate_ty(span, dyn_self)?, RefKind::Mut).into_ty();
1009 let ref_target_self = {
1011 let impl_trait = self.translate_trait_ref(span, &trait_pred.trait_ref)?;
1012 TyKind::RawPtr(impl_trait.generics.types[0].clone(), RefKind::Mut).into_ty()
1013 };
1014
1015 let signature = FunSig {
1017 is_unsafe: true,
1018 inputs: vec![ref_dyn_self.clone()],
1019 output: Ty::mk_unit(),
1020 };
1021
1022 let body: Body = self.translate_vtable_drop_shim_body(
1023 span,
1024 &ref_dyn_self,
1025 &ref_target_self,
1026 trait_pred,
1027 )?;
1028
1029 Ok(FunDecl {
1030 def_id: fun_id,
1031 item_meta,
1032 generics: self.into_generics(),
1033 signature,
1034 src: ItemSource::VTableMethodShim,
1035 is_global_initializer: None,
1036 body,
1037 })
1038 }
1039
1040 pub(crate) fn translate_vtable_shim(
1041 mut self,
1042 fun_id: FunDeclId,
1043 item_meta: ItemMeta,
1044 impl_func_def: &hax::FullDef,
1045 ) -> Result<FunDecl, Error> {
1046 let span = item_meta.span;
1047 self.check_no_monomorphize(span)?;
1048
1049 let hax::FullDefKind::AssocFn {
1050 vtable_sig: Some(vtable_sig),
1051 sig: target_signature,
1052 ..
1053 } = impl_func_def.kind()
1054 else {
1055 raise_error!(
1056 self,
1057 span,
1058 "Trying to generate a vtable shim for a non-vtable-safe method"
1059 );
1060 };
1061
1062 let signature = self.translate_fun_sig(span, &vtable_sig.value)?;
1064 let target_receiver = self.translate_ty(span, &target_signature.value.inputs[0])?;
1066
1067 trace!(
1068 "[VtableShim] Obtained dyn signature with receiver type: {}",
1069 signature.inputs[0].with_ctx(&self.into_fmt())
1070 );
1071
1072 let body = if item_meta.opacity.with_private_contents().is_opaque() {
1073 Body::Opaque
1074 } else {
1075 self.translate_vtable_shim_body(span, &target_receiver, &signature, impl_func_def)?
1076 };
1077
1078 Ok(FunDecl {
1079 def_id: fun_id,
1080 item_meta,
1081 generics: self.into_generics(),
1082 signature,
1083 src: ItemSource::VTableMethodShim,
1084 is_global_initializer: None,
1085 body,
1086 })
1087 }
1088}