1use itertools::Itertools;
2use rustc_span::kw;
3use std::mem;
4
5use super::{
6 translate_crate::TransItemSourceKind, translate_ctx::*, translate_generics::BindingLevel,
7};
8use crate::hax;
9use crate::hax::TraitPredicate;
10use charon_lib::formatter::IntoFormatter;
11use charon_lib::pretty::FmtWithCtx;
12use charon_lib::ullbc_ast::*;
13
14fn usize_ty() -> Ty {
15 Ty::new(TyKind::Literal(LiteralTy::UInt(UIntTy::Usize)))
16}
17
18enum VtableMethodValue {
22 Const(ConstantExprKind),
23 Cast((String, 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<TraitRefKind> {
58 if let DeBruijnVar::Bound(DeBruijnId::ZERO, clause_id) = v {
59 if self.for_method && clause_id == TraitClauseId::ZERO {
60 Some(TraitRefKind::Dyn)
62 } else {
63 panic!("Found unexpected clause var when constructing vtable: {v}")
64 }
65 } else {
66 None
67 }
68 }
69
70 fn visit_self_clause(&mut self) -> Option<TraitRefKind> {
71 Some(TraitRefKind::Dyn)
72 }
73 }
74 x.visit_vars(&mut ReplaceSelfVisitor {
75 new_self,
76 for_method,
77 });
78 x
79}
80
81impl<'tcx> ItemTransCtx<'tcx, '_> {
83 pub fn check_at_most_one_pred_has_methods(
84 &mut self,
85 span: Span,
86 preds: &hax::GenericPredicates,
87 ) -> Result<(), Error> {
88 for pred in preds.predicates.iter().skip(1) {
90 if let hax::ClauseKind::Trait(trait_predicate) = pred.clause.kind.hax_skip_binder_ref()
91 {
92 let trait_def_id = &trait_predicate.trait_ref.def_id;
93 let trait_def = self.poly_hax_def(trait_def_id)?;
94 let has_methods = match trait_def.kind() {
95 hax::FullDefKind::Trait { items, .. } => items
96 .iter()
97 .any(|assoc| matches!(assoc.kind, hax::AssocKind::Fn { .. })),
98 hax::FullDefKind::TraitAlias { .. } => false,
99 _ => unreachable!(),
100 };
101 if has_methods {
102 raise_error!(
103 self,
104 span,
105 "`dyn Trait` with multiple method-bearing predicates is not supported"
106 );
107 }
108 }
109 }
110 Ok(())
111 }
112
113 pub fn translate_dyn_binder<T, U>(
114 &mut self,
115 span: Span,
116 binder: &hax::DynBinder<T>,
117 f: impl FnOnce(&mut Self, Ty, &T) -> Result<U, Error>,
118 ) -> Result<Binder<U>, Error> {
119 self.check_at_most_one_pred_has_methods(span, &binder.predicates)?;
123
124 self.binding_levels.push(BindingLevel::new());
126
127 let ty_id = self.innermost_binder_mut().push_type_var(
129 binder.existential_ty.index,
130 binder.existential_ty.name,
131 Variance::Unknown,
132 );
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 let enqueue = enqueue || self.monomorphize();
257
258 let mut vtable_ref: TypeDeclRef =
261 self.translate_item_maybe_enqueue(span, tref, TransItemSourceKind::VTable, enqueue)?;
262 vtable_ref
264 .generics
265 .types
266 .remove_and_shift_ids(TypeVarId::ZERO);
267
268 if !self.monomorphize() {
269 let assoc_tys: Vec<_> = tref
271 .trait_associated_types(self.hax_state_with_id())
272 .iter()
273 .map(|ty| self.translate_ty(span, ty))
274 .try_collect()?;
275 vtable_ref.generics.types.extend(assoc_tys);
276 }
277
278 Ok(Some(vtable_ref))
279 }
280
281 fn prepare_vtable_fields(
282 &mut self,
283 poly_trait_def: &hax::FullDef<'tcx>,
284 trait_id: TraitDeclId,
285 implied_predicates: &hax::GenericPredicates,
286 ) -> Result<VTableData, Error> {
287 let mut supertrait_map: IndexVec<TraitClauseId, _> =
288 (0..implied_predicates.predicates.len())
289 .map(|_| None)
290 .collect();
291 let mut fields = IndexVec::new();
292
293 fields.push(TrVTableField::Size);
295 fields.push(TrVTableField::Align);
296 fields.push(TrVTableField::Drop);
297
298 if let hax::FullDefKind::Trait { items, .. } = poly_trait_def.kind() {
300 for item in items {
301 let item_def_id = &item.def_id;
302 let poly_item_def = self.poly_hax_def(item_def_id)?;
304 if let hax::FullDefKind::AssocFn {
305 sig,
306 vtable_sig: Some(_),
307 ..
308 } = poly_item_def.kind()
309 {
310 let id = self.translate_trait_method_id_no_enqueue(trait_id, item_def_id)?;
311 fields.push(TrVTableField::Method(id, sig.clone()));
312 }
313 }
314 }
315
316 for (i, pred) in implied_predicates.iter_trait_clauses().enumerate() {
318 let trait_clause_id = TraitClauseId::from_raw(i); let clause = &pred.clause;
320 let hax::ClauseKind::Trait(pred) = clause.kind.hax_skip_binder_ref() else {
321 unreachable!()
322 };
323 if self.pred_is_for_self(&pred.trait_ref) {
325 if !self.trait_is_dyn_compatible(&pred.trait_ref.def_id)? {
326 self.assert_is_destruct(&pred.trait_ref);
328 continue;
329 }
330 supertrait_map[trait_clause_id] = Some(fields.next_idx());
331 fields.push(TrVTableField::SuperTrait(trait_clause_id, clause.clone()));
332 }
333 }
334
335 Ok(VTableData {
336 fields,
337 supertrait_map,
338 })
339 }
340
341 fn assert_is_destruct(&self, tref: &hax::TraitRef) {
347 assert!(
348 tref.def_id
349 .as_real_def_id()
350 .is_some_and(|id| self.tcx.is_lang_item(id, rustc_attr_ir::LangItem::Destruct)),
351 "unexpected non-dyn compatible supertrait: {:?}",
352 tref.def_id
353 );
354 }
355
356 fn gen_vtable_struct_fields(
357 &mut self,
358 span: Span,
359 self_trait_ref: &TraitRef,
360 vtable_data: &VTableData,
361 ) -> Result<IndexVec<FieldId, Field>, Error> {
362 let mut fields = IndexVec::new();
363 let mut supertrait_counter = 0..;
364 for field in &vtable_data.fields {
365 let (name, ty) = match field {
366 TrVTableField::Size => ("size".into(), usize_ty()),
367 TrVTableField::Align => ("align".into(), usize_ty()),
368 TrVTableField::Drop => {
369 if self.monomorphize() {
371 let erased_ptr_ty = Ty::new(TyKind::RawPtr(Ty::mk_unit(), RefKind::Shared));
372 ("drop".into(), erased_ptr_ty)
373 } else {
374 let self_ty =
375 TyKind::TypeVar(DeBruijnVar::new_at_zero(TypeVarId::ZERO)).into_ty();
376 let drop_ty = Ty::new(TyKind::FnPtr(self.drop_glue_fn_ptr_sig(self_ty)));
377 ("drop".into(), drop_ty)
378 }
379 }
380 TrVTableField::Method(item_id, sig) => {
381 let item_name = self
382 .translated
383 .assoc_item_name(self_trait_ref.trait_id(), *item_id);
384 let field_name = format!("method_{}", item_name.0);
385 if self.monomorphize() {
387 let erased_ptr_ty = Ty::new(TyKind::RawPtr(Ty::mk_unit(), RefKind::Shared));
388 (field_name, erased_ptr_ty)
389 } else {
390 let bound_sig = self.inside_binder(BinderKind::Other, |ctx| {
393 ctx.innermost_binder_mut()
394 .trait_preds
395 .insert(hax::GenericPredicateId::TraitSelf, TraitClauseId::ZERO);
396 ctx.translate_poly_fun_sig(span, sig)
397 })?;
398 let sig = bound_sig.apply(&{
399 let mut generics = GenericArgs::empty();
400 generics.trait_refs.push(self_trait_ref.clone());
402 generics
403 });
404 let ty = TyKind::FnPtr(sig).into_ty();
405 (field_name, ty)
406 }
407 }
408 TrVTableField::SuperTrait(_, clause) => {
409 let vtbl_struct =
410 self.translate_region_binder(span, &clause.kind, |ctx, kind| {
411 let hax::ClauseKind::Trait(pred) = kind else {
412 unreachable!()
413 };
414 ctx.translate_vtable_struct_ref(span, &pred.trait_ref)
415 })?;
416 let vtbl_struct = self.erase_region_binder(vtbl_struct);
417 let ty = Ty::new(TyKind::Ref(
418 Region::Static,
419 Ty::new(TyKind::Adt(vtbl_struct)),
420 RefKind::Shared,
421 ));
422 let name = format!("super_trait_{}", supertrait_counter.next().unwrap());
423 (name, ty)
424 }
425 };
426 fields.push(Field {
427 span,
428 attr_info: AttrInfo::dummy_public(),
429 name,
430 is_positional: false,
431 ty,
432 });
433 }
434 Ok(fields)
435 }
436
437 pub(crate) fn translate_vtable_struct(
452 mut self,
453 type_id: TypeDeclId,
454 item_meta: ItemMeta,
455 trait_def: &hax::FullDef<'tcx>,
456 ) -> Result<TypeDecl, Error> {
457 let mono = self.monomorphize();
458 let span = item_meta.span;
459 if !self.trait_is_dyn_compatible(trait_def.def_id())? {
460 raise_error!(
461 self,
462 span,
463 "Trying to compute the vtable type \
464 for a non-dyn-compatible trait"
465 );
466 }
467
468 let (hax::FullDefKind::Trait {
469 self_predicate,
470 dyn_self,
471 implied_predicates,
472 ..
473 }
474 | hax::FullDefKind::TraitAlias {
475 self_predicate,
476 dyn_self,
477 implied_predicates,
478 ..
479 }) = trait_def.kind()
480 else {
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 RegionBinder::empty(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, ..) => VTableField::Method(id),
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 })
600 }
601}
602
603impl<'tcx> ItemTransCtx<'tcx, '_> {
605 pub fn translate_vtable_instance_const(
607 &mut self,
608 span: Span,
609 trait_proof: &hax::TraitProof,
610 ) -> Result<Box<ConstantExpr>, Error> {
611 let tref = trait_proof.pred.hax_skip_binder_ref();
612 if !self.trait_is_dyn_compatible(&tref.def_id)? {
613 raise_error!(
614 self,
615 span,
616 "Trait {:?} should be dyn-compatible",
617 tref.def_id
618 );
619 }
620
621 let vtbl_ty = {
622 let vtbl_ty = self.translate_region_binder(span, &trait_proof.pred, |ctx, tref| {
623 ctx.translate_vtable_struct_ref(span, tref)
624 })?;
625 let vtbl_ty = self.erase_region_binder(vtbl_ty);
626 TyKind::Adt(vtbl_ty).into_ty()
627 };
628 let ty = TyKind::Ref(Region::Static, vtbl_ty.clone(), RefKind::Shared).into_ty();
629
630 let kind = {
631 if let hax::TraitProofKind::Concrete(impl_item) = &trait_proof.kind {
632 let vtable_instance =
635 self.translate_region_binder(span, &trait_proof.pred, |ctx, tref| {
636 ctx.translate_vtable_instance_ref(span, tref, impl_item)
637 })?;
638 let vtable_instance = self.erase_region_binder(vtable_instance);
639 let vtable_instance = Box::new(ConstantExpr {
640 kind: ConstantExprKind::Global(vtable_instance),
641 ty: vtbl_ty,
642 });
643 ConstantExprKind::Ref(vtable_instance, None)
644 } else {
645 ConstantExprKind::VTableRef(self.translate_trait_proof(span, trait_proof)?)
646 }
647 };
648
649 Ok(Box::new(ConstantExpr { kind, ty }))
650 }
651
652 pub fn translate_vtable_instance_ref(
654 &mut self,
655 span: Span,
656 trait_ref: &hax::TraitRef,
657 impl_ref: &hax::ItemRef,
658 ) -> Result<GlobalDeclRef, Error> {
659 Ok(self
660 .translate_vtable_instance_ref_maybe_enqueue(true, span, trait_ref, impl_ref)?
661 .expect("trait should be dyn-compatible"))
662 }
663
664 pub fn translate_vtable_instance_ref_no_enqueue(
665 &mut self,
666 span: Span,
667 trait_ref: &hax::TraitRef,
668 impl_ref: &hax::ItemRef,
669 ) -> Result<Option<GlobalDeclRef>, Error> {
670 self.translate_vtable_instance_ref_maybe_enqueue(false, span, trait_ref, impl_ref)
671 }
672
673 pub fn translate_vtable_instance_ref_maybe_enqueue(
674 &mut self,
675 enqueue: bool,
676 span: Span,
677 trait_ref: &hax::TraitRef,
678 impl_ref: &hax::ItemRef,
679 ) -> Result<Option<GlobalDeclRef>, Error> {
680 if !self.trait_is_dyn_compatible(&trait_ref.def_id)? {
681 return Ok(None);
682 }
683 let vtable_ref: GlobalDeclRef = self.translate_item_maybe_enqueue(
688 span,
689 impl_ref,
690 TransItemSourceKind::VTableInstance(TransImplSource::Normal),
691 enqueue,
692 )?;
693 Ok(Some(vtable_ref))
694 }
695
696 fn get_vtable_instance_info(
698 &mut self,
699 span: Span,
700 impl_def: &hax::FullDef<'tcx>,
701 impl_kind: &TransImplSource,
702 ) -> Result<(Option<TraitImplRef>, TypeDeclRef), Error> {
703 let implemented_trait = match impl_def.kind() {
704 hax::FullDefKind::TraitImpl { trait_pred, .. } => &trait_pred.trait_ref,
705 _ => unreachable!(),
706 };
707 let vtable_struct_ref = self.translate_vtable_struct_ref(span, implemented_trait)?;
708 if self.monomorphize() {
709 return Ok((None, vtable_struct_ref));
710 }
711 let impl_ref = self.translate_item(
712 span,
713 impl_def.this(),
714 TransItemSourceKind::TraitImpl(*impl_kind),
715 )?;
716 Ok((Some(impl_ref), vtable_struct_ref))
717 }
718
719 pub(crate) fn translate_vtable_instance(
734 mut self,
735 global_id: GlobalDeclId,
736 item_meta: ItemMeta,
737 impl_def: &hax::FullDef<'tcx>,
738 impl_kind: &TransImplSource,
739 ) -> Result<GlobalDecl, Error> {
740 let span = item_meta.span;
741
742 let (impl_ref, vtable_struct_ref) =
743 self.get_vtable_instance_info(span, impl_def, impl_kind)?;
744 let src = GlobalSource::VTableInstance { impl_ref };
745
746 let init = self.register_item(
748 span,
749 impl_def.this(),
750 TransItemSourceKind::VTableInstanceInitializer(*impl_kind),
751 );
752 let ty = Ty::new(TyKind::Adt(vtable_struct_ref));
753 let value = ConstantExpr {
754 kind: ConstantExprKind::Call(
755 FnPtr::new(
756 FnPtrKind::Fun(FunId::Regular(init)),
757 self.outermost_generics().identity_args(),
758 ),
759 vec![],
760 ),
761 ty: ty.clone(),
762 };
763
764 Ok(GlobalDecl {
765 def_id: global_id,
766 item_meta,
767 generics: self.into_generics(),
768 src,
769 global_kind: GlobalKind::Static,
771 ty,
772 value,
773 })
774 }
775
776 fn add_method_to_vtable_value(
777 &mut self,
778 span: Span,
779 trait_id: TraitDeclId,
780 item: &hax::ImplAssocItem,
781 ) -> Result<Option<VtableMethodValue>, Error> {
782 let item_def = self.poly_hax_def(&item.decl_def_id)?;
784 let hax::FullDefKind::AssocFn {
785 vtable_sig: Some(_),
786 ..
787 } = item_def.kind()
788 else {
789 return Ok(None);
790 };
791
792 let vtable_value = match &item.value {
794 Some(value) => {
795 let item_ref = &value.skip_binder.item;
796 let shim_ref =
797 self.translate_fn_ptr(span, item_ref, TransItemSourceKind::VTableMethod)?;
798 if self.monomorphize() {
802 assert!(self.binding_levels.len() == 1);
806 let orginal_binding = self.binding_levels.pop();
807 let assoc_fun_def = self.hax_def(item_ref)?;
808 self.translate_item_generics(
809 span,
810 &assoc_fun_def,
811 &TransItemSourceKind::VTableMethod,
812 )?;
813 let vtable_sig = match assoc_fun_def.kind() {
814 hax::FullDefKind::AssocFn {
815 vtable_sig: Some(vtable_sig),
816 ..
817 } => vtable_sig.clone(),
818 _ => unreachable!("MONO: only assoc fun is supported"),
819 };
820
821 let signature = self.translate_fun_sig(span, &vtable_sig.value)?;
822 let method_ty = Ty::new(TyKind::FnPtr(RegionBinder {
824 regions: self.outermost_generics().regions.clone(),
825 skip_binder: signature,
826 }));
827
828 self.binding_levels.pop();
830 if let Some(binding_level) = orginal_binding {
831 self.binding_levels.push(binding_level);
832 }
833
834 let method_id = self.translate_trait_method_id(trait_id, item.decl_def_id())?;
835 let method_name = self.translated.assoc_item_name(trait_id, method_id);
836
837 VtableMethodValue::Cast((method_name.to_string(), method_ty, shim_ref))
838 } else {
839 VtableMethodValue::Const(ConstantExprKind::FnPtr(shim_ref))
840 }
841 }
842 None => VtableMethodValue::Const(ConstantExprKind::Opaque(
843 "shim for default methods aren't yet supported".into(),
844 )),
845 };
846
847 Ok(Some(vtable_value))
848 }
849
850 fn gen_vtable_instance_init_body(
858 &mut self,
859 span: Span,
860 impl_def: &hax::FullDef<'tcx>,
861 vtable_struct_ref: TypeDeclRef,
862 ) -> Result<Body, Error> {
863 let hax::FullDefKind::TraitImpl {
864 trait_pred,
865 implied_trait_proofs,
866 items,
867 ..
868 } = impl_def.kind()
869 else {
870 unreachable!()
871 };
872
873 let trait_def = self.hax_def(&trait_pred.trait_ref)?;
874 let poly_trait_def = self.poly_hax_def(&trait_pred.trait_ref.def_id)?;
876 let hax::FullDefKind::Trait {
877 implied_predicates: implied_preds,
878 ..
879 } = poly_trait_def.kind()
880 else {
881 unreachable!()
882 };
883
884 let implemented_trait = self.translate_trait_decl_ref(span, &trait_pred.trait_ref)?;
885 let trait_id = implemented_trait.id;
886 let self_ty = &implemented_trait.generics.types[0];
888
889 let mut builder = BodyBuilder::new(span, 0);
890 let ret_ty = Ty::new(TyKind::Adt(vtable_struct_ref.clone()));
891 let ret_place = builder.new_var(Some("ret".into()), ret_ty.clone());
892
893 let vtable_data = self.prepare_vtable_fields(&poly_trait_def, trait_id, implied_preds)?;
894 let field_tys = {
897 let vtable_decl_id = vtable_struct_ref.adt_id();
898 let ItemRef::Type(vtable_def) = self.t_ctx.get_or_translate(vtable_decl_id.into())?
899 else {
900 unreachable!()
901 };
902 let fields = match &vtable_def.kind {
903 TypeDeclKind::Struct(fields) => fields,
904 TypeDeclKind::Opaque => return Ok(Body::Opaque),
905 TypeDeclKind::Error(error) => return Err(Error::new(span, error.clone())),
906 _ => unreachable!(),
907 };
908 fields
909 .iter()
910 .map(|f| &f.ty)
911 .cloned()
912 .map(|ty| ty.substitute(&vtable_struct_ref.generics))
913 .collect_vec()
914 };
915
916 let mut aggregate_fields = vec![];
918 let mut items_iter = items.iter();
919 for (field, ty) in vtable_data.fields.into_iter().zip(field_tys) {
920 let mk_const = |kind| {
922 Operand::Const(Box::new(ConstantExpr {
923 kind,
924 ty: ty.clone(),
925 }))
926 };
927 let mut mk_cast = |(method_name, method_ty, method_shim): (String, Ty, FnPtr)| {
951 let method_local = builder.new_var(Some(method_name.clone()), method_ty.clone());
952 let shim = Rvalue::Use(
953 Operand::Const(Box::new(ConstantExpr {
954 kind: ConstantExprKind::FnPtr(method_shim.clone()),
955 ty: method_ty.clone(),
956 })),
957 WithRetag::No,
958 );
959 let cast_local = builder.new_var(
960 Some("erased_".to_string() + method_name.as_str()),
961 ty.clone(),
962 );
963 let cast = Rvalue::UnaryOp(
964 UnOp::Cast(CastKind::RawPtr(
965 method_local.ty().clone(),
966 cast_local.ty().clone(),
967 )),
968 Operand::Move(method_local.clone()),
969 );
970
971 builder.push_statement(StatementKind::Assign(method_local.clone(), shim));
972 builder.push_statement(StatementKind::Assign(cast_local.clone(), cast));
973 Operand::Move(cast_local)
974 };
975 let op = match field {
976 TrVTableField::Size => {
977 let size_local = builder.new_var(Some("size".to_string()), ty);
978 builder.push_statement(StatementKind::Assign(
979 size_local.clone(),
980 Rvalue::NullaryOp(NullOp::SizeOf, self_ty.clone()),
981 ));
982 Operand::Move(size_local)
983 }
984 TrVTableField::Align => {
985 let align_local = builder.new_var(Some("align".to_string()), ty);
986 builder.push_statement(StatementKind::Assign(
987 align_local.clone(),
988 Rvalue::NullaryOp(NullOp::AlignOf, self_ty.clone()),
989 ));
990 Operand::Move(align_local)
991 }
992 TrVTableField::Drop => {
993 let drop_shim = self.translate_item(
994 span,
995 impl_def.this(),
996 TransItemSourceKind::VTableDropShim,
997 )?;
998 if self.monomorphize() {
999 let hax::FullDefKind::Trait { dyn_self, .. } = trait_def.kind() else {
1001 panic!()
1002 };
1003
1004 let Some(dyn_self) = dyn_self else {
1005 panic!(
1006 "MONO: Trying to generate a vtable for a non-dyn-compatible trait"
1007 )
1008 };
1009 let ref_dyn_self =
1010 TyKind::RawPtr(self.translate_ty(span, dyn_self)?, RefKind::Mut)
1011 .into_ty();
1012 let signature = FunSig {
1013 is_unsafe: true,
1014 abi: Abi::rust(),
1015 is_variadic: false,
1016 inputs: vec![ref_dyn_self.clone()],
1017 output: Ty::mk_unit(),
1018 };
1019 let drop_ty = Ty::new(TyKind::FnPtr(RegionBinder::empty(signature)));
1020
1021 mk_cast(("drop".to_string(), drop_ty.clone(), drop_shim))
1022 } else {
1023 mk_const(ConstantExprKind::FnPtr(drop_shim))
1024 }
1025 }
1026 TrVTableField::Method(..) => 'a: {
1027 for item in items_iter.by_ref() {
1030 if let Some(kind) = self.add_method_to_vtable_value(span, trait_id, item)? {
1031 match kind {
1032 VtableMethodValue::Const(const_kind) => {
1033 break 'a mk_const(const_kind);
1034 }
1035 VtableMethodValue::Cast(method) => break 'a mk_cast(method),
1036 }
1037 }
1038 }
1039 unreachable!()
1040 }
1041 TrVTableField::SuperTrait(clause_id, _) => {
1042 let trait_proof = &implied_trait_proofs[clause_id.index()];
1043 let vtable = self.translate_vtable_instance_const(span, trait_proof)?;
1044 Operand::Const(vtable)
1045 }
1046 };
1047 aggregate_fields.push(op);
1048 }
1049
1050 builder.push_statement(StatementKind::Assign(
1052 ret_place,
1053 Rvalue::Aggregate(
1054 AggregateKind::Adt(vtable_struct_ref.clone(), None, None),
1055 aggregate_fields,
1056 ),
1057 ));
1058
1059 Ok(Body::Unstructured(builder.build()))
1060 }
1061
1062 pub(crate) fn translate_vtable_instance_init(
1063 mut self,
1064 init_func_id: FunDeclId,
1065 item_meta: ItemMeta,
1066 impl_def: &hax::FullDef<'tcx>,
1067 impl_kind: &TransImplSource,
1068 ) -> Result<FunDecl, Error> {
1069 let span = item_meta.span;
1070
1071 let (_, vtable_struct_ref) = self.get_vtable_instance_info(span, impl_def, impl_kind)?;
1072
1073 let init_for = self.register_item(
1074 span,
1075 impl_def.this(),
1076 TransItemSourceKind::VTableInstance(*impl_kind),
1077 );
1078 let src = FunSource::GlobalInitializer(GlobalDeclRef {
1079 id: init_for,
1080 generics: Box::new(self.outermost_generics().identity_args()),
1081 });
1082
1083 let sig = FunSig {
1085 is_unsafe: false,
1086 abi: Abi::rust(),
1087 is_variadic: false,
1088 inputs: vec![],
1089 output: Ty::new(TyKind::Adt(vtable_struct_ref.clone())),
1090 };
1091
1092 let body = match impl_kind {
1093 _ if item_meta.opacity.with_private_contents().is_opaque() => Body::Opaque,
1094 TransImplSource::Normal => {
1095 self.gen_vtable_instance_init_body(span, impl_def, vtable_struct_ref)?
1096 }
1097 _ => {
1098 raise_error!(
1099 self,
1100 span,
1101 "Don't know how to generate a vtable for a virtual impl {impl_kind:?}"
1102 );
1103 }
1104 };
1105
1106 Ok(FunDecl {
1107 def_id: init_func_id,
1108 item_meta,
1109 generics: self.into_generics(),
1110 signature: Box::new(sig),
1111 src,
1112 body,
1113 })
1114 }
1115
1116 fn translate_vtable_shim_body(
1134 &mut self,
1135 span: Span,
1136 target_receiver: &Ty,
1137 shim_signature: &FunSig,
1138 impl_func_def: &hax::FullDef,
1139 ) -> Result<Body, Error> {
1140 let mut builder = BodyBuilder::new(span, shim_signature.inputs.len());
1141
1142 let ret_place = builder.new_var(None, shim_signature.output.clone());
1143 let mut method_args = shim_signature
1144 .inputs
1145 .iter()
1146 .map(|ty| builder.new_var(None, ty.clone()))
1147 .collect_vec();
1148 let target_self = builder.new_var(None, target_receiver.clone());
1149
1150 let shim_self = mem::replace(&mut method_args[0], target_self.clone());
1152
1153 let rval = Rvalue::UnaryOp(
1157 UnOp::Cast(CastKind::Concretize(
1158 shim_self.ty().clone(),
1159 target_self.ty().clone(),
1160 )),
1161 Operand::Move(shim_self.clone()),
1162 );
1163 builder.push_statement(StatementKind::Assign(target_self.clone(), rval));
1164
1165 let fun_id = self.register_item(span, impl_func_def.this(), TransItemSourceKind::Fun);
1166 let generics = self.outermost_binder().params.identity_args();
1167 builder.call(Call {
1168 func: FnOperand::Regular(FnPtr::new(FnPtrKind::Fun(fun_id), generics)),
1169 args: method_args.into_iter().map(Operand::Move).collect(),
1170 dest: ret_place,
1171 });
1172
1173 Ok(Body::Unstructured(builder.build()))
1174 }
1175
1176 fn translate_vtable_drop_shim_body(
1188 &mut self,
1189 span: Span,
1190 shim_receiver: &Ty,
1191 target_receiver: &Ty,
1192 trait_pred: &TraitPredicate,
1193 ) -> Result<Body, Error> {
1194 let mut builder = BodyBuilder::new(span, 1);
1195
1196 builder.new_var(Some("ret".into()), Ty::mk_unit());
1197 let dyn_self = builder.new_var(Some("dyn_self".into()), shim_receiver.clone());
1198 let target_self = builder.new_var(Some("target_self".into()), target_receiver.clone());
1199
1200 let rval = Rvalue::UnaryOp(
1202 UnOp::Cast(CastKind::Concretize(
1203 dyn_self.ty().clone(),
1204 target_self.ty().clone(),
1205 )),
1206 Operand::Move(dyn_self.clone()),
1207 );
1208 builder.push_statement(StatementKind::Assign(target_self.clone(), rval));
1209
1210 let rustc_trait_args = trait_pred.trait_ref.rustc_args(self.hax_state_with_id());
1211 let rustc_self_ty = rustc_trait_args[0].as_type().unwrap();
1212 let fn_ptr = self.translate_drop_glue_method_call(span, rustc_self_ty)?;
1213
1214 let drop_arg = target_self.clone().deref();
1216 builder.insert_drop(drop_arg, fn_ptr);
1217
1218 Ok(Body::Unstructured(builder.build()))
1219 }
1220
1221 pub(crate) fn translate_vtable_drop_shim(
1222 mut self,
1223 fun_id: FunDeclId,
1224 item_meta: ItemMeta,
1225 impl_def: &hax::FullDef,
1226 ) -> Result<FunDecl, Error> {
1227 let span = item_meta.span;
1228
1229 let hax::FullDefKind::TraitImpl {
1230 dyn_self: Some(dyn_self),
1231 trait_pred,
1232 ..
1233 } = impl_def.kind()
1234 else {
1235 raise_error!(
1236 self,
1237 span,
1238 "Trying to generate a vtable drop shim for a non-dyn-compatible trait impl"
1239 );
1240 };
1241
1242 let borrow_region = self.drop_glue_region();
1243
1244 let dyn_self = self.translate_ty(span, dyn_self)?;
1245 let signature = self.drop_glue_method_sig(dyn_self.clone(), borrow_region);
1247
1248 let target_self_ref = {
1250 let impl_trait = self.translate_trait_ref(span, &trait_pred.trait_ref)?;
1251 TyKind::Ref(
1252 borrow_region,
1253 impl_trait.generics.types[0].clone(),
1254 RefKind::Mut,
1255 )
1256 .into_ty()
1257 };
1258
1259 let body: Body = self.translate_vtable_drop_shim_body(
1260 span,
1261 &signature.inputs[0],
1262 &target_self_ref,
1263 trait_pred,
1264 )?;
1265
1266 Ok(FunDecl {
1267 def_id: fun_id,
1268 item_meta,
1269 generics: self.into_generics(),
1270 signature: Box::new(signature),
1271 src: FunSource::VTableShim,
1272 body,
1273 })
1274 }
1275
1276 pub(crate) fn translate_vtable_shim(
1277 mut self,
1278 fun_id: FunDeclId,
1279 item_meta: ItemMeta,
1280 impl_func_def: &hax::FullDef,
1281 ) -> Result<FunDecl, Error> {
1282 let span = item_meta.span;
1283
1284 let hax::FullDefKind::AssocFn {
1285 vtable_sig: Some(vtable_sig),
1286 sig: target_signature,
1287 ..
1288 } = impl_func_def.kind()
1289 else {
1290 raise_error!(
1291 self,
1292 span,
1293 "Trying to generate a vtable shim for a non-vtable-safe method"
1294 );
1295 };
1296
1297 let signature = self.translate_fun_sig(span, &vtable_sig.value)?;
1299 let target_receiver = self.translate_ty(span, &target_signature.value.inputs[0])?;
1301
1302 trace!(
1303 "[VtableShim] Obtained dyn signature with receiver type: {}",
1304 signature.inputs[0].with_ctx(&self.into_fmt())
1305 );
1306
1307 let body = if item_meta.opacity.with_private_contents().is_opaque() {
1308 Body::Opaque
1309 } else {
1310 self.translate_vtable_shim_body(span, &target_receiver, &signature, impl_func_def)?
1311 };
1312
1313 Ok(FunDecl {
1314 def_id: fun_id,
1315 item_meta,
1316 generics: self.into_generics(),
1317 signature: Box::new(signature),
1318 src: FunSource::VTableShim,
1319 body,
1320 })
1321 }
1322}