1use itertools::Itertools;
2use rustc_span::kw;
3use std::mem;
4
5use super::{
6 translate_closures::{callable_virtual_impl, recognize_fn_trait_impl_proof},
7 translate_crate::TransItemSourceKind,
8 translate_ctx::*,
9 translate_generics::BindingLevel,
10};
11use crate::hax;
12use crate::hax::TraitPredicate;
13use charon_lib::formatter::IntoFormatter;
14use charon_lib::pretty::FmtWithCtx;
15use charon_lib::ullbc_ast::*;
16
17enum VtableMethodValue {
21 Const(ConstantExprKind),
22 Cast((String, Ty, FnPtr)),
24}
25
26fn dynify<T: TyVisitable>(mut x: T, new_self: Option<Ty>, for_method: bool) -> T {
34 struct ReplaceSelfVisitor {
35 new_self: Option<Ty>,
36 for_method: bool,
37 }
38 impl VarsVisitor for ReplaceSelfVisitor {
39 fn visit_type_var(&mut self, v: TypeDbVar) -> Option<Ty> {
40 if let DeBruijnVar::Bound(DeBruijnId::ZERO, type_id) = v {
41 Some(if let Some(new_id) = type_id.index().checked_sub(1) {
43 TyKind::TypeVar(DeBruijnVar::Bound(DeBruijnId::ZERO, TypeVarId::new(new_id)))
44 .into_ty()
45 } else {
46 self.new_self.clone().expect(
47 "Found unexpected `Self`
48 type when constructing vtable",
49 )
50 })
51 } else {
52 None
53 }
54 }
55
56 fn visit_clause_var(&mut self, v: ClauseDbVar) -> Option<TraitRefKind> {
57 if let DeBruijnVar::Bound(DeBruijnId::ZERO, clause_id) = v {
58 if self.for_method && clause_id == TraitClauseId::ZERO {
59 Some(TraitRefKind::Dyn)
61 } else {
62 panic!("Found unexpected clause var when constructing vtable: {v}")
63 }
64 } else {
65 None
66 }
67 }
68
69 fn visit_self_clause(&mut self) -> Option<TraitRefKind> {
70 Some(TraitRefKind::Dyn)
71 }
72 }
73 x.visit_vars(&mut ReplaceSelfVisitor {
74 new_self,
75 for_method,
76 });
77 x
78}
79
80impl<'tcx> ItemTransCtx<'tcx, '_> {
82 pub fn check_at_most_one_pred_has_methods(
83 &mut self,
84 span: Span,
85 preds: &hax::GenericPredicates,
86 ) -> Result<(), Error> {
87 for pred in preds.predicates.iter().skip(1) {
89 if let hax::ClauseKind::Trait(trait_predicate) = pred.clause.kind.hax_skip_binder_ref()
90 {
91 let trait_def_id = &trait_predicate.trait_ref.def_id;
92 let trait_def = self.poly_hax_def(trait_def_id)?;
93 let has_methods = match trait_def.kind() {
94 hax::FullDefKind::Trait { items, .. } => items
95 .iter()
96 .any(|assoc| matches!(assoc.kind, hax::AssocKind::Fn { .. })),
97 hax::FullDefKind::TraitAlias { .. } => false,
98 _ => unreachable!(),
99 };
100 if has_methods {
101 raise_error!(
102 self,
103 span,
104 "`dyn Trait` with multiple method-bearing predicates is not supported"
105 );
106 }
107 }
108 }
109 Ok(())
110 }
111
112 pub fn translate_dyn_binder<T, U>(
113 &mut self,
114 span: Span,
115 binder: &hax::DynBinder<T>,
116 f: impl FnOnce(&mut Self, Ty, &T) -> Result<U, Error>,
117 ) -> Result<Binder<U>, Error> {
118 self.check_at_most_one_pred_has_methods(span, &binder.predicates)?;
122
123 self.binding_levels.push(BindingLevel::new(None));
125
126 let ty_id = self.innermost_binder_mut().push_type_var(
128 binder.existential_ty.index,
129 binder.existential_ty.name,
130 Variance::Unknown,
131 );
132 let ty = TyKind::TypeVar(DeBruijnVar::new_at_zero(ty_id)).into_ty();
133
134 self.register_predicates(&binder.predicates, PredicateOrigin::Dyn)?;
135
136 let val = f(self, ty, &binder.val)?;
137
138 if self.monomorphize() {
143 struct ShiftDynClauseVars;
144 impl VarsVisitor for ShiftDynClauseVars {
145 fn visit_clause_var(&mut self, v: ClauseDbVar) -> Option<TraitRefKind> {
146 if let DeBruijnVar::Bound(DeBruijnId::ZERO, clause_id) = v
147 && let Some(new_id) = clause_id.index().checked_sub(1)
148 {
149 return Some(TraitRefKind::Clause(DeBruijnVar::Bound(
150 DeBruijnId::ZERO,
151 TraitClauseId::new(new_id),
152 )));
153 }
154 None
155 }
156 }
157
158 self.innermost_generics_mut()
159 .trait_type_constraints
160 .iter_mut()
161 .for_each(|pred| pred.visit_vars(&mut ShiftDynClauseVars));
162 }
163
164 let params = self.binding_levels.pop().unwrap().params;
165 Ok(Binder {
166 params,
167 skip_binder: val,
168 kind: BinderKind::Dyn,
169 })
170 }
171}
172
173#[derive(Debug)]
176pub enum TrVTableField {
177 Size,
178 Align,
179 Drop,
180 Method(TraitMethodId, hax::Binder<hax::TyFnSig>),
181 SuperTrait(TraitClauseId, hax::Clause),
182}
183
184pub struct VTableData {
185 pub fields: IndexVec<FieldId, TrVTableField>,
186 pub supertrait_map: IndexVec<TraitClauseId, Option<FieldId>>,
187}
188
189struct VTableInstanceData<'a> {
191 implemented_trait_ref: &'a hax::TraitRef,
192 implied_trait_proofs: &'a [hax::TraitProof],
193 methods: VTableMethodSource<'a>,
194}
195
196enum VTableMethodSource<'a> {
198 ImplMethods(IndexVec<TraitMethodId, &'a hax::ImplAssocItem>),
199 FnTraitShim(&'a hax::ItemRef, TransImplSource, &'a hax::PolyFnSig),
200}
201
202impl<'tcx> ItemTransCtx<'tcx, '_> {
204 pub fn trait_is_dyn_compatible(&mut self, def_id: &hax::DefId) -> Result<bool, Error> {
208 let def = self.poly_hax_def(def_id)?;
209 Ok(match def.kind() {
210 hax::FullDefKind::Trait { dyn_self, .. }
211 | hax::FullDefKind::TraitAlias { dyn_self, .. } => dyn_self.is_some(),
212 _ => false,
213 })
214 }
215
216 fn pred_is_for_self(&self, tref: &hax::TraitRef) -> bool {
218 let first_ty = tref
219 .generic_args
220 .iter()
221 .filter_map(|arg| match arg {
222 hax::GenericArg::Type(ty) => Some(ty),
223 _ => None,
224 })
225 .next();
226 match first_ty {
227 None => false,
228 Some(first_ty) => match first_ty.kind() {
229 hax::TyKind::Param(param_ty) if param_ty.index == 0 => {
230 assert_eq!(param_ty.name, kw::SelfUpper);
231 true
232 }
233 _ => false,
234 },
235 }
236 }
237
238 pub fn translate_vtable_struct_ref(
239 &mut self,
240 span: Span,
241 tref: &hax::TraitRef,
242 ) -> Result<TypeDeclRef, Error> {
243 Ok(self
244 .translate_vtable_struct_ref_maybe_enqueue(true, span, tref)?
245 .expect("trait should be dyn-compatible"))
246 }
247
248 pub fn translate_vtable_struct_ref_no_enqueue(
249 &mut self,
250 span: Span,
251 tref: &hax::TraitRef,
252 ) -> Result<Option<TypeDeclRef>, Error> {
253 self.translate_vtable_struct_ref_maybe_enqueue(false, span, tref)
254 }
255
256 pub fn translate_vtable_struct_ref_maybe_enqueue(
258 &mut self,
259 enqueue: bool,
260 span: Span,
261 tref: &hax::TraitRef,
262 ) -> Result<Option<TypeDeclRef>, Error> {
263 if !self.trait_is_dyn_compatible(&tref.def_id)? {
264 return Ok(None);
265 }
266
267 let enqueue = enqueue || self.monomorphize();
269
270 let mut vtable_ref = self.translate_type_decl_ref_maybe_enqueue(
273 span,
274 tref,
275 TransItemSourceKind::VTable,
276 enqueue,
277 )?;
278 vtable_ref
280 .generics
281 .types
282 .remove_and_shift_ids(TypeVarId::ZERO);
283
284 if !self.monomorphize() {
285 let assoc_tys: Vec<_> = tref
287 .trait_associated_types(self.hax_state_with_id())
288 .iter()
289 .map(|ty| self.translate_ty(span, ty))
290 .try_collect()?;
291 vtable_ref.generics.types.extend(assoc_tys);
292 }
293
294 Ok(Some(vtable_ref))
295 }
296
297 fn prepare_vtable_fields(
298 &mut self,
299 poly_trait_def: &hax::FullDef<'tcx>,
300 trait_id: TraitDeclId,
301 implied_predicates: &hax::GenericPredicates,
302 ) -> Result<VTableData, Error> {
303 let mut supertrait_map: IndexVec<TraitClauseId, _> =
304 (0..implied_predicates.predicates.len())
305 .map(|_| None)
306 .collect();
307 let mut fields = IndexVec::new();
308
309 fields.push(TrVTableField::Size);
311 fields.push(TrVTableField::Align);
312 fields.push(TrVTableField::Drop);
313
314 if let hax::FullDefKind::Trait { items, .. } = poly_trait_def.kind() {
316 for item in items {
317 let item_def_id = &item.def_id;
318 let poly_item_def = self.poly_hax_def(item_def_id)?;
320 if let hax::FullDefKind::AssocFn {
321 vtable_sig: Some(sig),
322 ..
323 } = poly_item_def.kind()
324 {
325 let id = self.translate_trait_method_id_no_enqueue(trait_id, item_def_id)?;
326 fields.push(TrVTableField::Method(id, sig.clone()));
327 }
328 }
329 }
330
331 for (i, pred) in implied_predicates.iter_trait_clauses().enumerate() {
333 let trait_clause_id = TraitClauseId::from_usize(i); let clause = &pred.clause;
335 let hax::ClauseKind::Trait(pred) = clause.kind.hax_skip_binder_ref() else {
336 unreachable!()
337 };
338 if self.pred_is_for_self(&pred.trait_ref) {
340 if !self.trait_is_dyn_compatible(&pred.trait_ref.def_id)? {
341 self.assert_is_destruct(&pred.trait_ref);
343 continue;
344 }
345 supertrait_map[trait_clause_id] = Some(fields.next_idx());
346 fields.push(TrVTableField::SuperTrait(trait_clause_id, clause.clone()));
347 }
348 }
349
350 Ok(VTableData {
351 fields,
352 supertrait_map,
353 })
354 }
355
356 fn assert_is_destruct(&self, tref: &hax::TraitRef) {
362 assert!(
363 tref.def_id
364 .as_real_def_id()
365 .is_some_and(|id| self.tcx.is_lang_item(id, rustc_attr_ir::LangItem::Destruct)),
366 "unexpected non-dyn compatible supertrait: {:?}",
367 tref.def_id
368 );
369 }
370
371 fn gen_vtable_struct_fields(
372 &mut self,
373 span: Span,
374 self_trait_ref: &TraitRef,
375 vtable_data: &VTableData,
376 ) -> Result<IndexVec<FieldId, Field>, Error> {
377 let mut fields = IndexVec::new();
378 let mut supertrait_counter = 0..;
379 for field in &vtable_data.fields {
380 let (name, ty) = match field {
381 TrVTableField::Size => ("size".into(), Ty::mk_usize()),
382 TrVTableField::Align => ("align".into(), Ty::mk_usize()),
383 TrVTableField::Drop => {
384 if self.monomorphize() {
386 let erased_ptr_ty = Ty::new(TyKind::RawPtr(Ty::mk_unit(), RefKind::Shared));
387 ("drop".into(), erased_ptr_ty)
388 } else {
389 let self_ty =
390 TyKind::TypeVar(DeBruijnVar::new_at_zero(TypeVarId::ZERO)).into_ty();
391 let drop_ty = Ty::new(TyKind::FnPtr(self.drop_glue_fn_ptr_sig(self_ty)));
392 ("drop".into(), drop_ty)
393 }
394 }
395 TrVTableField::Method(item_id, sig) => {
396 let item_name = self
397 .translated
398 .assoc_item_name(self_trait_ref.trait_id(), *item_id);
399 let field_name = format!("method_{}", item_name.0);
400 if self.monomorphize() {
402 let erased_ptr_ty = Ty::new(TyKind::RawPtr(Ty::mk_unit(), RefKind::Shared));
403 (field_name, erased_ptr_ty)
404 } else {
405 let sig = self.translate_poly_fun_sig(span, sig)?;
406 let ty = TyKind::FnPtr(sig).into_ty();
407 (field_name, ty)
408 }
409 }
410 TrVTableField::SuperTrait(_, clause) => {
411 let vtbl_struct =
412 self.translate_region_binder(span, &clause.kind, |ctx, kind| {
413 let hax::ClauseKind::Trait(pred) = kind else {
414 unreachable!()
415 };
416 ctx.translate_vtable_struct_ref(span, &pred.trait_ref)
417 })?;
418 let vtbl_struct = self.erase_region_binder(vtbl_struct);
419 let ty = Ty::new(TyKind::Ref(
420 Region::Static,
421 Ty::new(TyKind::Adt(vtbl_struct)),
422 RefKind::Shared,
423 ));
424 let name = format!("super_trait_{}", supertrait_counter.next().unwrap());
425 (name, ty)
426 }
427 };
428 fields.push(Field {
429 span,
430 attr_info: AttrInfo::dummy_public(),
431 name,
432 is_positional: false,
433 ty,
434 });
435 }
436 Ok(fields)
437 }
438
439 pub(crate) fn translate_vtable_struct(
455 mut self,
456 type_id: TypeDeclId,
457 item_meta: ItemMeta,
458 trait_def: &hax::FullDef<'tcx>,
459 ) -> Result<TypeDecl, Error> {
460 let mono = self.monomorphize();
461 let span = item_meta.span;
462 if !self.trait_is_dyn_compatible(trait_def.def_id())? {
463 raise_error!(
464 self,
465 span,
466 "Trying to compute the vtable type \
467 for a non-dyn-compatible trait"
468 );
469 }
470
471 let (hax::FullDefKind::Trait {
472 self_predicate,
473 dyn_self,
474 implied_predicates,
475 ..
476 }
477 | hax::FullDefKind::TraitAlias {
478 self_predicate,
479 dyn_self,
480 implied_predicates,
481 ..
482 }) = trait_def.kind()
483 else {
484 panic!()
485 };
486 let Some(dyn_self) = dyn_self else {
487 panic!("Trying to generate a vtable for a non-dyn-compatible trait")
488 };
489
490 let self_trait_ref = TraitRef::new(
491 TraitRefKind::SelfId,
492 RegionBinder::empty(self.translate_trait_predicate(span, self_predicate)?),
493 );
494 let trait_id = self_trait_ref.trait_id();
495
496 let mut field_map = IndexVec::new();
497 let mut supertrait_map: IndexVec<TraitClauseId, _> =
498 (0..implied_predicates.predicates.len())
499 .map(|_| None)
500 .collect();
501 let (mut kind, layout) = if item_meta.opacity.with_private_contents().is_opaque() {
502 (TypeDeclKind::Opaque, SeqHashMap::default())
503 } else {
504 let vtable_data =
507 self.prepare_vtable_fields(trait_def, trait_id, implied_predicates)?;
508 let fields = self.gen_vtable_struct_fields(span, &self_trait_ref, &vtable_data)?;
509
510 let kind = TypeDeclKind::Struct(fields);
511 let l = self.generate_naive_layout(span, &kind)?;
512 supertrait_map = vtable_data.supertrait_map;
513 field_map = vtable_data.fields.map_ref(|tr_field| match *tr_field {
514 TrVTableField::Size => VTableField::Size,
515 TrVTableField::Align => VTableField::Align,
516 TrVTableField::Drop => VTableField::Drop,
517 TrVTableField::Method(id, ..) => VTableField::Method(id),
518 TrVTableField::SuperTrait(clause_id, ..) => VTableField::SuperTrait(clause_id),
519 });
520 let layout = [(self.get_target_triple(), l)].into();
521 (kind, layout)
522 };
523
524 let mut generics = Default::default();
525
526 let dyn_predicate = if mono {
527 DynPredicate {
528 binder: Binder {
529 params: GenericParams::empty(),
530 skip_binder: TyKind::Error(
531 "mono vtable dyn predicate is intentionally erased".to_string(),
532 )
533 .into_ty(),
534 kind: BinderKind::Dyn,
535 },
536 }
537 } else {
538 let mut dyn_self = {
541 let dyn_self = self.translate_ty(span, dyn_self)?;
542 let TyKind::DynTrait(mut dyn_pred) = dyn_self.kind().clone() else {
543 panic!("incorrect `dyn_self`")
544 };
545
546 for (i, ty_constraint) in dyn_pred
549 .binder
550 .params
551 .trait_type_constraints
552 .iter_mut()
553 .enumerate()
554 {
555 let name = format!("Ty{i}");
556 let new_ty = self
557 .the_only_binder_mut()
558 .params
559 .types
560 .push_with(|index| TypeParam::new(index, name, Variance::Invariant));
561 let new_ty =
564 TyKind::TypeVar(DeBruijnVar::bound(DeBruijnId::new(2), new_ty)).into_ty();
565 ty_constraint.skip_binder.ty = new_ty;
566 }
567 TyKind::DynTrait(dyn_pred).into_ty()
568 };
569
570 generics = self.into_generics();
573 {
574 dyn_self = dynify(dyn_self, None, false);
575 generics = dynify(generics, Some(dyn_self.clone()), false);
576 kind = dynify(kind, Some(dyn_self.clone()), true);
577 generics.types.remove_and_shift_ids(TypeVarId::ZERO);
578 generics.types.iter_mut().for_each(|ty| {
579 ty.index -= 1;
580 });
581 }
582
583 dyn_self
584 .kind()
585 .as_dyn_trait()
586 .expect("incorrect `dyn_self`")
587 .clone()
588 };
589 Ok(TypeDecl {
590 def_id: type_id,
591 item_meta,
592 generics,
593 src: TypeSource::VTable {
594 dyn_predicate,
595 field_map,
596 supertrait_map,
597 },
598 kind,
599 layout,
600 ptr_metadata: PtrMetadata::None,
602 })
603 }
604}
605
606impl<'tcx> ItemTransCtx<'tcx, '_> {
608 pub fn translate_vtable_instance_const(
610 &mut self,
611 span: Span,
612 trait_proof: &hax::TraitProof,
613 ) -> Result<ConstantExpr, Error> {
614 let tref = trait_proof.pred.hax_skip_binder_ref();
615 if !self.trait_is_dyn_compatible(&tref.def_id)? {
616 raise_error!(
617 self,
618 span,
619 "Trait {:?} should be dyn-compatible",
620 tref.def_id
621 );
622 }
623
624 let vtbl_ty = {
625 let vtbl_ty = self.translate_region_binder(span, &trait_proof.pred, |ctx, tref| {
626 ctx.translate_vtable_struct_ref(span, tref)
627 })?;
628 let vtbl_ty = self.erase_region_binder(vtbl_ty);
629 TyKind::Adt(vtbl_ty).into_ty()
630 };
631 let ty = TyKind::Ref(Region::Static, vtbl_ty.clone(), RefKind::Shared).into_ty();
632
633 let fn_trait_impl = recognize_fn_trait_impl_proof(trait_proof);
634 let kind = match &trait_proof.kind {
635 _ if let Some((self_ty, _)) = &fn_trait_impl
639 && !matches!(
640 self_ty.hax_skip_binder_ref().kind(),
641 hax::TyKind::Closure(..) | hax::TyKind::FnDef { .. }
642 ) =>
643 {
644 ConstantExprKind::VTableRef(self.translate_trait_proof(span, trait_proof)?)
645 }
646 hax::TraitProofKind::Concrete { .. } | hax::TraitProofKind::Builtin { .. } => {
647 let vtable_instance =
650 self.translate_region_binder(span, &trait_proof.pred, |ctx, tref| {
651 let (impl_item, impl_kind) = match (&trait_proof.kind, fn_trait_impl) {
654 (hax::TraitProofKind::Concrete(impl_item), _) => {
655 (impl_item, TransImplSource::Normal)
656 }
657 (_, Some((self_ty, kind))) => {
659 match self_ty.hax_skip_binder_ref().kind() {
660 hax::TyKind::Closure(args) => {
661 (&args.item, TransImplSource::Callable(kind))
662 }
663 hax::TyKind::FnDef { item, .. } => {
664 (item, TransImplSource::Callable(kind))
665 }
666 _ => unreachable!("builtin `Fn*` impl for {self_ty:?}"),
667 }
668 }
669 (_, None) => (tref, TransImplSource::Marker),
670 };
671 ctx.translate_vtable_instance_ref(span, tref, impl_item, impl_kind)
672 })?;
673 let vtable_instance = self.erase_region_binder(vtable_instance);
674 let vtable_instance =
675 ConstantExpr::new(ConstantExprKind::Global(vtable_instance), vtbl_ty);
676 ConstantExprKind::Ref(vtable_instance, None)
677 }
678 _ => ConstantExprKind::VTableRef(self.translate_trait_proof(span, trait_proof)?),
679 };
680
681 Ok(ConstantExpr::new(kind, ty))
682 }
683
684 pub fn translate_vtable_instance_ref(
686 &mut self,
687 span: Span,
688 trait_ref: &hax::TraitRef,
689 vtable_item: &hax::ItemRef,
690 impl_kind: TransImplSource,
691 ) -> Result<GlobalDeclRef, Error> {
692 Ok(self
693 .translate_vtable_instance_ref_maybe_enqueue(
694 true,
695 span,
696 trait_ref,
697 vtable_item,
698 impl_kind,
699 )?
700 .expect("trait should be dyn-compatible"))
701 }
702
703 pub fn translate_vtable_instance_ref_no_enqueue(
704 &mut self,
705 span: Span,
706 trait_ref: &hax::TraitRef,
707 vtable_item: &hax::ItemRef,
708 impl_kind: TransImplSource,
709 ) -> Result<Option<GlobalDeclRef>, Error> {
710 self.translate_vtable_instance_ref_maybe_enqueue(
711 false,
712 span,
713 trait_ref,
714 vtable_item,
715 impl_kind,
716 )
717 }
718
719 pub fn translate_vtable_instance_ref_maybe_enqueue(
720 &mut self,
721 enqueue: bool,
722 span: Span,
723 trait_ref: &hax::TraitRef,
724 vtable_item: &hax::ItemRef,
725 impl_kind: TransImplSource,
726 ) -> Result<Option<GlobalDeclRef>, Error> {
727 if !self.trait_is_dyn_compatible(&trait_ref.def_id)? {
728 return Ok(None);
729 }
730 let vtable_ref: GlobalDeclRef = self.translate_item_maybe_enqueue(
735 span,
736 vtable_item,
737 TransItemSourceKind::VTableInstance(impl_kind),
738 enqueue,
739 )?;
740 Ok(Some(vtable_ref))
741 }
742
743 fn get_vtable_instance_info(
745 &mut self,
746 span: Span,
747 impl_def: &hax::FullDef<'tcx>,
748 impl_kind: TransImplSource,
749 ) -> Result<(Option<TraitImplRef>, TypeDeclRef), Error> {
750 let implemented_trait = self
751 .vtable_instance_data(impl_def, impl_kind)
752 .implemented_trait_ref;
753 let vtable_struct_ref = self.translate_vtable_struct_ref(span, implemented_trait)?;
754 let impl_ref = if impl_kind == TransImplSource::Marker || self.monomorphize() {
755 None
756 } else {
757 Some(self.translate_item(
758 span,
759 impl_def.this(),
760 TransItemSourceKind::TraitImpl(impl_kind),
761 )?)
762 };
763 Ok((impl_ref, vtable_struct_ref))
764 }
765
766 pub(crate) fn translate_vtable_instance(
781 mut self,
782 global_id: GlobalDeclId,
783 item_meta: ItemMeta,
784 impl_def: &hax::FullDef<'tcx>,
785 impl_kind: TransImplSource,
786 ) -> Result<GlobalDecl, Error> {
787 let span = item_meta.span;
788
789 let (impl_ref, vtable_struct_ref) =
790 self.get_vtable_instance_info(span, impl_def, impl_kind)?;
791 let src = GlobalSource::VTableInstance { impl_ref };
792
793 let init = self.register_item(
795 span,
796 impl_def.this(),
797 TransItemSourceKind::VTableInstanceInitializer(impl_kind),
798 );
799 let ty = Ty::new(TyKind::Adt(vtable_struct_ref));
800 let value = ConstantExpr::new(
801 ConstantExprKind::Call(
802 FnPtr::new(
803 FnPtrKind::Fun(init),
804 self.outermost_generics().identity_args(),
805 ),
806 vec![],
807 ),
808 ty.clone(),
809 );
810
811 Ok(GlobalDecl {
812 def_id: global_id,
813 item_meta,
814 generics: self.into_generics(),
815 src,
816 global_kind: GlobalKind::Static,
818 ty,
819 value,
820 })
821 }
822
823 fn vtable_instance_data<'a>(
825 &self,
826 impl_def: &'a hax::FullDef<'tcx>,
827 impl_kind: TransImplSource,
828 ) -> VTableInstanceData<'a> {
829 match (impl_kind, impl_def.kind()) {
830 (TransImplSource::Callable(target_kind), _) => {
832 let vimpl = callable_virtual_impl(impl_def, target_kind);
833 let vtable_sig = vimpl.methods[0]
834 .1
835 .as_ref()
836 .expect("a callable with a vtable must be dyn-compatible");
837 VTableInstanceData {
838 implemented_trait_ref: &vimpl.trait_pred.trait_ref,
839 implied_trait_proofs: &vimpl.implied_trait_proofs,
840 methods: VTableMethodSource::FnTraitShim(
841 impl_def.this(),
842 impl_kind,
843 vtable_sig,
844 ),
845 }
846 }
847 (
848 TransImplSource::Normal,
849 hax::FullDefKind::TraitImpl {
850 trait_pred,
851 items,
852 implied_trait_proofs,
853 ..
854 },
855 ) => {
856 let methods: IndexVec<TraitMethodId, _> = items
859 .iter()
860 .filter(|item| matches!(item.decl_def_id.kind, hax::DefKind::AssocFn))
861 .collect();
862 VTableInstanceData {
863 implemented_trait_ref: &trait_pred.trait_ref,
864 implied_trait_proofs,
865 methods: VTableMethodSource::ImplMethods(methods),
866 }
867 }
868 (
869 TransImplSource::Marker,
870 hax::FullDefKind::Trait {
871 self_predicate,
872 implied_trait_proofs,
873 ..
874 },
875 ) => VTableInstanceData {
876 implemented_trait_ref: &self_predicate.trait_ref,
877 implied_trait_proofs,
878 methods: VTableMethodSource::ImplMethods(IndexVec::new()),
879 },
880 _ => unreachable!(),
881 }
882 }
883
884 fn vtable_method_value(
886 &mut self,
887 span: Span,
888 trait_id: TraitDeclId,
889 method_id: TraitMethodId,
890 implemented_trait: &hax::TraitRef,
891 methods: &VTableMethodSource<'_>,
892 ) -> Result<VtableMethodValue, Error> {
893 match methods {
894 VTableMethodSource::ImplMethods(methods) => {
895 let item = methods[method_id];
896 let item_ref = match &item.value {
898 Some(value) => value.skip_binder.item.clone(),
899 None => {
901 let hax_state = self.hax_state_with_id();
902 let trait_args = implemented_trait.rustc_args(hax_state);
903 hax::ItemRef::translate_from_hax_def_id(
904 hax_state,
905 item.decl_def_id.clone(),
906 trait_args,
907 )
908 }
909 };
910 let shim = self.translate_fn_ptr(
911 span,
912 &item_ref,
913 TransItemSourceKind::VTableMethod(TransImplSource::Normal),
914 )?;
915
916 if !self.monomorphize() {
919 return Ok(VtableMethodValue::Const(ConstantExprKind::FnPtr(shim)));
920 }
921
922 assert!(self.binding_levels.len() == 1);
926 let orginal_binding = self.binding_levels.pop();
927 let assoc_fun_def = self.hax_def(&item_ref)?;
928 self.translate_item_generics(
929 span,
930 &assoc_fun_def,
931 &TransItemSourceKind::VTableMethod(TransImplSource::Normal),
932 )?;
933 let vtable_sig = match assoc_fun_def.kind() {
934 hax::FullDefKind::AssocFn {
935 vtable_sig: Some(vtable_sig),
936 ..
937 } => vtable_sig.clone(),
938 _ => unreachable!("MONO: only assoc fun is supported"),
939 };
940
941 let signature = self.translate_fun_sig(span, &vtable_sig.value)?;
942 let method_ty = Ty::new(TyKind::FnPtr(RegionBinder {
944 regions: self.outermost_generics().regions.clone(),
945 skip_binder: signature,
946 }));
947
948 self.binding_levels.pop();
950 if let Some(binding_level) = orginal_binding {
951 self.binding_levels.push(binding_level);
952 }
953
954 self.mark_method_as_used(trait_id, method_id);
955 let method_name = self
956 .translated
957 .assoc_item_name(trait_id, method_id)
958 .to_string();
959 Ok(VtableMethodValue::Cast((method_name, method_ty, shim)))
960 }
961 &VTableMethodSource::FnTraitShim(item, impl_source, vtable_sig) => {
962 let shim = self.translate_fn_ptr(
963 span,
964 item,
965 TransItemSourceKind::VTableMethod(impl_source),
966 )?;
967 if !self.monomorphize() {
968 return Ok(VtableMethodValue::Const(ConstantExprKind::FnPtr(shim)));
969 }
970 let bound_sig = self.translate_region_binder(span, vtable_sig, |ctx, sig| {
973 ctx.translate_fun_sig(span, sig)
974 })?;
975 let method_ty = TyKind::FnPtr(bound_sig).into_ty();
976 let method_name = self
977 .translated
978 .assoc_item_name(trait_id, method_id)
979 .to_string();
980 Ok(VtableMethodValue::Cast((method_name, method_ty, shim)))
981 }
982 }
983 }
984
985 fn gen_vtable_instance_init_body(
992 &mut self,
993 span: Span,
994 impl_def: &hax::FullDef<'tcx>,
995 vtable_struct_ref: TypeDeclRef,
996 impl_kind: TransImplSource,
997 ) -> Result<Body, Error> {
998 let VTableInstanceData {
999 implemented_trait_ref,
1000 implied_trait_proofs,
1001 methods,
1002 } = self.vtable_instance_data(impl_def, impl_kind);
1003
1004 let trait_def = self.hax_def(implemented_trait_ref)?;
1005 let poly_trait_def = self.poly_hax_def(&implemented_trait_ref.def_id)?;
1007 let hax::FullDefKind::Trait {
1008 implied_predicates: implied_preds,
1009 ..
1010 } = poly_trait_def.kind()
1011 else {
1012 unreachable!()
1013 };
1014
1015 let implemented_trait = self.translate_trait_decl_ref(span, implemented_trait_ref)?;
1016 let trait_id = implemented_trait.id;
1017 let self_ty = &implemented_trait.generics.types[0];
1019
1020 let mut builder = BodyBuilder::new(span, 0);
1021 let ret_ty = Ty::new(TyKind::Adt(vtable_struct_ref.clone()));
1022 let ret_place = builder.new_var(Some("ret".into()), ret_ty.clone());
1023
1024 let vtable_data = self.prepare_vtable_fields(&poly_trait_def, trait_id, implied_preds)?;
1025 let field_tys = {
1028 let ItemRef::Type(vtable_def) =
1029 self.t_ctx.get_or_translate(vtable_struct_ref.id.into())?
1030 else {
1031 unreachable!()
1032 };
1033 let fields = match &vtable_def.kind {
1034 TypeDeclKind::Struct(fields) => fields,
1035 TypeDeclKind::Opaque => return Ok(Body::Opaque),
1036 TypeDeclKind::Error(error) => return Err(Error::new(span, error.clone())),
1037 _ => unreachable!(),
1038 };
1039 fields
1040 .iter()
1041 .map(|f| &f.ty)
1042 .cloned()
1043 .map(|ty| ty.substitute(&vtable_struct_ref.generics))
1044 .collect_vec()
1045 };
1046
1047 let mut aggregate_fields = vec![];
1049 for (field, ty) in vtable_data.fields.into_iter().zip(field_tys) {
1050 let mk_const = |kind| Operand::Const(ConstantExpr::new(kind, ty.clone()));
1052 let mut mk_cast = |(method_name, method_ty, method_shim): (String, Ty, FnPtr)| {
1076 let method_local = builder.new_var(Some(method_name.clone()), method_ty.clone());
1077 let shim = Rvalue::Use(
1078 Operand::Const(ConstantExpr::new(
1079 ConstantExprKind::FnPtr(method_shim.clone()),
1080 method_ty.clone(),
1081 )),
1082 WithRetag::No,
1083 );
1084 let cast_local = builder.new_var(
1085 Some("erased_".to_string() + method_name.as_str()),
1086 ty.clone(),
1087 );
1088 let cast = Rvalue::UnaryOp(
1089 UnOp::Cast(CastKind::RawPtr(
1090 method_local.ty().clone(),
1091 cast_local.ty().clone(),
1092 )),
1093 Operand::Move(method_local.clone()),
1094 );
1095
1096 builder.push_statement(StatementKind::Assign(method_local.clone(), shim));
1097 builder.push_statement(StatementKind::Assign(cast_local.clone(), cast));
1098 Operand::Move(cast_local)
1099 };
1100 let op = match field {
1101 TrVTableField::Size => mk_const(ConstantExprKind::SizeOf(self_ty.clone())),
1102 TrVTableField::Align => mk_const(ConstantExprKind::AlignOf(self_ty.clone())),
1103 TrVTableField::Drop => {
1104 let drop_shim = self.translate_item(
1105 span,
1106 impl_def.this(),
1107 TransItemSourceKind::VTableDropShim(impl_kind),
1108 )?;
1109 if self.monomorphize() {
1110 let hax::FullDefKind::Trait { dyn_self, .. } = trait_def.kind() else {
1112 panic!()
1113 };
1114
1115 let Some(dyn_self) = dyn_self else {
1116 panic!(
1117 "MONO: Trying to generate a vtable for a non-dyn-compatible trait"
1118 )
1119 };
1120 let ref_dyn_self =
1121 TyKind::RawPtr(self.translate_ty(span, dyn_self)?, RefKind::Mut)
1122 .into_ty();
1123 let signature = FunSig {
1124 is_unsafe: true,
1125 abi: Abi::rust(),
1126 is_variadic: false,
1127 inputs: vec![ref_dyn_self.clone()],
1128 output: Ty::mk_unit(),
1129 };
1130 let drop_ty = Ty::new(TyKind::FnPtr(RegionBinder::empty(signature)));
1131
1132 mk_cast(("drop".to_string(), drop_ty.clone(), drop_shim))
1133 } else {
1134 mk_const(ConstantExprKind::FnPtr(drop_shim))
1135 }
1136 }
1137 TrVTableField::Method(method_id, _) => {
1138 let value = self.vtable_method_value(
1139 span,
1140 trait_id,
1141 method_id,
1142 implemented_trait_ref,
1143 &methods,
1144 )?;
1145 match value {
1146 VtableMethodValue::Const(const_kind) => mk_const(const_kind),
1147 VtableMethodValue::Cast(method) => mk_cast(method),
1148 }
1149 }
1150 TrVTableField::SuperTrait(clause_id, _) => {
1151 let trait_proof = &implied_trait_proofs[clause_id.index()];
1152 Operand::Const(self.translate_vtable_instance_const(span, trait_proof)?)
1153 }
1154 };
1155 aggregate_fields.push(op);
1156 }
1157
1158 builder.push_statement(StatementKind::Assign(
1160 ret_place,
1161 Rvalue::Aggregate(
1162 AggregateKind::Adt(vtable_struct_ref.clone(), None, None),
1163 aggregate_fields,
1164 ),
1165 ));
1166
1167 Ok(Body::Unstructured(builder.build()))
1168 }
1169
1170 pub(crate) fn translate_vtable_instance_init(
1171 mut self,
1172 init_func_id: FunDeclId,
1173 item_meta: ItemMeta,
1174 impl_def: &hax::FullDef<'tcx>,
1175 impl_kind: TransImplSource,
1176 ) -> Result<FunDecl, Error> {
1177 let span = item_meta.span;
1178
1179 let (_, vtable_struct_ref) = self.get_vtable_instance_info(span, impl_def, impl_kind)?;
1180
1181 let init_for = self.register_item(
1182 span,
1183 impl_def.this(),
1184 TransItemSourceKind::VTableInstance(impl_kind),
1185 );
1186 let src = FunSource::GlobalInitializer(GlobalDeclRef {
1187 id: init_for,
1188 generics: Box::new(self.outermost_generics().identity_args()),
1189 });
1190
1191 let sig = FunSig {
1193 is_unsafe: false,
1194 abi: Abi::rust(),
1195 is_variadic: false,
1196 inputs: vec![],
1197 output: Ty::new(TyKind::Adt(vtable_struct_ref.clone())),
1198 };
1199
1200 let body = match impl_kind {
1201 _ if item_meta.opacity.with_private_contents().is_opaque() => Body::Opaque,
1202 TransImplSource::Marker | TransImplSource::Normal | TransImplSource::Callable(..) => {
1203 self.gen_vtable_instance_init_body(span, impl_def, vtable_struct_ref, impl_kind)?
1204 }
1205 _ => {
1206 raise_error!(
1207 self,
1208 span,
1209 "Don't know how to generate a vtable for a virtual impl {impl_kind:?}"
1210 );
1211 }
1212 };
1213
1214 Ok(FunDecl {
1215 def_id: init_func_id,
1216 item_meta,
1217 generics: self.into_generics(),
1218 signature: Box::new(sig),
1219 src,
1220 body,
1221 })
1222 }
1223
1224 fn translate_vtable_shim_body(
1249 &mut self,
1250 span: Span,
1251 target_receiver: &Ty,
1252 shim_signature: &FunSig,
1253 receiver_is_by_value: bool,
1254 target_fn: FnPtr,
1255 ) -> Result<Body, Error> {
1256 let mut builder = BodyBuilder::new(span, shim_signature.inputs.len());
1257
1258 let ret_place = builder.new_var(None, shim_signature.output.clone());
1259 let mut method_args = shim_signature
1260 .inputs
1261 .iter()
1262 .map(|ty| builder.new_var(None, ty.clone()))
1263 .collect_vec();
1264
1265 let cast_target_ty = if receiver_is_by_value {
1266 TyKind::RawPtr(target_receiver.clone(), RefKind::Mut).into_ty()
1267 } else {
1268 target_receiver.clone()
1269 };
1270 let target_self = builder.new_var(None, cast_target_ty);
1271
1272 let receiver_arg = if receiver_is_by_value {
1274 target_self.clone().deref()
1275 } else {
1276 target_self.clone()
1277 };
1278 let shim_self = mem::replace(&mut method_args[0], receiver_arg);
1279
1280 let rval = Rvalue::UnaryOp(
1284 UnOp::Cast(CastKind::Concretize(
1285 shim_self.ty().clone(),
1286 target_self.ty().clone(),
1287 )),
1288 Operand::Move(shim_self.clone()),
1289 );
1290 builder.push_statement(StatementKind::Assign(target_self.clone(), rval));
1291
1292 builder.call(Call {
1293 func: FnOperand::Regular(target_fn),
1294 args: method_args.into_iter().map(Operand::Move).collect(),
1295 dest: ret_place,
1296 });
1297
1298 Ok(Body::Unstructured(builder.build()))
1299 }
1300
1301 fn translate_vtable_drop_shim_body(
1313 &mut self,
1314 span: Span,
1315 shim_receiver: &Ty,
1316 target_receiver: &Ty,
1317 trait_pred: &TraitPredicate,
1318 ) -> Result<Body, Error> {
1319 let mut builder = BodyBuilder::new(span, 1);
1320
1321 builder.new_var(Some("ret".into()), Ty::mk_unit());
1322 let dyn_self = builder.new_var(Some("dyn_self".into()), shim_receiver.clone());
1323 let target_self = builder.new_var(Some("target_self".into()), target_receiver.clone());
1324
1325 let rval = Rvalue::UnaryOp(
1327 UnOp::Cast(CastKind::Concretize(
1328 dyn_self.ty().clone(),
1329 target_self.ty().clone(),
1330 )),
1331 Operand::Move(dyn_self.clone()),
1332 );
1333 builder.push_statement(StatementKind::Assign(target_self.clone(), rval));
1334
1335 let rustc_trait_args = trait_pred.trait_ref.rustc_args(self.hax_state_with_id());
1336 let rustc_self_ty = rustc_trait_args[0].as_type().unwrap();
1337 let fn_ptr = self.translate_drop_glue_method_call(span, rustc_self_ty)?;
1338
1339 let drop_arg = target_self.clone().deref();
1341 builder.insert_drop(drop_arg, fn_ptr);
1342
1343 Ok(Body::Unstructured(builder.build()))
1344 }
1345
1346 pub(crate) fn translate_vtable_drop_shim(
1347 mut self,
1348 fun_id: FunDeclId,
1349 item_meta: ItemMeta,
1350 impl_def: &hax::FullDef,
1351 impl_kind: TransImplSource,
1352 ) -> Result<FunDecl, Error> {
1353 let span = item_meta.span;
1354
1355 let (dyn_self, trait_pred) = match (impl_kind, impl_def.kind()) {
1356 (TransImplSource::Callable(target_kind), _) => {
1358 let vimpl = callable_virtual_impl(impl_def, target_kind);
1359 (vimpl.dyn_self.clone(), &vimpl.trait_pred)
1360 }
1361 (
1362 TransImplSource::Normal,
1363 hax::FullDefKind::TraitImpl {
1364 dyn_self,
1365 trait_pred,
1366 ..
1367 },
1368 ) => (dyn_self.clone(), trait_pred),
1369 (
1370 TransImplSource::Marker,
1371 hax::FullDefKind::Trait {
1372 dyn_self,
1373 self_predicate,
1374 ..
1375 },
1376 ) => (dyn_self.clone(), self_predicate),
1377 _ => unreachable!(),
1378 };
1379 let Some(dyn_self) = dyn_self else {
1380 raise_error!(
1381 self,
1382 span,
1383 "Trying to generate a vtable drop shim for a non-dyn-compatible trait"
1384 );
1385 };
1386
1387 let borrow_region = self.drop_glue_region();
1388
1389 let dyn_self = self.translate_ty(span, &dyn_self)?;
1390 let signature = self.drop_glue_method_sig(dyn_self.clone(), borrow_region);
1392
1393 let target_self_ref = {
1395 let impl_trait = self.translate_trait_ref(span, &trait_pred.trait_ref)?;
1396 TyKind::Ref(
1397 borrow_region,
1398 impl_trait.generics.types[0].clone(),
1399 RefKind::Mut,
1400 )
1401 .into_ty()
1402 };
1403
1404 let body: Body = self.translate_vtable_drop_shim_body(
1405 span,
1406 &signature.inputs[0],
1407 &target_self_ref,
1408 trait_pred,
1409 )?;
1410
1411 Ok(FunDecl {
1412 def_id: fun_id,
1413 item_meta,
1414 generics: self.into_generics(),
1415 signature: Box::new(signature),
1416 src: FunSource::VTableShim,
1417 body,
1418 })
1419 }
1420
1421 pub(crate) fn translate_vtable_shim(
1422 mut self,
1423 fun_id: FunDeclId,
1424 item_meta: ItemMeta,
1425 def: &hax::FullDef<'tcx>,
1426 impl_kind: TransImplSource,
1427 ) -> Result<FunDecl, Error> {
1428 let span = item_meta.span;
1429
1430 let signature: FunSig;
1431 let target_receiver: Ty;
1433 let receiver_is_by_value: bool;
1434 let target_item: TransItemSourceKind;
1436
1437 if let TransImplSource::Callable(target_kind) = impl_kind {
1438 let vimpl = callable_virtual_impl(def, target_kind);
1439 let vtable_sig = &vimpl.methods[0]
1440 .1
1441 .as_ref()
1442 .expect("a callable with a vtable must be dyn-compatible");
1443 signature = {
1446 let bound_sig = self.translate_region_binder(span, vtable_sig, |ctx, sig| {
1447 ctx.translate_fun_sig(span, sig)
1448 })?;
1449 bound_sig.apply(
1450 self.the_only_binder()
1451 .closure_call_method_region
1452 .iter()
1453 .map(|r| Region::Var(DeBruijnVar::new_at_zero(*r)))
1454 .collect(),
1455 )
1456 };
1457 target_receiver = {
1459 let hax::GenericArg::Type(self_ty) = &vimpl.trait_pred.trait_ref.generic_args[0]
1460 else {
1461 unreachable!("no `Self` type arg on a `Fn*` trait ref")
1462 };
1463 let state_ty = self.translate_ty(span, self_ty)?;
1464 match target_kind {
1465 ClosureKind::FnOnce => state_ty,
1466 ClosureKind::Fn | ClosureKind::FnMut => {
1467 let rid = self.the_only_binder().closure_call_method_region.unwrap();
1468 let region = Region::Var(DeBruijnVar::new_at_zero(rid));
1469 let mutability = RefKind::mutable(target_kind == ClosureKind::FnMut);
1470 TyKind::Ref(region, state_ty, mutability).into_ty()
1471 }
1472 }
1473 };
1474 receiver_is_by_value = target_kind == ClosureKind::FnOnce;
1475 target_item = TransItemSourceKind::CallableMethod(target_kind);
1476 } else {
1477 let hax::FullDefKind::AssocFn {
1478 vtable_sig: Some(vtable_sig),
1479 sig: target_signature,
1480 associated_item,
1481 ..
1482 } = def.kind()
1483 else {
1484 raise_error!(
1485 self,
1486 span,
1487 "Trying to generate a vtable shim for a non-vtable-safe method"
1488 );
1489 };
1490 signature = self.translate_fun_sig(span, &vtable_sig.value)?;
1491 target_receiver = self.translate_ty(span, &target_signature.value.inputs[0])?;
1492 receiver_is_by_value = hax::vtable_receiver_is_by_value(
1493 self.tcx,
1494 associated_item
1495 .implemented_trait_item_id()
1496 .real_rust_def_id(),
1497 );
1498 target_item = TransItemSourceKind::Fun;
1499 };
1500
1501 trace!(
1502 "[VtableShim] Obtained dyn signature with receiver type: {}",
1503 signature.inputs[0].with_ctx(&self.into_fmt())
1504 );
1505
1506 let body = if item_meta.opacity.with_private_contents().is_opaque() {
1507 Body::Opaque
1508 } else {
1509 let fun_id = self.register_item(span, def.this(), target_item);
1510 let target_fn = FnPtr::new(
1511 FnPtrKind::Fun(fun_id),
1512 self.outermost_binder().params.identity_args(),
1513 );
1514 self.translate_vtable_shim_body(
1515 span,
1516 &target_receiver,
1517 &signature,
1518 receiver_is_by_value,
1519 target_fn,
1520 )?
1521 };
1522
1523 Ok(FunDecl {
1524 def_id: fun_id,
1525 item_meta,
1526 generics: self.into_generics(),
1527 signature: Box::new(signature),
1528 src: FunSource::VTableShim,
1529 body,
1530 })
1531 }
1532}