1use itertools::Itertools;
2use rustc_hir::attrs::LangItem;
3use rustc_span::kw;
4use std::mem;
5
6use super::{
7 translate_closures::{callable_virtual_impl, recognize_fn_trait_impl_proof},
8 translate_crate::TransItemSourceKind,
9 translate_ctx::*,
10 translate_generics::BindingLevel,
11};
12use crate::hax;
13use crate::hax::TraitPredicate;
14use charon_lib::formatter::IntoFormatter;
15use charon_lib::pretty::FmtWithCtx;
16use charon_lib::ullbc_ast::*;
17
18enum VtableMethodValue {
22 Const(FnPtr),
23 Cast(Ty, FnPtr),
25}
26
27fn dynify<T: TyVisitable>(mut x: T, new_self: Option<Ty>, for_method: bool) -> T {
35 struct ReplaceSelfVisitor {
36 new_self: Option<Ty>,
37 for_method: bool,
38 }
39 impl VarsVisitor for ReplaceSelfVisitor {
40 fn visit_type_var(&mut self, v: TypeDbVar) -> Option<Ty> {
41 if let DeBruijnVar::Bound(DeBruijnId::ZERO, type_id) = v {
42 Some(if let Some(new_id) = type_id.index().checked_sub(1) {
44 TyKind::TypeVar(DeBruijnVar::Bound(DeBruijnId::ZERO, TypeVarId::new(new_id)))
45 .into_ty()
46 } else {
47 self.new_self.clone().expect(
48 "Found unexpected `Self`
49 type when constructing vtable",
50 )
51 })
52 } else {
53 None
54 }
55 }
56
57 fn visit_clause_var(&mut self, v: ClauseDbVar) -> Option<ClauseReplacement> {
58 if let DeBruijnVar::Bound(DeBruijnId::ZERO, clause_id) = v {
59 if self.for_method && clause_id == TraitClauseId::ZERO {
60 Some(ClauseReplacement::Proof(RegionBinder::empty(
62 TraitRefKind::Dyn,
63 )))
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<'tcx> ItemTransCtx<'tcx, '_> {
85 pub fn check_at_most_one_pred_has_methods(
86 &mut self,
87 span: Span,
88 preds: &hax::GenericPredicates<'tcx>,
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(t) => t
98 .items(self.hax_state())
99 .iter()
100 .any(|assoc| matches!(assoc.kind, hax::AssocKind::Fn { .. })),
101 hax::FullDefKind::TraitAlias(_) => false,
102 _ => unreachable!(),
103 };
104 if has_methods {
105 raise_error!(
106 self,
107 span,
108 "`dyn Trait` with multiple method-bearing predicates is not supported"
109 );
110 }
111 }
112 }
113 Ok(())
114 }
115
116 pub fn translate_dyn_binder<T, U>(
117 &mut self,
118 span: Span,
119 binder: &hax::DynBinder<'tcx, T>,
120 f: impl FnOnce(&mut Self, Ty, &T) -> Result<U, Error>,
121 ) -> Result<Binder<U>, Error> {
122 self.check_at_most_one_pred_has_methods(span, &binder.predicates)?;
126
127 self.binding_levels.push(BindingLevel::new_dyn());
129
130 let ty_id = self.innermost_binder_mut().push_type_var(
132 binder.existential_ty.index,
133 binder.existential_ty.name,
134 Variance::Unknown,
135 );
136 let ty = TyKind::TypeVar(DeBruijnVar::new_at_zero(ty_id)).into_ty();
137
138 self.register_predicates(&binder.predicates, PredicateOrigin::Dyn)?;
139
140 let val = f(self, ty, &binder.val)?;
141
142 if self.monomorphize() {
147 struct ShiftDynClauseVars;
148 impl VarsVisitor for ShiftDynClauseVars {
149 fn visit_clause_var(&mut self, v: ClauseDbVar) -> Option<ClauseReplacement> {
150 if let DeBruijnVar::Bound(DeBruijnId::ZERO, clause_id) = v
151 && let Some(new_id) = clause_id.index().checked_sub(1)
152 {
153 return Some(ClauseReplacement::Var(DeBruijnVar::Bound(
154 DeBruijnId::ZERO,
155 TraitClauseId::new(new_id),
156 )));
157 }
158 None
159 }
160 }
161
162 self.innermost_generics_mut()
163 .trait_type_constraints
164 .iter_mut()
165 .for_each(|pred| pred.visit_vars(&mut ShiftDynClauseVars));
166 }
167
168 let params = self.binding_levels.pop().unwrap().params;
169 Ok(Binder {
170 params,
171 skip_binder: val,
172 kind: BinderKind::Dyn,
173 })
174 }
175}
176
177#[derive(Debug)]
180pub enum TrVTableField<'tcx> {
181 Size,
182 Align,
183 Drop,
184 Method(TraitMethodId, hax::Binder<hax::TyFnSig<'tcx>>, MetadataPath),
185 SuperTrait(TraitClauseId, hax::Clause<'tcx>),
186}
187
188pub struct VTableData<'tcx> {
189 pub fields: IndexVec<FieldId, TrVTableField<'tcx>>,
190 pub supertrait_map: IndexVec<TraitClauseId, Option<FieldId>>,
191}
192
193struct VTableInstanceData<'tcx, 'a> {
195 implemented_trait_ref: &'a hax::TraitRef<'tcx>,
196 implied_trait_proofs: &'a [hax::TraitProof<'tcx>],
197 methods: VTableMethodSource<'tcx, 'a>,
198}
199
200enum VTableMethodSource<'tcx, 'a> {
202 ImplMethods(IndexVec<TraitMethodId, &'a hax::ImplAssocItem<'tcx>>),
203 FnTraitShim(
204 &'a hax::ItemRef<'tcx>,
205 TransImplSource,
206 &'a hax::PolyFnSig<'tcx>,
207 ),
208}
209
210impl<'tcx> ItemTransCtx<'tcx, '_> {
212 pub fn trait_is_dyn_compatible(&mut self, def_id: &hax::DefId) -> bool {
216 matches!(def_id.kind, hax::DefKind::Trait | hax::DefKind::TraitAlias)
217 && def_id
218 .as_real_def_id()
219 .is_some_and(|id| self.tcx.is_dyn_compatible(id))
220 }
221
222 fn pred_is_for_self(&self, tref: &hax::TraitRef<'tcx>) -> bool {
224 let first_ty = tref
225 .generic_args
226 .iter()
227 .filter_map(|arg| match arg {
228 hax::GenericArg::Type(ty) => Some(ty),
229 _ => None,
230 })
231 .next();
232 match first_ty {
233 None => false,
234 Some(first_ty) => match first_ty.kind() {
235 hax::TyKind::Param(param_ty) if param_ty.index == 0 => {
236 assert_eq!(param_ty.name, kw::SelfUpper);
237 true
238 }
239 _ => false,
240 },
241 }
242 }
243
244 pub fn translate_vtable_struct_ref(
245 &mut self,
246 span: Span,
247 tref: &hax::TraitRef<'tcx>,
248 ) -> Result<TypeDeclRef, Error> {
249 Ok(self
250 .translate_vtable_struct_ref_maybe_enqueue(true, span, tref)?
251 .expect("trait should be dyn-compatible"))
252 }
253
254 pub fn translate_vtable_struct_ref_no_enqueue(
255 &mut self,
256 span: Span,
257 tref: &hax::TraitRef<'tcx>,
258 ) -> Result<Option<TypeDeclRef>, Error> {
259 self.translate_vtable_struct_ref_maybe_enqueue(false, span, tref)
260 }
261
262 pub fn translate_vtable_struct_ref_maybe_enqueue(
264 &mut self,
265 enqueue: bool,
266 span: Span,
267 tref: &hax::TraitRef<'tcx>,
268 ) -> Result<Option<TypeDeclRef>, Error> {
269 if !self.trait_is_dyn_compatible(&tref.def_id) {
270 return Ok(None);
271 }
272
273 let mut vtable_ref = self.translate_type_decl_ref_maybe_enqueue(
276 span,
277 tref,
278 TransItemSourceKind::VTable,
279 enqueue,
280 )?;
281 vtable_ref
283 .generics
284 .types
285 .remove_and_shift_ids(TypeVarId::ZERO);
286
287 if !self.monomorphize() {
288 let assoc_tys: Vec<_> = tref
290 .trait_associated_types(self.hax_state_with_id())
291 .iter()
292 .map(|ty| self.translate_ty(span, ty))
293 .try_collect()?;
294 vtable_ref.generics.types.extend(assoc_tys);
295 }
296
297 Ok(Some(vtable_ref))
298 }
299
300 fn prepare_vtable_fields(
301 &mut self,
302 poly_trait_def: &hax::FullDef<'tcx>,
303 trait_id: TraitDeclId,
304 implied_predicates: &hax::GenericPredicates<'tcx>,
305 ) -> Result<VTableData<'tcx>, Error> {
306 let mut supertrait_map: IndexVec<TraitClauseId, _> =
307 (0..implied_predicates.predicates.len())
308 .map(|_| None)
309 .collect();
310 let mut fields = IndexVec::new();
311
312 fields.push(TrVTableField::Size);
314 fields.push(TrVTableField::Align);
315 fields.push(TrVTableField::Drop);
316
317 if let hax::FullDefKind::Trait(t) = poly_trait_def.kind() {
319 for item in t.items(self.hax_state()) {
320 let item_def_id = &item.def_id;
321 let poly_item_def = self.poly_hax_def(item_def_id)?;
323 if let hax::FullDefKind::AssocFn(f) = poly_item_def.kind()
324 && let Some(sig) = f.vtable_sig(self.hax_state())
325 {
326 let id = self.translate_trait_method_id_no_enqueue(trait_id, item_def_id)?;
327 let path =
328 self.translate_metadata_path(&f.vtable_receiver_path(self.hax_state()));
329 fields.push(TrVTableField::Method(id, sig, path));
330 }
331 }
332 }
333
334 for (i, pred) in implied_predicates.iter_trait_clauses().enumerate() {
336 let trait_clause_id = TraitClauseId::from_usize(i); let clause = &pred.clause;
338 let hax::ClauseKind::Trait(pred) = clause.kind.hax_skip_binder_ref() else {
339 unreachable!()
340 };
341 if self.pred_is_for_self(&pred.trait_ref) {
343 if !self.trait_is_dyn_compatible(&pred.trait_ref.def_id) {
344 self.assert_is_destruct(&pred.trait_ref);
346 continue;
347 }
348 supertrait_map[trait_clause_id] = Some(fields.next_idx());
349 fields.push(TrVTableField::SuperTrait(trait_clause_id, clause.clone()));
350 }
351 }
352
353 Ok(VTableData {
354 fields,
355 supertrait_map,
356 })
357 }
358
359 fn assert_is_destruct(&self, tref: &hax::TraitRef<'tcx>) {
365 assert!(
366 tref.def_id
367 .as_real_def_id()
368 .is_some_and(|id| self.tcx.is_lang_item(id, LangItem::Destruct)),
369 "unexpected non-dyn compatible supertrait: {:?}",
370 tref.def_id
371 );
372 }
373
374 fn gen_vtable_struct_fields(
375 &mut self,
376 span: Span,
377 self_trait_ref: &TraitRef,
378 vtable_data: &VTableData<'tcx>,
379 ) -> Result<IndexVec<FieldId, Field>, Error> {
380 let mut fields = IndexVec::new();
381 let mut supertrait_counter = 0..;
382 for field in &vtable_data.fields {
383 let (name, ty) = match field {
384 TrVTableField::Size => ("size".into(), Ty::mk_usize()),
385 TrVTableField::Align => ("align".into(), Ty::mk_usize()),
386 TrVTableField::Drop => {
387 if self.monomorphize() {
389 let erased_ptr_ty = Ty::new(TyKind::RawPtr(Ty::mk_unit(), RefKind::Shared));
390 ("drop".into(), erased_ptr_ty)
391 } else {
392 let self_ty =
393 TyKind::TypeVar(DeBruijnVar::new_at_zero(TypeVarId::ZERO)).into_ty();
394 let drop_ty = Ty::new(TyKind::FnPtr(self.drop_glue_fn_ptr_sig(self_ty)));
395 ("drop".into(), drop_ty)
396 }
397 }
398 TrVTableField::Method(item_id, sig, _) => {
399 let item_name = self
400 .translated
401 .assoc_item_name(self_trait_ref.trait_id(), *item_id);
402 let field_name = format!("method_{}", item_name.0);
403 if self.monomorphize() {
405 let erased_ptr_ty = Ty::new(TyKind::RawPtr(Ty::mk_unit(), RefKind::Shared));
406 (field_name, erased_ptr_ty)
407 } else {
408 let sig = self.translate_poly_fun_sig(span, sig)?;
409 let ty = TyKind::FnPtr(sig).into_ty();
410 (field_name, ty)
411 }
412 }
413 TrVTableField::SuperTrait(_, clause) => {
414 let vtbl_struct =
415 self.translate_region_binder(span, &clause.kind, |ctx, kind| {
416 let hax::ClauseKind::Trait(pred) = kind else {
417 unreachable!()
418 };
419 ctx.translate_vtable_struct_ref(span, &pred.trait_ref)
420 })?;
421 let vtbl_struct = self.erase_region_binder(vtbl_struct);
422 let ty = Ty::new(TyKind::Ref(
423 Region::Static,
424 Ty::new(TyKind::Adt(vtbl_struct)),
425 RefKind::Shared,
426 ));
427 let name = format!("super_trait_{}", supertrait_counter.next().unwrap());
428 (name, ty)
429 }
430 };
431 fields.push(Field {
432 span,
433 attr_info: AttrInfo::dummy_public(),
434 name,
435 is_positional: false,
436 ty,
437 });
438 }
439 Ok(fields)
440 }
441
442 pub(crate) fn translate_vtable_struct(
458 mut self,
459 type_id: TypeDeclId,
460 item_meta: ItemMeta,
461 trait_def: &hax::FullDef<'tcx>,
462 ) -> Result<TypeDecl, Error> {
463 let mono = self.monomorphize();
464 let span = item_meta.span;
465 if !self.trait_is_dyn_compatible(trait_def.def_id()) {
466 raise_error!(
467 self,
468 span,
469 "Trying to compute the vtable type \
470 for a non-dyn-compatible trait"
471 );
472 }
473
474 let (self_predicate, dyn_self, implied_predicates) = match trait_def.kind() {
475 hax::FullDefKind::Trait(t) => {
476 (t.self_predicate(), t.dyn_self(), t.implied_predicates())
477 }
478 hax::FullDefKind::TraitAlias(t) => {
479 (t.self_predicate(), t.dyn_self(), t.implied_predicates())
480 }
481 _ => panic!(),
482 };
483 let Some(dyn_self) = dyn_self else {
484 panic!("Trying to generate a vtable for a non-dyn-compatible trait")
485 };
486
487 let self_trait_ref = TraitRef::new(
488 TraitRefKind::SelfId,
489 self.translate_trait_predicate(span, self_predicate)?,
490 );
491 let trait_id = self_trait_ref.trait_id();
492
493 let mut field_map = IndexVec::new();
494 let mut supertrait_map: IndexVec<TraitClauseId, _> =
495 (0..implied_predicates.predicates.len())
496 .map(|_| None)
497 .collect();
498 let (mut kind, layout) = if item_meta.opacity.with_private_contents().is_opaque() {
499 (TypeDeclKind::Opaque, SeqHashMap::default())
500 } else {
501 let vtable_data =
504 self.prepare_vtable_fields(trait_def, trait_id, implied_predicates)?;
505 let fields = self.gen_vtable_struct_fields(span, &self_trait_ref, &vtable_data)?;
506
507 let kind = TypeDeclKind::Struct(fields);
508 let l = self.generate_naive_layout(span, &kind)?;
509 supertrait_map = vtable_data.supertrait_map;
510 field_map = vtable_data.fields.map_ref(|tr_field| match tr_field {
511 TrVTableField::Size => VTableField::Size,
512 TrVTableField::Align => VTableField::Align,
513 TrVTableField::Drop => VTableField::Drop,
514 TrVTableField::Method(id, _, path) => VTableField::Method(*id, path.clone()),
515 TrVTableField::SuperTrait(clause_id, ..) => VTableField::SuperTrait(*clause_id),
516 });
517 let layout = [(self.get_target_triple(), l)].into();
518 (kind, layout)
519 };
520
521 let mut generics = Default::default();
522
523 let dyn_predicate = if mono {
524 DynPredicate {
525 binder: Binder {
526 params: GenericParams::empty(),
527 skip_binder: TyKind::Error(
528 "mono vtable dyn predicate is intentionally erased".to_string(),
529 )
530 .into_ty(),
531 kind: BinderKind::Dyn,
532 },
533 }
534 } else {
535 let mut dyn_self = {
538 let dyn_self = self.translate_ty(span, dyn_self)?;
539 let TyKind::DynTrait(mut dyn_pred) = dyn_self.kind().clone() else {
540 panic!("incorrect `dyn_self`")
541 };
542
543 for (i, ty_constraint) in dyn_pred
546 .binder
547 .params
548 .trait_type_constraints
549 .iter_mut()
550 .enumerate()
551 {
552 let name = format!("Ty{i}");
553 let new_ty = self
554 .the_only_binder_mut()
555 .params
556 .types
557 .push_with(|index| TypeParam::new(index, name, Variance::Invariant));
558 let new_ty =
561 TyKind::TypeVar(DeBruijnVar::bound(DeBruijnId::new(2), new_ty)).into_ty();
562 ty_constraint.skip_binder.ty = new_ty;
563 }
564 TyKind::DynTrait(dyn_pred).into_ty()
565 };
566
567 generics = self.into_generics();
570 {
571 dyn_self = dynify(dyn_self, None, false);
572 generics = dynify(generics, Some(dyn_self.clone()), false);
573 kind = dynify(kind, Some(dyn_self.clone()), true);
574 generics.types.remove_and_shift_ids(TypeVarId::ZERO);
575 generics.types.iter_mut().for_each(|ty| {
576 ty.index -= 1;
577 });
578 }
579
580 dyn_self
581 .kind()
582 .as_dyn_trait()
583 .expect("incorrect `dyn_self`")
584 .clone()
585 };
586 Ok(TypeDecl {
587 def_id: type_id,
588 item_meta,
589 generics,
590 src: TypeSource::VTable {
591 dyn_predicate,
592 field_map,
593 supertrait_map,
594 },
595 kind,
596 layout,
597 ptr_metadata: PtrMetadata::None,
599 marker_traits: Some(Box::new(ImplementsMarkerTraits {
600 is_sized: true,
601 is_send: true,
602 is_sync: true,
603 is_freeze: true,
604 is_unpin: true,
605 })),
606 })
607 }
608}
609
610impl<'tcx> ItemTransCtx<'tcx, '_> {
612 pub fn translate_vtable_instance_const(
614 &mut self,
615 span: Span,
616 trait_proof: &hax::TraitProof<'tcx>,
617 ) -> Result<ConstantExpr, Error> {
618 let tref = trait_proof.pred.hax_skip_binder_ref();
619 if !self.trait_is_dyn_compatible(&tref.def_id) {
620 raise_error!(
621 self,
622 span,
623 "Trait {:?} should be dyn-compatible",
624 tref.def_id
625 );
626 }
627
628 let vtbl_ty = {
629 let vtbl_ty = self.translate_region_binder(span, &trait_proof.pred, |ctx, tref| {
630 ctx.translate_vtable_struct_ref(span, tref)
631 })?;
632 let vtbl_ty = self.erase_region_binder(vtbl_ty);
633 TyKind::Adt(vtbl_ty).into_ty()
634 };
635 let ty = TyKind::Ref(Region::Static, vtbl_ty.clone(), RefKind::Shared).into_ty();
636
637 let fn_trait_impl = recognize_fn_trait_impl_proof(trait_proof);
638 let kind = match &trait_proof.kind {
639 hax::TraitProofKind::Concrete { .. } | hax::TraitProofKind::Builtin { .. } => {
640 let vtable_instance =
643 self.translate_region_binder(span, &trait_proof.pred, |ctx, tref| {
644 let (impl_item, impl_kind) = match (&trait_proof.kind, fn_trait_impl) {
647 (hax::TraitProofKind::Concrete(impl_item), _) => {
648 (impl_item, TransImplSource::Normal)
649 }
650 (_, Some((self_ty, kind))) => {
652 let Some(item) = self_ty.hax_skip_binder_ref().callable_item()
653 else {
654 unreachable!("builtin `Fn*` impl for {self_ty:?}")
655 };
656 (item, TransImplSource::Callable(kind))
657 }
658 (_, None) => (tref, TransImplSource::Marker),
659 };
660 ctx.translate_vtable_instance_ref(span, tref, impl_item, impl_kind)
661 })?;
662 let vtable_instance = self.erase_region_binder(vtable_instance);
663 let vtable_instance = GlobalPlace::new_global(vtable_instance, vtbl_ty);
664 ConstantExprKind::Ref(vtable_instance, None)
665 }
666 _ => ConstantExprKind::VTableRef(self.translate_trait_proof(span, trait_proof)?),
667 };
668
669 Ok(ConstantExpr::new(kind, ty))
670 }
671
672 pub fn translate_vtable_instance_ref(
674 &mut self,
675 span: Span,
676 trait_ref: &hax::TraitRef<'tcx>,
677 vtable_item: &hax::ItemRef<'tcx>,
678 impl_kind: TransImplSource,
679 ) -> Result<GlobalDeclRef, Error> {
680 Ok(self
681 .translate_vtable_instance_ref_maybe_enqueue(
682 true,
683 span,
684 trait_ref,
685 vtable_item,
686 impl_kind,
687 )?
688 .expect("trait should be dyn-compatible"))
689 }
690
691 pub fn translate_vtable_instance_ref_no_enqueue(
692 &mut self,
693 span: Span,
694 trait_ref: &hax::TraitRef<'tcx>,
695 vtable_item: &hax::ItemRef<'tcx>,
696 impl_kind: TransImplSource,
697 ) -> Result<Option<GlobalDeclRef>, Error> {
698 self.translate_vtable_instance_ref_maybe_enqueue(
699 false,
700 span,
701 trait_ref,
702 vtable_item,
703 impl_kind,
704 )
705 }
706
707 pub fn translate_trait_impl_vtable(
710 &mut self,
711 span: Span,
712 trait_ref: &hax::TraitRef<'tcx>,
713 vtable_item: &hax::ItemRef<'tcx>,
714 impl_kind: TransImplSource,
715 ) -> Result<VTableDecl, Error> {
716 let Some(vtable_struct) = self.translate_vtable_struct_ref_no_enqueue(span, trait_ref)?
717 else {
718 return Ok(VTableDecl::NotDynCompatible);
719 };
720 let struct_name = &self.translated.item_names[&ItemId::Type(vtable_struct.id)];
722 if self.opacity_for_name(struct_name).is_invisible() {
723 return Ok(VTableDecl::Unknown(
724 "the vtable struct of the trait is excluded".into(),
725 ));
726 }
727 let vtable = self
728 .translate_vtable_instance_ref_maybe_enqueue(
729 self.options.eager_vtables,
730 span,
731 trait_ref,
732 vtable_item,
733 impl_kind,
734 )?
735 .unwrap();
736
737 if self.translated.global_decls.get(vtable.id).is_none() {
738 Ok(VTableDecl::Lazy)
739 } else {
740 Ok(VTableDecl::VTable(vtable))
741 }
742 }
743
744 pub fn translate_vtable_instance_ref_maybe_enqueue(
745 &mut self,
746 enqueue: bool,
747 span: Span,
748 trait_ref: &hax::TraitRef<'tcx>,
749 vtable_item: &hax::ItemRef<'tcx>,
750 impl_kind: TransImplSource,
751 ) -> Result<Option<GlobalDeclRef>, Error> {
752 if !self.trait_is_dyn_compatible(&trait_ref.def_id) {
753 return Ok(None);
754 }
755 let vtable_ref: GlobalDeclRef = self.translate_item_maybe_enqueue(
760 span,
761 vtable_item,
762 TransItemSourceKind::VTableInstance(impl_kind),
763 enqueue,
764 )?;
765 Ok(Some(vtable_ref))
766 }
767
768 fn get_vtable_instance_info(
770 &mut self,
771 span: Span,
772 impl_def: &hax::FullDef<'tcx>,
773 impl_kind: TransImplSource,
774 ) -> Result<(GlobalSource, TypeDeclRef), Error> {
775 let implemented_trait = self
776 .vtable_instance_data(impl_def, impl_kind)
777 .implemented_trait_ref;
778 let self_ty =
779 self.translate_ty(span, implemented_trait.generic_args[0].as_type().unwrap())?;
780 let vtable_struct_ref = self.translate_vtable_struct_ref(span, implemented_trait)?;
781 let impl_ref = if impl_kind == TransImplSource::Marker || self.monomorphize() {
782 None
783 } else {
784 Some(self.translate_item(
785 span,
786 impl_def.this(),
787 TransItemSourceKind::TraitImpl(impl_kind),
788 )?)
789 };
790 Ok((
791 GlobalSource::VTableInstance { impl_ref, self_ty },
792 vtable_struct_ref,
793 ))
794 }
795
796 pub(crate) fn translate_vtable_instance(
811 mut self,
812 global_id: GlobalDeclId,
813 item_meta: ItemMeta,
814 impl_def: &hax::FullDef<'tcx>,
815 impl_kind: TransImplSource,
816 ) -> Result<GlobalDecl, Error> {
817 let span = item_meta.span;
818
819 if impl_kind != TransImplSource::Marker {
821 let impl_id: TraitImplId = self.register_item_maybe_enqueue(
822 span,
823 false,
824 impl_def.this(),
825 TransItemSourceKind::TraitImpl(impl_kind),
826 );
827 let vtable_ref = GlobalDeclRef {
828 id: global_id,
829 generics: Box::new(self.outermost_generics().identity_args()),
830 };
831 if let Some(timpl) = self.t_ctx.translated.trait_impls.get_mut(impl_id)
832 && timpl.vtable.is_lazy()
833 {
834 timpl.vtable = VTableDecl::VTable(vtable_ref);
835 }
836 }
837
838 let (src, vtable_struct_ref) = self.get_vtable_instance_info(span, impl_def, impl_kind)?;
839
840 let ty = Ty::new(TyKind::Adt(vtable_struct_ref.clone()));
841 let size = Size::from_expr(SizeExpr::size_of(&ty));
842 let align = Size::from_expr(SizeExpr::align_of(&ty));
843 let kind = if item_meta.opacity.with_private_contents().is_opaque() {
844 ConstantExprKind::Opaque("VTable was chosen to be opaque".to_string())
845 } else if matches!(
846 impl_kind,
847 TransImplSource::Marker | TransImplSource::Normal | TransImplSource::Callable(..)
848 ) {
849 self.gen_vtable_value(span, impl_def, vtable_struct_ref, impl_kind)?
850 } else {
851 ConstantExprKind::Opaque("Couldn't compute vtable field".to_string())
852 };
853 let value = ConstantExpr::new(kind, ty.clone());
854
855 Ok(GlobalDecl {
856 def_id: global_id,
857 item_meta,
858 generics: self.into_generics(),
859 src,
860 global_kind: GlobalKind::VTable,
861 ty,
862 size,
863 align,
864 ptr_metadata: ConstantExpr::mk_unit(),
865 value,
866 })
867 }
868
869 fn vtable_instance_data<'a>(
871 &self,
872 impl_def: &'a hax::FullDef<'tcx>,
873 impl_kind: TransImplSource,
874 ) -> VTableInstanceData<'tcx, 'a> {
875 match (impl_kind, impl_def.kind()) {
876 (TransImplSource::Callable(target_kind), _) => {
878 let vimpl = callable_virtual_impl(self.hax_state(), impl_def, target_kind);
879 let vtable_sig = vimpl
880 .vtable_sig(self.hax_state(), 0)
881 .expect("a callable with a vtable must be dyn-compatible");
882 VTableInstanceData {
883 implemented_trait_ref: &vimpl.trait_pred.trait_ref,
884 implied_trait_proofs: &vimpl.implied_trait_proofs,
885 methods: VTableMethodSource::FnTraitShim(
886 impl_def.this(),
887 impl_kind,
888 vtable_sig,
889 ),
890 }
891 }
892 (TransImplSource::Normal, hax::FullDefKind::TraitImpl(timpl)) => {
893 let methods: IndexVec<TraitMethodId, _> = timpl
896 .items(self.hax_state())
897 .iter()
898 .filter(|item| matches!(item.decl_def_id.kind, hax::DefKind::AssocFn))
899 .collect();
900 VTableInstanceData {
901 implemented_trait_ref: &timpl.trait_pred().trait_ref,
902 implied_trait_proofs: timpl.implied_trait_proofs(),
903 methods: VTableMethodSource::ImplMethods(methods),
904 }
905 }
906 (TransImplSource::Marker, hax::FullDefKind::Trait(t)) => VTableInstanceData {
907 implemented_trait_ref: &t.self_predicate().trait_ref,
908 implied_trait_proofs: t.implied_trait_proofs(self.hax_state()),
909 methods: VTableMethodSource::ImplMethods(IndexVec::new()),
910 },
911 _ => unreachable!(),
912 }
913 }
914
915 fn vtable_method_value(
917 &mut self,
918 span: Span,
919 trait_id: TraitDeclId,
920 method_id: TraitMethodId,
921 implemented_trait: &hax::TraitRef<'tcx>,
922 methods: &VTableMethodSource<'tcx, '_>,
923 ) -> Result<VtableMethodValue, Error> {
924 match methods {
925 VTableMethodSource::ImplMethods(methods) => {
926 let item = methods[method_id];
927 let item_ref = match &item.value {
929 Some(value) => value.skip_binder.item.clone(),
930 None => {
932 let hax_state = self.hax_state_with_id();
933 let trait_args = implemented_trait.rustc_args(hax_state);
934 hax::ItemRef::translate_from_hax_def_id(
935 hax_state,
936 item.decl_def_id.clone(),
937 trait_args,
938 )
939 }
940 };
941 let shim = self.translate_fn_ptr(
942 span,
943 &item_ref,
944 TransItemSourceKind::VTableMethod(TransImplSource::Normal),
945 )?;
946
947 if !self.monomorphize() {
950 return Ok(VtableMethodValue::Const(shim));
951 }
952
953 assert!(self.binding_levels.len() == 1);
957 let orginal_binding = self.binding_levels.pop();
958 let assoc_fun_def = self.hax_def(&item_ref)?;
959 self.translate_item_generics(
960 span,
961 &assoc_fun_def,
962 &TransItemSourceKind::VTableMethod(TransImplSource::Normal),
963 )?;
964 let vtable_sig = match assoc_fun_def.kind() {
965 hax::FullDefKind::AssocFn(f) => f.vtable_sig(self.hax_state()),
966 _ => None,
967 };
968 let Some(vtable_sig) = vtable_sig else {
969 unreachable!("MONO: only assoc fun is supported")
970 };
971
972 let signature = self.translate_fun_sig(span, &vtable_sig.value)?;
973 let method_ty = Ty::new(TyKind::FnPtr(RegionBinder {
975 regions: self.outermost_generics().regions.clone(),
976 outlives: self.outermost_generics().outlives.clone(),
977 skip_binder: signature,
978 }));
979
980 self.binding_levels.pop();
982 if let Some(binding_level) = orginal_binding {
983 self.binding_levels.push(binding_level);
984 }
985
986 self.mark_method_as_used(trait_id, method_id);
987 Ok(VtableMethodValue::Cast(method_ty, shim))
988 }
989 &VTableMethodSource::FnTraitShim(item, impl_source, vtable_sig) => {
990 let shim = self.translate_fn_ptr(
991 span,
992 item,
993 TransItemSourceKind::VTableMethod(impl_source),
994 )?;
995 if !self.monomorphize() {
996 return Ok(VtableMethodValue::Const(shim));
997 }
998 let bound_sig = self.translate_region_binder(span, vtable_sig, |ctx, sig| {
1001 ctx.translate_fun_sig(span, sig)
1002 })?;
1003 let method_ty = TyKind::FnPtr(bound_sig).into_ty();
1004 Ok(VtableMethodValue::Cast(method_ty, shim))
1005 }
1006 }
1007 }
1008
1009 fn gen_vtable_value(
1011 &mut self,
1012 span: Span,
1013 impl_def: &hax::FullDef<'tcx>,
1014 vtable_struct_ref: TypeDeclRef,
1015 impl_kind: TransImplSource,
1016 ) -> Result<ConstantExprKind, Error> {
1017 let VTableInstanceData {
1018 implemented_trait_ref,
1019 implied_trait_proofs,
1020 methods,
1021 } = self.vtable_instance_data(impl_def, impl_kind);
1022
1023 let trait_def = self.hax_def(implemented_trait_ref)?;
1024 let poly_trait_def = self.poly_hax_def(&implemented_trait_ref.def_id)?;
1026 let hax::FullDefKind::Trait(poly_trait) = poly_trait_def.kind() else {
1027 unreachable!()
1028 };
1029
1030 let implemented_trait = self.translate_trait_decl_ref(span, implemented_trait_ref)?;
1031 let trait_id = implemented_trait.id;
1032 let self_ty = &implemented_trait.generics.types[0];
1034
1035 let vtable_data =
1036 self.prepare_vtable_fields(&poly_trait_def, trait_id, poly_trait.implied_predicates())?;
1037 let field_tys = {
1040 let ItemRef::Type(vtable_def) =
1041 self.t_ctx.get_or_translate(vtable_struct_ref.id.into())?
1042 else {
1043 unreachable!()
1044 };
1045 let fields = match &vtable_def.kind {
1046 TypeDeclKind::Struct(fields) => fields,
1047 TypeDeclKind::Opaque => {
1048 return Ok(ConstantExprKind::Opaque(
1049 "VTable was chosen to be opaque".to_string(),
1050 ));
1051 }
1052 TypeDeclKind::Error(error) => return Err(Error::new(span, error.clone())),
1053 _ => unreachable!(),
1054 };
1055 fields
1056 .iter()
1057 .map(|f| &f.ty)
1058 .cloned()
1059 .map(|ty| ty.substitute(&vtable_struct_ref.generics))
1060 .collect_vec()
1061 };
1062
1063 let mut aggregate_fields = IndexVec::new();
1065 for (field, ty) in vtable_data.fields.into_iter().zip(field_tys) {
1066 let mk = |kind| ConstantExpr::new(kind, ty.clone());
1067 let constant = match field {
1068 TrVTableField::Size => mk(ConstantExprKind::SizeOf(self_ty.clone())),
1069 TrVTableField::Align => mk(ConstantExprKind::AlignOf(self_ty.clone())),
1070 TrVTableField::Drop => {
1071 let drop_shim = self.translate_item(
1072 span,
1073 impl_def.this(),
1074 TransItemSourceKind::VTableDropShim(impl_kind),
1075 )?;
1076 if self.monomorphize() {
1077 let hax::FullDefKind::Trait(trait_def) = trait_def.kind() else {
1078 unreachable!()
1079 };
1080 let dyn_self = trait_def
1081 .dyn_self()
1082 .expect("vtable trait must be dyn-compatible");
1083 let dyn_self = self.translate_ty(span, dyn_self)?;
1084 let shim_ty = TyKind::FnPtr(self.drop_glue_fn_ptr_sig(dyn_self)).into_ty();
1085 let shim =
1086 ConstantExpr::new(ConstantExprKind::FnPtr(drop_shim), shim_ty.clone());
1087 mk(ConstantExprKind::Cast(shim, CastKind::RawPtr(ty.clone())))
1088 } else {
1089 mk(ConstantExprKind::FnPtr(drop_shim))
1090 }
1091 }
1092 TrVTableField::Method(method_id, ..) => {
1093 let value = self.vtable_method_value(
1094 span,
1095 trait_id,
1096 method_id,
1097 implemented_trait_ref,
1098 &methods,
1099 )?;
1100 match value {
1101 VtableMethodValue::Const(method) => mk(ConstantExprKind::FnPtr(method)),
1102 VtableMethodValue::Cast(cast_ty, method) => {
1103 let method =
1104 ConstantExpr::new(ConstantExprKind::FnPtr(method), cast_ty.clone());
1105 mk(ConstantExprKind::Cast(method, CastKind::RawPtr(ty.clone())))
1106 }
1107 }
1108 }
1109 TrVTableField::SuperTrait(clause_id, _) => {
1110 let trait_proof = &implied_trait_proofs[clause_id.index()];
1111 self.translate_vtable_instance_const(span, trait_proof)?
1112 }
1113 };
1114 aggregate_fields.push(constant);
1115 }
1116
1117 Ok(ConstantExprKind::Adt(None, aggregate_fields))
1118 }
1119
1120 fn translate_vtable_shim_body(
1145 &mut self,
1146 span: Span,
1147 target_receiver: &Ty,
1148 shim_signature: &FunSig,
1149 receiver_is_by_value: bool,
1150 receiver_path: MetadataPath,
1151 target_fn: FnPtr,
1152 ) -> Result<Body, Error> {
1153 let mut builder = BodyBuilder::new(span, shim_signature.inputs.len());
1154
1155 let ret_place = builder.new_var(None, shim_signature.output.clone());
1156 let mut method_args = shim_signature
1157 .inputs
1158 .iter()
1159 .map(|ty| builder.new_var(None, ty.clone()))
1160 .collect_vec();
1161
1162 let cast_target_ty = if receiver_is_by_value {
1163 TyKind::RawPtr(target_receiver.clone(), RefKind::Mut).into_ty()
1164 } else {
1165 target_receiver.clone()
1166 };
1167 let target_self = builder.new_var(None, cast_target_ty);
1168
1169 let receiver_arg = if receiver_is_by_value {
1171 target_self.clone().deref()
1172 } else {
1173 target_self.clone()
1174 };
1175 let shim_self = mem::replace(&mut method_args[0], receiver_arg);
1176
1177 let rval = Rvalue::UnaryOp(
1181 UnOp::Cast(CastKind::Concretize(
1182 target_self.ty().clone(),
1183 receiver_path,
1184 )),
1185 Operand::Move(shim_self.clone()),
1186 );
1187 builder.push_statement(StatementKind::Assign(target_self.clone(), rval));
1188
1189 builder.call(
1190 ret_place,
1191 Call {
1192 func: FnOperand::Regular(target_fn),
1193 args: method_args.into_iter().map(Operand::Move).collect(),
1194 safety: CallSafety::Inherit,
1195 },
1196 );
1197
1198 Ok(Body::Unstructured(builder.build()))
1199 }
1200
1201 fn translate_vtable_drop_shim_body(
1213 &mut self,
1214 span: Span,
1215 shim_receiver: &Ty,
1216 target_receiver: &Ty,
1217 trait_pred: &TraitPredicate<'tcx>,
1218 ) -> Result<Body, Error> {
1219 let mut builder = BodyBuilder::new(span, 1);
1220
1221 builder.new_var(Some("ret".into()), Ty::mk_unit());
1222 let dyn_self = builder.new_var(Some("dyn_self".into()), shim_receiver.clone());
1223 let target_self = builder.new_var(Some("target_self".into()), target_receiver.clone());
1224
1225 let rval = Rvalue::UnaryOp(
1227 UnOp::Cast(CastKind::Concretize(target_self.ty().clone(), vec![])),
1228 Operand::Move(dyn_self.clone()),
1229 );
1230 builder.push_statement(StatementKind::Assign(target_self.clone(), rval));
1231
1232 let rustc_trait_args = trait_pred.trait_ref.rustc_args(self.hax_state_with_id());
1233 let rustc_self_ty = rustc_trait_args[0].as_type().unwrap();
1234 let fn_ptr = self.translate_drop_glue_method_call(span, rustc_self_ty)?;
1235
1236 let drop_arg = target_self.clone().deref();
1238 builder.insert_drop(drop_arg, fn_ptr);
1239
1240 Ok(Body::Unstructured(builder.build()))
1241 }
1242
1243 pub(crate) fn translate_vtable_drop_shim(
1244 mut self,
1245 fun_id: FunDeclId,
1246 item_meta: ItemMeta,
1247 impl_def: &hax::FullDef<'tcx>,
1248 impl_kind: TransImplSource,
1249 ) -> Result<FunDecl, Error> {
1250 let span = item_meta.span;
1251
1252 let (dyn_self, trait_pred) = match (impl_kind, impl_def.kind()) {
1253 (TransImplSource::Callable(target_kind), _) => {
1255 let vimpl = callable_virtual_impl(self.hax_state(), impl_def, target_kind);
1256 (vimpl.dyn_self(self.hax_state()), &vimpl.trait_pred)
1257 }
1258 (TransImplSource::Normal, hax::FullDefKind::TraitImpl(timpl)) => {
1259 (timpl.dyn_self(self.hax_state()), timpl.trait_pred())
1260 }
1261 (TransImplSource::Marker, hax::FullDefKind::Trait(t)) => {
1262 (t.dyn_self().cloned(), t.self_predicate())
1263 }
1264 _ => unreachable!(),
1265 };
1266 let Some(dyn_self) = dyn_self else {
1267 raise_error!(
1268 self,
1269 span,
1270 "Trying to generate a vtable drop shim for a non-dyn-compatible trait"
1271 );
1272 };
1273
1274 let borrow_region = self.drop_glue_region();
1275
1276 let dyn_self = self.translate_ty(span, &dyn_self)?;
1277 let signature = self.drop_glue_method_sig(dyn_self.clone(), borrow_region.clone());
1279
1280 let target_self_ref = {
1282 let impl_trait = self.translate_trait_ref(span, &trait_pred.trait_ref)?;
1283 TyKind::Ref(
1284 borrow_region,
1285 impl_trait.generics.types[0].clone(),
1286 RefKind::Mut,
1287 )
1288 .into_ty()
1289 };
1290
1291 let body: Body = self.translate_vtable_drop_shim_body(
1292 span,
1293 &signature.inputs[0],
1294 &target_self_ref,
1295 trait_pred,
1296 )?;
1297
1298 Ok(FunDecl {
1299 def_id: fun_id,
1300 item_meta,
1301 generics: self.into_generics(),
1302 signature: Box::new(signature),
1303 src: FunSource::VTableShim,
1304 body,
1305 })
1306 }
1307
1308 pub(crate) fn translate_vtable_shim(
1309 mut self,
1310 fun_id: FunDeclId,
1311 item_meta: ItemMeta,
1312 def: &hax::FullDef<'tcx>,
1313 impl_kind: TransImplSource,
1314 ) -> Result<FunDecl, Error> {
1315 let span = item_meta.span;
1316
1317 let signature: FunSig;
1318 let target_receiver: Ty;
1320 let receiver_is_by_value: bool;
1321 let receiver_path: MetadataPath;
1323 let target_item: TransItemSourceKind;
1325
1326 if let TransImplSource::Callable(target_kind) = impl_kind {
1327 let vimpl = callable_virtual_impl(self.hax_state(), def, target_kind);
1328 let vtable_sig = vimpl
1329 .vtable_sig(self.hax_state(), 0)
1330 .expect("a callable with a vtable must be dyn-compatible");
1331 signature = {
1334 let bound_sig = self.translate_region_binder(span, vtable_sig, |ctx, sig| {
1335 ctx.translate_fun_sig(span, sig)
1336 })?;
1337 bound_sig.apply(
1338 self.the_only_binder()
1339 .closure_call_method_region
1340 .iter()
1341 .map(|r| Region::Var(DeBruijnVar::new_at_zero(*r)))
1342 .collect(),
1343 )
1344 };
1345 target_receiver = {
1347 let hax::GenericArg::Type(self_ty) = &vimpl.trait_pred.trait_ref.generic_args[0]
1348 else {
1349 unreachable!("no `Self` type arg on a `Fn*` trait ref")
1350 };
1351 let state_ty = self.translate_ty(span, self_ty)?;
1352 match target_kind {
1353 ClosureKind::FnOnce => state_ty,
1354 ClosureKind::Fn | ClosureKind::FnMut => {
1355 let rid = self.the_only_binder().closure_call_method_region.unwrap();
1356 let region = Region::Var(DeBruijnVar::new_at_zero(rid));
1357 let mutability = RefKind::mutable(target_kind == ClosureKind::FnMut);
1358 TyKind::Ref(region, state_ty, mutability).into_ty()
1359 }
1360 }
1361 };
1362 receiver_is_by_value = target_kind == ClosureKind::FnOnce;
1363 receiver_path = vec![];
1364 target_item = TransItemSourceKind::CallableMethod(target_kind);
1365 } else {
1366 let hax::FullDefKind::AssocFn(f) = def.kind() else {
1367 raise_error!(
1368 self,
1369 span,
1370 "Trying to generate a vtable shim for a non-vtable-safe method"
1371 );
1372 };
1373 let Some(vtable_sig) = f.vtable_sig(self.hax_state()) else {
1374 raise_error!(
1375 self,
1376 span,
1377 "Trying to generate a vtable shim for a non-vtable-safe method"
1378 );
1379 };
1380 signature = self.translate_fun_sig(span, &vtable_sig.value)?;
1381 target_receiver = self.translate_ty(span, &f.sig().value.inputs[0])?;
1382 receiver_is_by_value = hax::vtable_receiver_is_by_value(
1383 self.tcx,
1384 f.associated_item()
1385 .implemented_trait_item_id()
1386 .real_rust_def_id(),
1387 );
1388 receiver_path = self.translate_metadata_path(&f.vtable_receiver_path(self.hax_state()));
1389 target_item = TransItemSourceKind::Fun;
1390 };
1391
1392 trace!(
1393 "[VtableShim] Obtained dyn signature with receiver type: {}",
1394 signature.inputs[0].with_ctx(&self.into_fmt())
1395 );
1396
1397 let body = if item_meta.opacity.with_private_contents().is_opaque() {
1398 Body::Opaque
1399 } else {
1400 let fun_id = self.register_item(span, def.this(), target_item);
1401 let target_fn = FnPtr::new(
1402 FnPtrKind::Fun(fun_id),
1403 self.outermost_binder().params.identity_args(),
1404 );
1405 self.translate_vtable_shim_body(
1406 span,
1407 &target_receiver,
1408 &signature,
1409 receiver_is_by_value,
1410 receiver_path,
1411 target_fn,
1412 )?
1413 };
1414
1415 Ok(FunDecl {
1416 def_id: fun_id,
1417 item_meta,
1418 generics: self.into_generics(),
1419 signature: Box::new(signature),
1420 src: FunSource::VTableShim,
1421 body,
1422 })
1423 }
1424}