1use crate::hax;
2use crate::hax::TraitPredicate;
3use charon_lib::ast::ullbc_ast_utils::BodyBuilder;
4use itertools::Itertools;
5use rustc_span::kw;
6use std::mem;
7
8use super::{
9 translate_crate::TransItemSourceKind, translate_ctx::*, translate_generics::BindingLevel,
10};
11use charon_lib::formatter::IntoFormatter;
12use charon_lib::ids::IndexVec;
13use charon_lib::pretty::FmtWithCtx;
14use charon_lib::ullbc_ast::*;
15
16fn usize_ty() -> Ty {
17 Ty::new(TyKind::Literal(LiteralTy::UInt(UIntTy::Usize)))
18}
19
20enum VtableMethodValue {
24 Const(ConstantExprKind),
25 Cast((String, Ty, FnPtr)),
27}
28
29fn dynify<T: TyVisitable>(mut x: T, new_self: Option<Ty>, for_method: bool) -> T {
37 struct ReplaceSelfVisitor {
38 new_self: Option<Ty>,
39 for_method: bool,
40 }
41 impl VarsVisitor for ReplaceSelfVisitor {
42 fn visit_type_var(&mut self, v: TypeDbVar) -> Option<Ty> {
43 if let DeBruijnVar::Bound(DeBruijnId::ZERO, type_id) = v {
44 Some(if let Some(new_id) = type_id.index().checked_sub(1) {
46 TyKind::TypeVar(DeBruijnVar::Bound(DeBruijnId::ZERO, TypeVarId::new(new_id)))
47 .into_ty()
48 } else {
49 self.new_self.clone().expect(
50 "Found unexpected `Self`
51 type when constructing vtable",
52 )
53 })
54 } else {
55 None
56 }
57 }
58
59 fn visit_clause_var(&mut self, v: ClauseDbVar) -> Option<TraitRefKind> {
60 if let DeBruijnVar::Bound(DeBruijnId::ZERO, clause_id) = v {
61 if self.for_method && clause_id == TraitClauseId::ZERO {
62 Some(TraitRefKind::Dyn)
64 } else {
65 panic!("Found unexpected clause var when constructing vtable: {v}")
66 }
67 } else {
68 None
69 }
70 }
71
72 fn visit_self_clause(&mut self) -> Option<TraitRefKind> {
73 Some(TraitRefKind::Dyn)
74 }
75 }
76 x.visit_vars(&mut ReplaceSelfVisitor {
77 new_self,
78 for_method,
79 });
80 x
81}
82
83impl<'tcx> ItemTransCtx<'tcx, '_> {
85 pub fn check_at_most_one_pred_has_methods(
86 &mut self,
87 span: Span,
88 preds: &hax::GenericPredicates,
89 ) -> Result<(), Error> {
90 for pred in preds.predicates.iter().skip(1) {
92 if let hax::ClauseKind::Trait(trait_predicate) = pred.clause.kind.hax_skip_binder_ref()
93 {
94 let trait_def_id = &trait_predicate.trait_ref.def_id;
95 let trait_def = self.poly_hax_def(trait_def_id)?;
96 let has_methods = match trait_def.kind() {
97 hax::FullDefKind::Trait { items, .. } => items
98 .iter()
99 .any(|assoc| matches!(assoc.kind, hax::AssocKind::Fn { .. })),
100 hax::FullDefKind::TraitAlias { .. } => false,
101 _ => unreachable!(),
102 };
103 if has_methods {
104 raise_error!(
105 self,
106 span,
107 "`dyn Trait` with multiple method-bearing predicates is not supported"
108 );
109 }
110 }
111 }
112 Ok(())
113 }
114
115 pub fn translate_dyn_binder<T, U>(
116 &mut self,
117 span: Span,
118 binder: &hax::DynBinder<T>,
119 f: impl FnOnce(&mut Self, Ty, &T) -> Result<U, Error>,
120 ) -> Result<Binder<U>, Error> {
121 self.check_at_most_one_pred_has_methods(span, &binder.predicates)?;
125
126 self.binding_levels.push(BindingLevel::new());
128
129 let ty_id = self
131 .innermost_binder_mut()
132 .push_type_var(binder.existential_ty.index, binder.existential_ty.name);
133 let ty = TyKind::TypeVar(DeBruijnVar::new_at_zero(ty_id)).into_ty();
134
135 self.register_predicates(&binder.predicates, PredicateOrigin::Dyn)?;
136
137 let val = f(self, ty, &binder.val)?;
138
139 if self.monomorphize() {
144 struct ShiftDynClauseVars;
145 impl VarsVisitor for ShiftDynClauseVars {
146 fn visit_clause_var(&mut self, v: ClauseDbVar) -> Option<TraitRefKind> {
147 if let DeBruijnVar::Bound(DeBruijnId::ZERO, clause_id) = v
148 && let Some(new_id) = clause_id.index().checked_sub(1)
149 {
150 return Some(TraitRefKind::Clause(DeBruijnVar::Bound(
151 DeBruijnId::ZERO,
152 TraitClauseId::new(new_id),
153 )));
154 }
155 None
156 }
157 }
158
159 self.innermost_generics_mut()
160 .trait_type_constraints
161 .iter_mut()
162 .for_each(|pred| pred.visit_vars(&mut ShiftDynClauseVars));
163 }
164
165 let params = self.binding_levels.pop().unwrap().params;
166 Ok(Binder {
167 params,
168 skip_binder: val,
169 kind: BinderKind::Dyn,
170 })
171 }
172}
173
174#[derive(Debug)]
177pub enum TrVTableField {
178 Size,
179 Align,
180 Drop,
181 Method(TraitMethodId, hax::Binder<hax::TyFnSig>),
182 SuperTrait(TraitClauseId, hax::Clause),
183}
184
185pub struct VTableData {
186 pub fields: IndexVec<FieldId, TrVTableField>,
187 pub supertrait_map: IndexVec<TraitClauseId, Option<FieldId>>,
188}
189
190impl<'tcx> ItemTransCtx<'tcx, '_> {
192 pub fn trait_is_dyn_compatible(&mut self, def_id: &hax::DefId) -> Result<bool, Error> {
196 let def = self.poly_hax_def(def_id)?;
197 Ok(match def.kind() {
198 hax::FullDefKind::Trait { dyn_self, .. }
199 | hax::FullDefKind::TraitAlias { dyn_self, .. } => dyn_self.is_some(),
200 _ => false,
201 })
202 }
203
204 fn pred_is_for_self(&self, tref: &hax::TraitRef) -> bool {
206 let first_ty = tref
207 .generic_args
208 .iter()
209 .filter_map(|arg| match arg {
210 hax::GenericArg::Type(ty) => Some(ty),
211 _ => None,
212 })
213 .next();
214 match first_ty {
215 None => false,
216 Some(first_ty) => match first_ty.kind() {
217 hax::TyKind::Param(param_ty) if param_ty.index == 0 => {
218 assert_eq!(param_ty.name, kw::SelfUpper);
219 true
220 }
221 _ => false,
222 },
223 }
224 }
225
226 pub fn translate_vtable_struct_ref(
227 &mut self,
228 span: Span,
229 tref: &hax::TraitRef,
230 ) -> Result<TypeDeclRef, Error> {
231 Ok(self
232 .translate_vtable_struct_ref_maybe_enqueue(true, span, tref)?
233 .expect("trait should be dyn-compatible"))
234 }
235
236 pub fn translate_vtable_struct_ref_no_enqueue(
237 &mut self,
238 span: Span,
239 tref: &hax::TraitRef,
240 ) -> Result<Option<TypeDeclRef>, Error> {
241 self.translate_vtable_struct_ref_maybe_enqueue(false, span, tref)
242 }
243
244 pub fn translate_vtable_struct_ref_maybe_enqueue(
246 &mut self,
247 enqueue: bool,
248 span: Span,
249 tref: &hax::TraitRef,
250 ) -> Result<Option<TypeDeclRef>, Error> {
251 if !self.trait_is_dyn_compatible(&tref.def_id)? {
252 return Ok(None);
253 }
254
255 if self.monomorphize() {
257 let item_src =
258 TransItemSource::monomorphic_trait(&tref.def_id, TransItemSourceKind::VTable);
259 let id: ItemId = self.register_and_enqueue(span, item_src);
260 let id = id
261 .try_into()
262 .expect("translated trait decl should be a trait decl id");
263 return Ok(Some(TypeDeclRef {
264 id,
265 generics: Box::new(GenericArgs::empty()),
266 }));
267 }
268
269 let mut vtable_ref: TypeDeclRef =
272 self.translate_item_maybe_enqueue(span, tref, TransItemSourceKind::VTable, enqueue)?;
273 vtable_ref
275 .generics
276 .types
277 .remove_and_shift_ids(TypeVarId::ZERO);
278
279 let assoc_tys: Vec<_> = tref
281 .trait_associated_types(self.hax_state_with_id())
282 .iter()
283 .map(|ty| self.translate_ty(span, ty))
284 .try_collect()?;
285 vtable_ref.generics.types.extend(assoc_tys);
286
287 Ok(Some(vtable_ref))
288 }
289
290 fn prepare_vtable_fields(
291 &mut self,
292 poly_trait_def: &hax::FullDef<'tcx>,
293 trait_id: TraitDeclId,
294 implied_predicates: &hax::GenericPredicates,
295 ) -> Result<VTableData, Error> {
296 let mut supertrait_map: IndexVec<TraitClauseId, _> =
297 (0..implied_predicates.predicates.len())
298 .map(|_| None)
299 .collect();
300 let mut fields = IndexVec::new();
301
302 fields.push(TrVTableField::Size);
304 fields.push(TrVTableField::Align);
305 fields.push(TrVTableField::Drop);
306
307 if let hax::FullDefKind::Trait { items, .. } = poly_trait_def.kind() {
309 for item in items {
310 let item_def_id = &item.def_id;
311 let poly_item_def = self.poly_hax_def(item_def_id)?;
313 if let hax::FullDefKind::AssocFn {
314 sig,
315 vtable_sig: Some(_),
316 ..
317 } = poly_item_def.kind()
318 {
319 let id = self.translate_trait_method_id_no_enqueue(trait_id, item_def_id)?;
320 fields.push(TrVTableField::Method(id, sig.clone()));
321 }
322 }
323 }
324
325 for (i, pred) in implied_predicates.iter_trait_clauses().enumerate() {
327 let trait_clause_id = TraitClauseId::from_raw(i); let clause = &pred.clause;
329 let hax::ClauseKind::Trait(pred) = clause.kind.hax_skip_binder_ref() else {
330 unreachable!()
331 };
332 if self.pred_is_for_self(&pred.trait_ref) {
334 if !self.trait_is_dyn_compatible(&pred.trait_ref.def_id)? {
335 self.assert_is_destruct(&pred.trait_ref);
337 continue;
338 }
339 supertrait_map[trait_clause_id] = Some(fields.next_idx());
340 fields.push(TrVTableField::SuperTrait(trait_clause_id, clause.clone()));
341 }
342 }
343
344 Ok(VTableData {
345 fields,
346 supertrait_map,
347 })
348 }
349
350 fn assert_is_destruct(&self, tref: &hax::TraitRef) {
356 assert!(
357 tref.def_id
358 .as_real_def_id()
359 .is_some_and(|id| self.tcx.is_lang_item(id, rustc_hir::LangItem::Destruct)),
360 "unexpected non-dyn compatible supertrait: {:?}",
361 tref.def_id
362 );
363 }
364
365 fn gen_vtable_struct_fields(
366 &mut self,
367 span: Span,
368 self_trait_ref: &TraitRef,
369 vtable_data: &VTableData,
370 ) -> Result<IndexVec<FieldId, Field>, Error> {
371 let mut fields = IndexVec::new();
372 let mut supertrait_counter = 0..;
373 for field in &vtable_data.fields {
374 let (name, ty) = match field {
375 TrVTableField::Size => ("size".into(), usize_ty()),
376 TrVTableField::Align => ("align".into(), usize_ty()),
377 TrVTableField::Drop => {
378 if self.monomorphize() {
380 let erased_ptr_ty = Ty::new(TyKind::RawPtr(Ty::mk_unit(), RefKind::Shared));
381 ("drop".into(), erased_ptr_ty)
382 } else {
383 let self_ty =
384 TyKind::TypeVar(DeBruijnVar::new_at_zero(TypeVarId::ZERO)).into_ty();
385 let drop_ty = Ty::new(TyKind::FnPtr(self.drop_glue_fn_ptr_sig(self_ty)));
386 ("drop".into(), drop_ty)
387 }
388 }
389 TrVTableField::Method(item_id, sig) => {
390 let item_name = self
391 .translated
392 .assoc_item_name(self_trait_ref.trait_id(), *item_id);
393 let field_name = format!("method_{}", item_name.0);
394 if self.monomorphize() {
396 let erased_ptr_ty = Ty::new(TyKind::RawPtr(Ty::mk_unit(), RefKind::Shared));
397 (field_name, erased_ptr_ty)
398 } else {
399 let bound_sig = self.inside_binder(BinderKind::Other, |ctx| {
402 ctx.innermost_binder_mut()
403 .trait_preds
404 .insert(hax::GenericPredicateId::TraitSelf, TraitClauseId::ZERO);
405 ctx.translate_poly_fun_sig(span, sig)
406 })?;
407 let sig = bound_sig.apply(&{
408 let mut generics = GenericArgs::empty();
409 generics.trait_refs.push(self_trait_ref.clone());
411 generics
412 });
413 let ty = TyKind::FnPtr(sig).into_ty();
414 (field_name, ty)
415 }
416 }
417 TrVTableField::SuperTrait(_, clause) => {
418 let vtbl_struct =
419 self.translate_region_binder(span, &clause.kind, |ctx, kind| {
420 let hax::ClauseKind::Trait(pred) = kind else {
421 unreachable!()
422 };
423 ctx.translate_vtable_struct_ref(span, &pred.trait_ref)
424 })?;
425 let vtbl_struct = self.erase_region_binder(vtbl_struct);
426 let ty = Ty::new(TyKind::Ref(
427 Region::Static,
428 Ty::new(TyKind::Adt(vtbl_struct)),
429 RefKind::Shared,
430 ));
431 let name = format!("super_trait_{}", supertrait_counter.next().unwrap());
432 (name, ty)
433 }
434 };
435 fields.push(Field {
436 span,
437 attr_info: AttrInfo::dummy_public(),
438 name: Some(name),
439 ty,
440 });
441 }
442 Ok(fields)
443 }
444
445 pub(crate) fn translate_vtable_struct(
460 mut self,
461 type_id: TypeDeclId,
462 item_meta: ItemMeta,
463 trait_def: &hax::FullDef<'tcx>,
464 ) -> Result<TypeDecl, Error> {
465 let mono = self.monomorphize();
466 let span = item_meta.span;
467 if !self.trait_is_dyn_compatible(trait_def.def_id())? {
468 raise_error!(
469 self,
470 span,
471 "Trying to compute the vtable type \
472 for a non-dyn-compatible trait"
473 );
474 }
475
476 let (hax::FullDefKind::Trait {
477 self_predicate,
478 dyn_self,
479 implied_predicates,
480 ..
481 }
482 | hax::FullDefKind::TraitAlias {
483 self_predicate,
484 dyn_self,
485 implied_predicates,
486 ..
487 }) = trait_def.kind()
488 else {
489 panic!()
490 };
491 let Some(dyn_self) = dyn_self else {
492 panic!("Trying to generate a vtable for a non-dyn-compatible trait")
493 };
494
495 let self_trait_ref = TraitRef::new(
496 TraitRefKind::SelfId,
497 RegionBinder::empty(self.translate_trait_predicate(span, self_predicate)?),
498 );
499 let trait_id = self_trait_ref.trait_id();
500
501 let mut field_map = IndexVec::new();
502 let mut supertrait_map: IndexVec<TraitClauseId, _> =
503 (0..implied_predicates.predicates.len())
504 .map(|_| None)
505 .collect();
506 let (mut kind, layout) = if item_meta.opacity.with_private_contents().is_opaque() {
507 (TypeDeclKind::Opaque, SeqHashMap::default())
508 } else {
509 let vtable_data =
512 self.prepare_vtable_fields(trait_def, trait_id, implied_predicates)?;
513 let fields = self.gen_vtable_struct_fields(span, &self_trait_ref, &vtable_data)?;
514
515 let kind = TypeDeclKind::Struct(fields);
516 let l = self.generate_naive_layout(span, &kind)?;
517 supertrait_map = vtable_data.supertrait_map;
518 field_map = vtable_data.fields.map_ref(|tr_field| match *tr_field {
519 TrVTableField::Size => VTableField::Size,
520 TrVTableField::Align => VTableField::Align,
521 TrVTableField::Drop => VTableField::Drop,
522 TrVTableField::Method(id, ..) => VTableField::Method(id),
523 TrVTableField::SuperTrait(clause_id, ..) => VTableField::SuperTrait(clause_id),
524 });
525 let layout = [(self.get_target_triple(), l)].into();
526 (kind, layout)
527 };
528
529 let mut generics = Default::default();
530
531 let dyn_predicate = if mono {
532 DynPredicate {
533 binder: Binder {
534 params: GenericParams::empty(),
535 skip_binder: TyKind::Error(
536 "mono vtable dyn predicate is intentionally erased".to_string(),
537 )
538 .into_ty(),
539 kind: BinderKind::Dyn,
540 },
541 }
542 } else {
543 let mut dyn_self = {
546 let dyn_self = self.translate_ty(span, dyn_self)?;
547 let TyKind::DynTrait(mut dyn_pred) = dyn_self.kind().clone() else {
548 panic!("incorrect `dyn_self`")
549 };
550
551 for (i, ty_constraint) in dyn_pred
554 .binder
555 .params
556 .trait_type_constraints
557 .iter_mut()
558 .enumerate()
559 {
560 let name = format!("Ty{i}");
561 let new_ty = self
562 .the_only_binder_mut()
563 .params
564 .types
565 .push_with(|index| TypeParam { index, name });
566 let new_ty =
569 TyKind::TypeVar(DeBruijnVar::bound(DeBruijnId::new(2), new_ty)).into_ty();
570 ty_constraint.skip_binder.ty = new_ty;
571 }
572 TyKind::DynTrait(dyn_pred).into_ty()
573 };
574
575 generics = self.into_generics();
578 {
579 dyn_self = dynify(dyn_self, None, false);
580 generics = dynify(generics, Some(dyn_self.clone()), false);
581 kind = dynify(kind, Some(dyn_self.clone()), true);
582 generics.types.remove_and_shift_ids(TypeVarId::ZERO);
583 generics.types.iter_mut().for_each(|ty| {
584 ty.index -= 1;
585 });
586 }
587
588 dyn_self
589 .kind()
590 .as_dyn_trait()
591 .expect("incorrect `dyn_self`")
592 .clone()
593 };
594 Ok(TypeDecl {
595 def_id: type_id,
596 item_meta,
597 generics,
598 src: ItemSource::VTableTy {
599 dyn_predicate,
600 field_map,
601 supertrait_map,
602 },
603 kind,
604 layout,
605 ptr_metadata: PtrMetadata::None,
607 })
608 }
609}
610
611impl<'tcx> ItemTransCtx<'tcx, '_> {
613 pub fn translate_vtable_instance_const(
615 &mut self,
616 span: Span,
617 trait_proof: &hax::TraitProof,
618 ) -> Result<Box<ConstantExpr>, Error> {
619 let tref = trait_proof.pred.hax_skip_binder_ref();
620 if !self.trait_is_dyn_compatible(&tref.def_id)? {
621 raise_error!(
622 self,
623 span,
624 "Trait {:?} should be dyn-compatible",
625 tref.def_id
626 );
627 }
628
629 let vtbl_ty = {
630 let vtbl_ty = self.translate_region_binder(span, &trait_proof.pred, |ctx, tref| {
631 ctx.translate_vtable_struct_ref(span, tref)
632 })?;
633 let vtbl_ty = self.erase_region_binder(vtbl_ty);
634 TyKind::Adt(vtbl_ty).into_ty()
635 };
636 let ty = TyKind::Ref(Region::Static, vtbl_ty.clone(), RefKind::Shared).into_ty();
637
638 let kind = {
639 if let hax::TraitProofKind::Concrete(impl_item) = &trait_proof.kind {
640 let vtable_instance =
643 self.translate_region_binder(span, &trait_proof.pred, |ctx, tref| {
644 ctx.translate_vtable_instance_ref(span, tref, impl_item)
645 })?;
646 let vtable_instance = self.erase_region_binder(vtable_instance);
647 let vtable_instance = Box::new(ConstantExpr {
648 kind: ConstantExprKind::Global(vtable_instance),
649 ty: vtbl_ty,
650 });
651 ConstantExprKind::Ref(vtable_instance, None)
652 } else {
653 ConstantExprKind::VTableRef(self.translate_trait_proof(span, trait_proof)?)
654 }
655 };
656
657 Ok(Box::new(ConstantExpr { kind, ty }))
658 }
659
660 pub fn translate_vtable_instance_ref(
662 &mut self,
663 span: Span,
664 trait_ref: &hax::TraitRef,
665 impl_ref: &hax::ItemRef,
666 ) -> Result<GlobalDeclRef, Error> {
667 Ok(self
668 .translate_vtable_instance_ref_maybe_enqueue(true, span, trait_ref, impl_ref)?
669 .expect("trait should be dyn-compatible"))
670 }
671
672 pub fn translate_vtable_instance_ref_no_enqueue(
673 &mut self,
674 span: Span,
675 trait_ref: &hax::TraitRef,
676 impl_ref: &hax::ItemRef,
677 ) -> Result<Option<GlobalDeclRef>, Error> {
678 self.translate_vtable_instance_ref_maybe_enqueue(false, span, trait_ref, impl_ref)
679 }
680
681 pub fn translate_vtable_instance_ref_maybe_enqueue(
682 &mut self,
683 enqueue: bool,
684 span: Span,
685 trait_ref: &hax::TraitRef,
686 impl_ref: &hax::ItemRef,
687 ) -> Result<Option<GlobalDeclRef>, Error> {
688 if !self.trait_is_dyn_compatible(&trait_ref.def_id)? {
689 return Ok(None);
690 }
691 let vtable_ref: GlobalDeclRef = self.translate_item_maybe_enqueue(
696 span,
697 impl_ref,
698 TransItemSourceKind::VTableInstance(TraitImplSource::Normal),
699 enqueue,
700 )?;
701 Ok(Some(vtable_ref))
702 }
703
704 fn get_vtable_instance_info(
706 &mut self,
707 span: Span,
708 impl_def: &hax::FullDef<'tcx>,
709 impl_kind: &TraitImplSource,
710 ) -> Result<(Option<TraitImplRef>, TypeDeclRef), Error> {
711 let implemented_trait = match impl_def.kind() {
712 hax::FullDefKind::TraitImpl { trait_pred, .. } => &trait_pred.trait_ref,
713 _ => unreachable!(),
714 };
715 let vtable_struct_ref = self.translate_vtable_struct_ref(span, implemented_trait)?;
716 if self.monomorphize() {
717 return Ok((None, vtable_struct_ref));
718 }
719 let impl_ref = self.translate_item(
720 span,
721 impl_def.this(),
722 TransItemSourceKind::TraitImpl(*impl_kind),
723 )?;
724 Ok((Some(impl_ref), vtable_struct_ref))
725 }
726
727 pub(crate) fn translate_vtable_instance(
742 mut self,
743 global_id: GlobalDeclId,
744 item_meta: ItemMeta,
745 impl_def: &hax::FullDef<'tcx>,
746 impl_kind: &TraitImplSource,
747 ) -> Result<GlobalDecl, Error> {
748 let span = item_meta.span;
749
750 let (src, vtable_struct_ref) =
751 match self.get_vtable_instance_info(span, impl_def, impl_kind)? {
752 (Some(impl_ref), vtable_struct_ref) => {
753 (ItemSource::VTableInstance { impl_ref }, vtable_struct_ref)
754 }
755 (None, vtable_struct_ref) => (ItemSource::VTableInstanceMono, vtable_struct_ref),
756 };
757
758 let init = self.register_item(
760 span,
761 impl_def.this(),
762 TransItemSourceKind::VTableInstanceInitializer(*impl_kind),
763 );
764 let ty = Ty::new(TyKind::Adt(vtable_struct_ref));
765 let value = ConstantExpr {
766 kind: ConstantExprKind::Call(
767 FnPtr::new(
768 FnPtrKind::Fun(FunId::Regular(init)),
769 self.outermost_generics().identity_args(),
770 ),
771 vec![],
772 ),
773 ty: ty.clone(),
774 };
775
776 Ok(GlobalDecl {
777 def_id: global_id,
778 item_meta,
779 generics: self.into_generics(),
780 src,
781 global_kind: GlobalKind::Static,
783 ty,
784 value,
785 })
786 }
787
788 fn add_method_to_vtable_value(
789 &mut self,
790 span: Span,
791 trait_id: TraitDeclId,
792 item: &hax::ImplAssocItem,
793 ) -> Result<Option<VtableMethodValue>, Error> {
794 let item_def = self.poly_hax_def(&item.decl_def_id)?;
796 let hax::FullDefKind::AssocFn {
797 vtable_sig: Some(_),
798 ..
799 } = item_def.kind()
800 else {
801 return Ok(None);
802 };
803
804 let vtable_value = match &item.value {
806 Some(value) => {
807 let item_ref = &value.skip_binder.item;
808 let shim_ref =
809 self.translate_fn_ptr(span, item_ref, TransItemSourceKind::VTableMethod)?;
810 if self.monomorphize() {
814 assert!(self.binding_levels.len() == 1);
818 let orginal_binding = self.binding_levels.pop();
819 let assoc_fun_def = self.hax_def(item_ref)?;
820 self.translate_item_generics(
821 span,
822 &assoc_fun_def,
823 &TransItemSourceKind::VTableMethod,
824 )?;
825 let vtable_sig = match assoc_fun_def.kind() {
826 hax::FullDefKind::AssocFn {
827 vtable_sig: Some(vtable_sig),
828 ..
829 } => vtable_sig.clone(),
830 _ => unreachable!("MONO: only assoc fun is supported"),
831 };
832
833 let signature = self.translate_fun_sig(span, &vtable_sig.value)?;
834 let method_ty = Ty::new(TyKind::FnPtr(RegionBinder {
836 regions: self.outermost_generics().regions.clone(),
837 skip_binder: signature,
838 }));
839
840 self.binding_levels.pop();
842 if let Some(binding_level) = orginal_binding {
843 self.binding_levels.push(binding_level);
844 }
845
846 let method_id = self.translate_trait_method_id(trait_id, item.decl_def_id())?;
847 let method_name = self.translated.assoc_item_name(trait_id, method_id);
848
849 VtableMethodValue::Cast((method_name.to_string(), method_ty, shim_ref))
850 } else {
851 VtableMethodValue::Const(ConstantExprKind::FnPtr(shim_ref))
852 }
853 }
854 None => VtableMethodValue::Const(ConstantExprKind::Opaque(
855 "shim for default methods aren't yet supported".into(),
856 )),
857 };
858
859 Ok(Some(vtable_value))
860 }
861
862 fn gen_vtable_instance_init_body(
870 &mut self,
871 span: Span,
872 impl_def: &hax::FullDef<'tcx>,
873 vtable_struct_ref: TypeDeclRef,
874 ) -> Result<Body, Error> {
875 let hax::FullDefKind::TraitImpl {
876 trait_pred,
877 implied_trait_proofs,
878 items,
879 ..
880 } = impl_def.kind()
881 else {
882 unreachable!()
883 };
884
885 let trait_def = self.hax_def(&trait_pred.trait_ref)?;
886 let poly_trait_def = self.poly_hax_def(&trait_pred.trait_ref.def_id)?;
888 let hax::FullDefKind::Trait {
889 implied_predicates: implied_preds,
890 ..
891 } = poly_trait_def.kind()
892 else {
893 unreachable!()
894 };
895
896 let implemented_trait = self.translate_trait_decl_ref(span, &trait_pred.trait_ref)?;
897 let trait_id = implemented_trait.id;
898 let self_ty = &implemented_trait.generics.types[0];
900
901 let mut builder = BodyBuilder::new(span, 0);
902 let ret_ty = Ty::new(TyKind::Adt(vtable_struct_ref.clone()));
903 let ret_place = builder.new_var(Some("ret".into()), ret_ty.clone());
904
905 let vtable_data = self.prepare_vtable_fields(&poly_trait_def, trait_id, implied_preds)?;
906 let field_tys = {
909 let vtable_decl_id = *vtable_struct_ref.id.as_adt().unwrap();
910 let ItemRef::Type(vtable_def) = self.t_ctx.get_or_translate(vtable_decl_id.into())?
911 else {
912 unreachable!()
913 };
914 let fields = match &vtable_def.kind {
915 TypeDeclKind::Struct(fields) => fields,
916 TypeDeclKind::Opaque => return Ok(Body::Opaque),
917 TypeDeclKind::Error(error) => return Err(Error::new(span, error.clone())),
918 _ => unreachable!(),
919 };
920 fields
921 .iter()
922 .map(|f| &f.ty)
923 .cloned()
924 .map(|ty| ty.substitute(&vtable_struct_ref.generics))
925 .collect_vec()
926 };
927
928 let mut aggregate_fields = vec![];
930 let mut items_iter = items.iter();
931 for (field, ty) in vtable_data.fields.into_iter().zip(field_tys) {
932 let mk_const = |kind| {
934 Operand::Const(Box::new(ConstantExpr {
935 kind,
936 ty: ty.clone(),
937 }))
938 };
939 let mut mk_cast = |(method_name, method_ty, method_shim): (String, Ty, FnPtr)| {
963 let method_local = builder.new_var(Some(method_name.clone()), method_ty.clone());
964 let shim = Rvalue::Use(
965 Operand::Const(Box::new(ConstantExpr {
966 kind: ConstantExprKind::FnPtr(method_shim.clone()),
967 ty: method_ty.clone(),
968 })),
969 WithRetag::No,
970 );
971 let cast_local = builder.new_var(
972 Some("erased_".to_string() + method_name.as_str()),
973 ty.clone(),
974 );
975 let cast = Rvalue::UnaryOp(
976 UnOp::Cast(CastKind::RawPtr(
977 method_local.ty().clone(),
978 cast_local.ty().clone(),
979 )),
980 Operand::Move(method_local.clone()),
981 );
982
983 builder.push_statement(StatementKind::Assign(method_local.clone(), shim));
984 builder.push_statement(StatementKind::Assign(cast_local.clone(), cast));
985 Operand::Move(cast_local)
986 };
987 let op = match field {
988 TrVTableField::Size => {
989 let size_local = builder.new_var(Some("size".to_string()), ty);
990 builder.push_statement(StatementKind::Assign(
991 size_local.clone(),
992 Rvalue::NullaryOp(NullOp::SizeOf, self_ty.clone()),
993 ));
994 Operand::Move(size_local)
995 }
996 TrVTableField::Align => {
997 let align_local = builder.new_var(Some("align".to_string()), ty);
998 builder.push_statement(StatementKind::Assign(
999 align_local.clone(),
1000 Rvalue::NullaryOp(NullOp::AlignOf, self_ty.clone()),
1001 ));
1002 Operand::Move(align_local)
1003 }
1004 TrVTableField::Drop => {
1005 let drop_shim = self.translate_item(
1006 span,
1007 impl_def.this(),
1008 TransItemSourceKind::VTableDropShim,
1009 )?;
1010 if self.monomorphize() {
1011 let hax::FullDefKind::Trait { dyn_self, .. } = trait_def.kind() else {
1013 panic!()
1014 };
1015
1016 let Some(dyn_self) = dyn_self else {
1017 panic!(
1018 "MONO: Trying to generate a vtable for a non-dyn-compatible trait"
1019 )
1020 };
1021 let ref_dyn_self =
1022 TyKind::RawPtr(self.translate_ty(span, dyn_self)?, RefKind::Mut)
1023 .into_ty();
1024 let signature = FunSig {
1025 is_unsafe: true,
1026 abi: Abi::rust(),
1027 inputs: vec![ref_dyn_self.clone()],
1028 output: Ty::mk_unit(),
1029 };
1030 let drop_ty = Ty::new(TyKind::FnPtr(RegionBinder::empty(signature)));
1031
1032 mk_cast(("drop".to_string(), drop_ty.clone(), drop_shim))
1033 } else {
1034 mk_const(ConstantExprKind::FnPtr(drop_shim))
1035 }
1036 }
1037 TrVTableField::Method(..) => 'a: {
1038 for item in items_iter.by_ref() {
1041 if let Some(kind) = self.add_method_to_vtable_value(span, trait_id, item)? {
1042 match kind {
1043 VtableMethodValue::Const(const_kind) => {
1044 break 'a mk_const(const_kind);
1045 }
1046 VtableMethodValue::Cast(method) => break 'a mk_cast(method),
1047 }
1048 }
1049 }
1050 unreachable!()
1051 }
1052 TrVTableField::SuperTrait(clause_id, _) => {
1053 let trait_proof = &implied_trait_proofs[clause_id.index()];
1054 let vtable = self.translate_vtable_instance_const(span, trait_proof)?;
1055 Operand::Const(vtable)
1056 }
1057 };
1058 aggregate_fields.push(op);
1059 }
1060
1061 builder.push_statement(StatementKind::Assign(
1063 ret_place,
1064 Rvalue::Aggregate(
1065 AggregateKind::Adt(vtable_struct_ref.clone(), None, None),
1066 aggregate_fields,
1067 ),
1068 ));
1069
1070 Ok(Body::Unstructured(builder.build()))
1071 }
1072
1073 pub(crate) fn translate_vtable_instance_init(
1074 mut self,
1075 init_func_id: FunDeclId,
1076 item_meta: ItemMeta,
1077 impl_def: &hax::FullDef<'tcx>,
1078 impl_kind: &TraitImplSource,
1079 ) -> Result<FunDecl, Error> {
1080 let span = item_meta.span;
1081
1082 let (src, vtable_struct_ref) =
1083 match self.get_vtable_instance_info(span, impl_def, impl_kind)? {
1084 (Some(impl_ref), vtable_struct_ref) => {
1085 (ItemSource::VTableInstance { impl_ref }, vtable_struct_ref)
1086 }
1087 (None, vtable_struct_ref) => (ItemSource::VTableInstanceMono, vtable_struct_ref),
1088 };
1089
1090 let init_for = self.register_item(
1091 span,
1092 impl_def.this(),
1093 TransItemSourceKind::VTableInstance(*impl_kind),
1094 );
1095
1096 let sig = FunSig {
1098 is_unsafe: false,
1099 abi: Abi::rust(),
1100 inputs: vec![],
1101 output: Ty::new(TyKind::Adt(vtable_struct_ref.clone())),
1102 };
1103
1104 let body = match impl_kind {
1105 _ if item_meta.opacity.with_private_contents().is_opaque() => Body::Opaque,
1106 TraitImplSource::Normal => {
1107 self.gen_vtable_instance_init_body(span, impl_def, vtable_struct_ref)?
1108 }
1109 _ => {
1110 raise_error!(
1111 self,
1112 span,
1113 "Don't know how to generate a vtable for a virtual impl {impl_kind:?}"
1114 );
1115 }
1116 };
1117
1118 Ok(FunDecl {
1119 def_id: init_func_id,
1120 item_meta,
1121 generics: self.into_generics(),
1122 signature: Box::new(sig),
1123 src,
1124 is_global_initializer: Some(init_for),
1125 body,
1126 })
1127 }
1128
1129 fn translate_vtable_shim_body(
1147 &mut self,
1148 span: Span,
1149 target_receiver: &Ty,
1150 shim_signature: &FunSig,
1151 impl_func_def: &hax::FullDef,
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 let target_self = builder.new_var(None, target_receiver.clone());
1162
1163 let shim_self = mem::replace(&mut method_args[0], target_self.clone());
1165
1166 let rval = Rvalue::UnaryOp(
1170 UnOp::Cast(CastKind::Concretize(
1171 shim_self.ty().clone(),
1172 target_self.ty().clone(),
1173 )),
1174 Operand::Move(shim_self.clone()),
1175 );
1176 builder.push_statement(StatementKind::Assign(target_self.clone(), rval));
1177
1178 let fun_id = self.register_item(span, impl_func_def.this(), TransItemSourceKind::Fun);
1179 let generics = self.outermost_binder().params.identity_args();
1180 builder.call(Call {
1181 func: FnOperand::Regular(FnPtr::new(FnPtrKind::Fun(fun_id), generics)),
1182 args: method_args.into_iter().map(Operand::Move).collect(),
1183 dest: ret_place,
1184 });
1185
1186 Ok(Body::Unstructured(builder.build()))
1187 }
1188
1189 fn translate_vtable_drop_shim_body(
1201 &mut self,
1202 span: Span,
1203 shim_receiver: &Ty,
1204 target_receiver: &Ty,
1205 trait_pred: &TraitPredicate,
1206 ) -> Result<Body, Error> {
1207 let mut builder = BodyBuilder::new(span, 1);
1208
1209 builder.new_var(Some("ret".into()), Ty::mk_unit());
1210 let dyn_self = builder.new_var(Some("dyn_self".into()), shim_receiver.clone());
1211 let target_self = builder.new_var(Some("target_self".into()), target_receiver.clone());
1212
1213 let rval = Rvalue::UnaryOp(
1215 UnOp::Cast(CastKind::Concretize(
1216 dyn_self.ty().clone(),
1217 target_self.ty().clone(),
1218 )),
1219 Operand::Move(dyn_self.clone()),
1220 );
1221 builder.push_statement(StatementKind::Assign(target_self.clone(), rval));
1222
1223 let rustc_trait_args = trait_pred.trait_ref.rustc_args(self.hax_state_with_id());
1224 let rustc_self_ty = rustc_trait_args[0].as_type().unwrap();
1225 let fn_ptr = self.translate_drop_glue_method_call(span, rustc_self_ty)?;
1226
1227 let drop_arg = target_self.clone().deref();
1229 builder.insert_drop(drop_arg, fn_ptr);
1230
1231 Ok(Body::Unstructured(builder.build()))
1232 }
1233
1234 pub(crate) fn translate_vtable_drop_shim(
1235 mut self,
1236 fun_id: FunDeclId,
1237 item_meta: ItemMeta,
1238 impl_def: &hax::FullDef,
1239 ) -> Result<FunDecl, Error> {
1240 let span = item_meta.span;
1241
1242 let hax::FullDefKind::TraitImpl {
1243 dyn_self: Some(dyn_self),
1244 trait_pred,
1245 ..
1246 } = impl_def.kind()
1247 else {
1248 raise_error!(
1249 self,
1250 span,
1251 "Trying to generate a vtable drop shim for a non-dyn-compatible trait impl"
1252 );
1253 };
1254
1255 let borrow_region = self.drop_glue_region();
1256
1257 let dyn_self = self.translate_ty(span, dyn_self)?;
1258 let signature = self.drop_glue_method_sig(dyn_self.clone(), borrow_region);
1260
1261 let target_self_ref = {
1263 let impl_trait = self.translate_trait_ref(span, &trait_pred.trait_ref)?;
1264 TyKind::Ref(
1265 borrow_region,
1266 impl_trait.generics.types[0].clone(),
1267 RefKind::Mut,
1268 )
1269 .into_ty()
1270 };
1271
1272 let body: Body = self.translate_vtable_drop_shim_body(
1273 span,
1274 &signature.inputs[0],
1275 &target_self_ref,
1276 trait_pred,
1277 )?;
1278
1279 Ok(FunDecl {
1280 def_id: fun_id,
1281 item_meta,
1282 generics: self.into_generics(),
1283 signature: Box::new(signature),
1284 src: ItemSource::VTableMethodShim,
1285 is_global_initializer: None,
1286 body,
1287 })
1288 }
1289
1290 pub(crate) fn translate_vtable_shim(
1291 mut self,
1292 fun_id: FunDeclId,
1293 item_meta: ItemMeta,
1294 impl_func_def: &hax::FullDef,
1295 ) -> Result<FunDecl, Error> {
1296 let span = item_meta.span;
1297
1298 let hax::FullDefKind::AssocFn {
1299 vtable_sig: Some(vtable_sig),
1300 sig: target_signature,
1301 ..
1302 } = impl_func_def.kind()
1303 else {
1304 raise_error!(
1305 self,
1306 span,
1307 "Trying to generate a vtable shim for a non-vtable-safe method"
1308 );
1309 };
1310
1311 let signature = self.translate_fun_sig(span, &vtable_sig.value)?;
1313 let target_receiver = self.translate_ty(span, &target_signature.value.inputs[0])?;
1315
1316 trace!(
1317 "[VtableShim] Obtained dyn signature with receiver type: {}",
1318 signature.inputs[0].with_ctx(&self.into_fmt())
1319 );
1320
1321 let body = if item_meta.opacity.with_private_contents().is_opaque() {
1322 Body::Opaque
1323 } else {
1324 self.translate_vtable_shim_body(span, &target_receiver, &signature, impl_func_def)?
1325 };
1326
1327 Ok(FunDecl {
1328 def_id: fun_id,
1329 item_meta,
1330 generics: self.into_generics(),
1331 signature: Box::new(signature),
1332 src: ItemSource::VTableMethodShim,
1333 is_global_initializer: None,
1334 body,
1335 })
1336 }
1337}