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