1use charon_lib::ast::ullbc_ast_utils::BodyBuilder;
2use hax::TraitPredicate;
3use itertools::Itertools;
4use rustc_span::kw;
5use std::mem;
6
7use super::{
8 translate_crate::TransItemSourceKind, translate_ctx::*, translate_generics::BindingLevel,
9};
10use charon_lib::formatter::IntoFormatter;
11use charon_lib::ids::{IndexMap, IndexVec};
12use charon_lib::pretty::FmtWithCtx;
13use charon_lib::ullbc_ast::*;
14
15fn usize_ty() -> Ty {
16 Ty::new(TyKind::Literal(LiteralTy::UInt(UIntTy::Usize)))
17}
18
19fn dynify<T: TyVisitable>(mut x: T, new_self: Option<Ty>, for_method: bool) -> T {
27 struct ReplaceSelfVisitor {
28 new_self: Option<Ty>,
29 for_method: bool,
30 }
31 impl VarsVisitor for ReplaceSelfVisitor {
32 fn visit_type_var(&mut self, v: TypeDbVar) -> Option<Ty> {
33 if let DeBruijnVar::Bound(DeBruijnId::ZERO, type_id) = v {
34 Some(if let Some(new_id) = type_id.index().checked_sub(1) {
36 TyKind::TypeVar(DeBruijnVar::Bound(DeBruijnId::ZERO, TypeVarId::new(new_id)))
37 .into_ty()
38 } else {
39 self.new_self.clone().expect(
40 "Found unexpected `Self`
41 type when constructing vtable",
42 )
43 })
44 } else {
45 None
46 }
47 }
48
49 fn visit_clause_var(&mut self, v: ClauseDbVar) -> Option<TraitRefKind> {
50 if let DeBruijnVar::Bound(DeBruijnId::ZERO, clause_id) = v {
51 if self.for_method && clause_id == TraitClauseId::ZERO {
52 Some(TraitRefKind::Dyn)
54 } else {
55 panic!("Found unexpected clause var when constructing vtable: {v}")
56 }
57 } else {
58 None
59 }
60 }
61
62 fn visit_self_clause(&mut self) -> Option<TraitRefKind> {
63 Some(TraitRefKind::Dyn)
64 }
65 }
66 x.visit_vars(&mut ReplaceSelfVisitor {
67 new_self,
68 for_method,
69 });
70 x
71}
72
73impl ItemTransCtx<'_, '_> {
75 pub fn check_at_most_one_pred_has_methods(
76 &mut self,
77 span: Span,
78 preds: &hax::GenericPredicates,
79 ) -> Result<(), Error> {
80 for (clause, _) in preds.predicates.iter().skip(1) {
82 if let hax::ClauseKind::Trait(trait_predicate) = clause.kind.hax_skip_binder_ref() {
83 let trait_def_id = &trait_predicate.trait_ref.def_id;
84 let trait_def = self.poly_hax_def(trait_def_id)?;
85 let has_methods = match trait_def.kind() {
86 hax::FullDefKind::Trait { items, .. } => items
87 .iter()
88 .any(|assoc| matches!(assoc.kind, hax::AssocKind::Fn { .. })),
89 hax::FullDefKind::TraitAlias { .. } => false,
90 _ => unreachable!(),
91 };
92 if has_methods {
93 raise_error!(
94 self,
95 span,
96 "`dyn Trait` with multiple method-bearing predicates is not supported"
97 );
98 }
99 }
100 }
101 Ok(())
102 }
103
104 pub fn translate_dyn_binder<T, U>(
105 &mut self,
106 span: Span,
107 binder: &hax::DynBinder<T>,
108 f: impl FnOnce(&mut Self, Ty, &T) -> Result<U, Error>,
109 ) -> Result<Binder<U>, Error> {
110 self.check_at_most_one_pred_has_methods(span, &binder.predicates)?;
114
115 self.binding_levels.push(BindingLevel::new(true));
117
118 let ty_id = self
120 .innermost_binder_mut()
121 .push_type_var(binder.existential_ty.index, binder.existential_ty.name);
122 let ty = TyKind::TypeVar(DeBruijnVar::new_at_zero(ty_id)).into_ty();
123 let val = f(self, ty, &binder.val)?;
124
125 self.register_predicates(&binder.predicates, PredicateOrigin::Dyn)?;
126
127 let params = self.binding_levels.pop().unwrap().params;
128 Ok(Binder {
129 params: params,
130 skip_binder: val,
131 kind: BinderKind::Dyn,
132 })
133 }
134}
135
136pub enum TrVTableField {
139 Size,
140 Align,
141 Drop,
142 Method(TraitItemName, hax::Binder<hax::TyFnSig>),
143 SuperTrait(TraitClauseId, hax::Clause),
144}
145
146pub struct VTableData {
147 pub fields: IndexVec<FieldId, TrVTableField>,
148 pub supertrait_map: IndexMap<TraitClauseId, Option<FieldId>>,
149}
150
151impl ItemTransCtx<'_, '_> {
153 pub fn trait_is_dyn_compatible(&mut self, def_id: &hax::DefId) -> Result<bool, Error> {
157 let def = self.poly_hax_def(def_id)?;
158 Ok(match def.kind() {
159 hax::FullDefKind::Trait { dyn_self, .. }
160 | hax::FullDefKind::TraitAlias { dyn_self, .. } => dyn_self.is_some(),
161 _ => false,
162 })
163 }
164
165 fn pred_is_for_self(&self, tref: &hax::TraitRef) -> bool {
167 let first_ty = tref
168 .generic_args
169 .iter()
170 .filter_map(|arg| match arg {
171 hax::GenericArg::Type(ty) => Some(ty),
172 _ => None,
173 })
174 .next();
175 match first_ty {
176 None => false,
177 Some(first_ty) => match first_ty.kind() {
178 hax::TyKind::Param(param_ty) if param_ty.index == 0 => {
179 assert_eq!(param_ty.name, kw::SelfUpper);
180 true
181 }
182 _ => false,
183 },
184 }
185 }
186
187 pub fn translate_vtable_struct_ref(
188 &mut self,
189 span: Span,
190 tref: &hax::TraitRef,
191 ) -> Result<TypeDeclRef, Error> {
192 Ok(self
193 .translate_vtable_struct_ref_maybe_enqueue(true, span, tref)?
194 .expect("trait should be dyn-compatible"))
195 }
196
197 pub fn translate_vtable_struct_ref_no_enqueue(
198 &mut self,
199 span: Span,
200 tref: &hax::TraitRef,
201 ) -> Result<Option<TypeDeclRef>, Error> {
202 self.translate_vtable_struct_ref_maybe_enqueue(false, span, tref)
203 }
204
205 pub fn translate_vtable_struct_ref_maybe_enqueue(
207 &mut self,
208 enqueue: bool,
209 span: Span,
210 tref: &hax::TraitRef,
211 ) -> Result<Option<TypeDeclRef>, Error> {
212 if !self.trait_is_dyn_compatible(&tref.def_id)? {
213 return Ok(None);
214 }
215 let mut vtable_ref: TypeDeclRef =
218 self.translate_item_maybe_enqueue(span, enqueue, tref, TransItemSourceKind::VTable)?;
219 vtable_ref
221 .generics
222 .types
223 .remove_and_shift_ids(TypeVarId::ZERO);
224
225 let assoc_tys: Vec<_> = tref
227 .trait_associated_types(self.hax_state_with_id())
228 .iter()
229 .map(|ty| self.translate_ty(span, ty))
230 .try_collect()?;
231 vtable_ref.generics.types.extend(assoc_tys);
232
233 Ok(Some(vtable_ref))
234 }
235
236 fn prepare_vtable_fields(
237 &mut self,
238 trait_def: &hax::FullDef,
239 implied_predicates: &hax::GenericPredicates,
240 ) -> Result<VTableData, Error> {
241 let mut supertrait_map: IndexMap<TraitClauseId, _> =
242 (0..implied_predicates.predicates.len())
243 .map(|_| None)
244 .collect();
245 let mut fields = IndexVec::new();
246
247 fields.push(TrVTableField::Size);
249 fields.push(TrVTableField::Align);
250 fields.push(TrVTableField::Drop);
251
252 if let hax::FullDefKind::Trait { items, .. } = trait_def.kind() {
254 for item in items {
255 let item_def_id = &item.def_id;
256 let item_def =
258 self.hax_def(&trait_def.this().with_def_id(self.hax_state(), item_def_id))?;
259 if let hax::FullDefKind::AssocFn {
260 sig,
261 vtable_sig: Some(_),
262 ..
263 } = item_def.kind()
264 {
265 let name = self.translate_trait_item_name(&item_def_id)?;
266 fields.push(TrVTableField::Method(name, sig.clone()));
267 }
268 }
269 }
270
271 for (i, (clause, _span)) in implied_predicates.predicates.iter().enumerate() {
273 if let hax::ClauseKind::Trait(pred) = clause.kind.hax_skip_binder_ref()
275 && self.pred_is_for_self(&pred.trait_ref)
276 {
277 if !self.trait_is_dyn_compatible(&pred.trait_ref.def_id)? {
278 self.assert_is_destruct(&pred.trait_ref);
280 continue;
281 }
282 let trait_clause_id = TraitClauseId::from_raw(i);
283 supertrait_map[trait_clause_id] = Some(fields.next_idx());
284 fields.push(TrVTableField::SuperTrait(trait_clause_id, clause.clone()));
285 }
286 }
287
288 Ok(VTableData {
289 fields,
290 supertrait_map,
291 })
292 }
293
294 fn assert_is_destruct(&self, tref: &hax::TraitRef) {
300 assert!(
301 tref.def_id
302 .as_rust_def_id()
303 .is_some_and(|id| self.tcx.is_lang_item(id, rustc_hir::LangItem::Destruct)),
304 "unexpected non-dyn compatible supertrait: {:?}",
305 tref.def_id
306 );
307 }
308
309 fn gen_vtable_struct_fields(
310 &mut self,
311 span: Span,
312 vtable_data: &VTableData,
313 ) -> Result<IndexVec<FieldId, Field>, Error> {
314 let mut fields = IndexVec::new();
315 let mut supertrait_counter = (0..).into_iter();
316 for field in &vtable_data.fields {
317 let (name, ty) = match field {
318 TrVTableField::Size => ("size".into(), usize_ty()),
319 TrVTableField::Align => ("align".into(), usize_ty()),
320 TrVTableField::Drop => {
321 let self_ty =
322 TyKind::TypeVar(DeBruijnVar::new_at_zero(TypeVarId::ZERO)).into_ty();
323 let self_ptr = TyKind::RawPtr(self_ty, RefKind::Mut).into_ty();
324 let drop_ty = Ty::new(TyKind::FnPtr(RegionBinder::empty(FunSig {
325 is_unsafe: true,
326 inputs: [self_ptr].into(),
327 output: Ty::mk_unit(),
328 })));
329 ("drop".into(), drop_ty)
330 }
331 TrVTableField::Method(item_name, sig) => {
332 let sig = self.translate_poly_fun_sig(span, &sig)?;
335 let ty = TyKind::FnPtr(sig).into_ty();
336 let field_name = format!("method_{}", item_name.0);
337 (field_name, ty)
338 }
339 TrVTableField::SuperTrait(_, clause) => {
340 let vtbl_struct =
341 self.translate_region_binder(span, &clause.kind, |ctx, kind| {
342 let hax::ClauseKind::Trait(pred) = kind else {
343 unreachable!()
344 };
345 ctx.translate_vtable_struct_ref(span, &pred.trait_ref)
346 })?;
347 let vtbl_struct = self.erase_region_binder(vtbl_struct);
348 let ty = Ty::new(TyKind::Ref(
349 Region::Static,
350 Ty::new(TyKind::Adt(vtbl_struct)),
351 RefKind::Shared,
352 ));
353 let name = format!("super_trait_{}", supertrait_counter.next().unwrap());
354 (name, ty)
355 }
356 };
357 fields.push(Field {
358 span,
359 attr_info: AttrInfo::dummy_public(),
360 name: Some(name),
361 ty,
362 });
363 }
364 Ok(fields)
365 }
366
367 pub(crate) fn check_no_monomorphize(&self, span: Span) -> Result<(), Error> {
369 if self.monomorphize() {
370 raise_error!(
371 self,
372 span,
373 "`dyn Trait` is not yet supported with `--monomorphize`"
374 )
375 }
376 Ok(())
377 }
378
379 pub(crate) fn translate_vtable_struct(
394 mut self,
395 type_id: TypeDeclId,
396 item_meta: ItemMeta,
397 trait_def: &hax::FullDef,
398 ) -> Result<TypeDecl, Error> {
399 let span = item_meta.span;
400 if !self.trait_is_dyn_compatible(trait_def.def_id())? {
401 raise_error!(
402 self,
403 span,
404 "Trying to compute the vtable type \
405 for a non-dyn-compatible trait"
406 );
407 }
408 self.check_no_monomorphize(span)?;
409
410 let (hax::FullDefKind::Trait {
411 dyn_self,
412 implied_predicates,
413 ..
414 }
415 | hax::FullDefKind::TraitAlias {
416 dyn_self,
417 implied_predicates,
418 ..
419 }) = trait_def.kind()
420 else {
421 panic!()
422 };
423 let Some(dyn_self) = dyn_self else {
424 panic!("Trying to generate a vtable for a non-dyn-compatible trait")
425 };
426
427 let mut dyn_self = {
429 let dyn_self = self.translate_ty(span, dyn_self)?;
430 let TyKind::DynTrait(mut dyn_pred) = dyn_self.kind().clone() else {
431 panic!("incorrect `dyn_self`")
432 };
433
434 for (i, ty_constraint) in dyn_pred
437 .binder
438 .params
439 .trait_type_constraints
440 .iter_mut()
441 .enumerate()
442 {
443 let name = format!("Ty{i}");
444 let new_ty = self
445 .the_only_binder_mut()
446 .params
447 .types
448 .push_with(|index| TypeParam { index, name });
449 let new_ty =
452 TyKind::TypeVar(DeBruijnVar::bound(DeBruijnId::new(2), new_ty)).into_ty();
453 ty_constraint.skip_binder.ty = new_ty;
454 }
455 TyKind::DynTrait(dyn_pred).into_ty()
456 };
457
458 let mut field_map = IndexVec::new();
459 let mut supertrait_map: IndexMap<TraitClauseId, _> =
460 (0..implied_predicates.predicates.len())
461 .map(|_| None)
462 .collect();
463 let (mut kind, layout) = if item_meta.opacity.with_private_contents().is_opaque() {
464 (TypeDeclKind::Opaque, None)
465 } else {
466 let vtable_data = self.prepare_vtable_fields(trait_def, implied_predicates)?;
469 let fields = self.gen_vtable_struct_fields(span, &vtable_data)?;
470 let kind = TypeDeclKind::Struct(fields);
471 let layout = self.generate_naive_layout(span, &kind)?;
472 supertrait_map = vtable_data.supertrait_map;
473 field_map = vtable_data.fields.map_ref(|tr_field| match *tr_field {
474 TrVTableField::Size => VTableField::Size,
475 TrVTableField::Align => VTableField::Align,
476 TrVTableField::Drop => VTableField::Drop,
477 TrVTableField::Method(name, ..) => VTableField::Method(name),
478 TrVTableField::SuperTrait(clause_id, ..) => VTableField::SuperTrait(clause_id),
479 });
480 (kind, Some(layout))
481 };
482
483 let mut generics = self.into_generics();
486 {
487 dyn_self = dynify(dyn_self, None, false);
488 generics = dynify(generics, Some(dyn_self.clone()), false);
489 kind = dynify(kind, Some(dyn_self.clone()), true);
490 generics.types.remove_and_shift_ids(TypeVarId::ZERO);
491 generics.types.iter_mut().for_each(|ty| {
492 ty.index -= 1;
493 });
494 }
495
496 let dyn_predicate = dyn_self
497 .kind()
498 .as_dyn_trait()
499 .expect("incorrect `dyn_self`");
500 Ok(TypeDecl {
501 def_id: type_id,
502 item_meta: item_meta,
503 generics: generics,
504 src: ItemSource::VTableTy {
505 dyn_predicate: dyn_predicate.clone(),
506 field_map,
507 supertrait_map,
508 },
509 kind,
510 layout,
511 ptr_metadata: PtrMetadata::None,
513 repr: None,
514 })
515 }
516}
517
518impl ItemTransCtx<'_, '_> {
520 pub fn translate_vtable_instance_const(
522 &mut self,
523 span: Span,
524 impl_expr: &hax::ImplExpr,
525 ) -> Result<Box<ConstantExpr>, Error> {
526 let tref = impl_expr.r#trait.hax_skip_binder_ref();
527 if !self.trait_is_dyn_compatible(&tref.def_id)? {
528 raise_error!(
529 self,
530 span,
531 "Trait {:?} should be dyn-compatible",
532 tref.def_id
533 );
534 }
535
536 let vtbl_ty = {
537 let vtbl_ty = self.translate_region_binder(span, &impl_expr.r#trait, |ctx, tref| {
538 ctx.translate_vtable_struct_ref(span, tref)
539 })?;
540 let vtbl_ty = self.erase_region_binder(vtbl_ty);
541 TyKind::Adt(vtbl_ty).into_ty()
542 };
543 let ty = TyKind::Ref(Region::Static, vtbl_ty.clone(), RefKind::Shared).into_ty();
544
545 let kind = {
546 if let hax::ImplExprAtom::Concrete(impl_item) = &impl_expr.r#impl {
547 let vtable_instance =
550 self.translate_region_binder(span, &impl_expr.r#trait, |ctx, tref| {
551 ctx.translate_vtable_instance_ref(span, tref, impl_item)
552 })?;
553 let vtable_instance = self.erase_region_binder(vtable_instance);
554 let vtable_instance = Box::new(ConstantExpr {
555 kind: ConstantExprKind::Global(vtable_instance),
556 ty: vtbl_ty,
557 });
558 ConstantExprKind::Ref(vtable_instance, None)
559 } else {
560 ConstantExprKind::VTableRef(self.translate_trait_impl_expr(span, impl_expr)?)
561 }
562 };
563
564 Ok(Box::new(ConstantExpr { kind, ty }))
565 }
566
567 pub fn translate_vtable_instance_ref(
569 &mut self,
570 span: Span,
571 trait_ref: &hax::TraitRef,
572 impl_ref: &hax::ItemRef,
573 ) -> Result<GlobalDeclRef, Error> {
574 Ok(self
575 .translate_vtable_instance_ref_maybe_enqueue(true, span, trait_ref, impl_ref)?
576 .expect("trait should be dyn-compatible"))
577 }
578
579 pub fn translate_vtable_instance_ref_no_enqueue(
580 &mut self,
581 span: Span,
582 trait_ref: &hax::TraitRef,
583 impl_ref: &hax::ItemRef,
584 ) -> Result<Option<GlobalDeclRef>, Error> {
585 self.translate_vtable_instance_ref_maybe_enqueue(false, span, trait_ref, impl_ref)
586 }
587
588 pub fn translate_vtable_instance_ref_maybe_enqueue(
589 &mut self,
590 enqueue: bool,
591 span: Span,
592 trait_ref: &hax::TraitRef,
593 impl_ref: &hax::ItemRef,
594 ) -> Result<Option<GlobalDeclRef>, Error> {
595 if !self.trait_is_dyn_compatible(&trait_ref.def_id)? {
596 return Ok(None);
597 }
598 let vtable_ref: GlobalDeclRef = self.translate_item_maybe_enqueue(
603 span,
604 enqueue,
605 impl_ref,
606 TransItemSourceKind::VTableInstance(TraitImplSource::Normal),
607 )?;
608 Ok(Some(vtable_ref))
609 }
610
611 fn get_vtable_instance_info<'a>(
613 &mut self,
614 span: Span,
615 impl_def: &'a hax::FullDef,
616 impl_kind: &TraitImplSource,
617 ) -> Result<(TraitImplRef, TypeDeclRef), Error> {
618 let implemented_trait = match impl_def.kind() {
619 hax::FullDefKind::TraitImpl { trait_pred, .. } => &trait_pred.trait_ref,
620 _ => unreachable!(),
621 };
622 let vtable_struct_ref = self.translate_vtable_struct_ref(span, implemented_trait)?;
623 let impl_ref = self.translate_item(
624 span,
625 impl_def.this(),
626 TransItemSourceKind::TraitImpl(*impl_kind),
627 )?;
628 Ok((impl_ref, vtable_struct_ref))
629 }
630
631 pub(crate) fn translate_vtable_instance(
646 mut self,
647 global_id: GlobalDeclId,
648 item_meta: ItemMeta,
649 impl_def: &hax::FullDef,
650 impl_kind: &TraitImplSource,
651 ) -> Result<GlobalDecl, Error> {
652 let span = item_meta.span;
653 self.check_no_monomorphize(span)?;
654
655 let (impl_ref, vtable_struct_ref) =
656 self.get_vtable_instance_info(span, impl_def, impl_kind)?;
657 let init = self.register_item(
659 span,
660 impl_def.this(),
661 TransItemSourceKind::VTableInstanceInitializer(*impl_kind),
662 );
663
664 Ok(GlobalDecl {
665 def_id: global_id,
666 item_meta,
667 generics: self.into_generics(),
668 src: ItemSource::VTableInstance { impl_ref },
669 global_kind: GlobalKind::Static,
671 ty: Ty::new(TyKind::Adt(vtable_struct_ref)),
672 init,
673 })
674 }
675
676 fn add_method_to_vtable_value(
677 &mut self,
678 span: Span,
679 impl_def: &hax::FullDef,
680 item: &hax::ImplAssocItem,
681 ) -> Result<Option<ConstantExprKind>, Error> {
682 let item_def = self.poly_hax_def(&item.decl_def_id)?;
684 let hax::FullDefKind::AssocFn {
685 vtable_sig: Some(_),
686 ..
687 } = item_def.kind()
688 else {
689 return Ok(None);
690 };
691
692 let const_kind = match &item.value {
693 hax::ImplAssocItemValue::Provided {
694 def_id: item_def_id,
695 ..
696 } => {
697 let item_ref = impl_def.this().with_def_id(self.hax_state(), item_def_id);
700 let shim_ref =
701 self.translate_fn_ptr(span, &item_ref, TransItemSourceKind::VTableMethod)?;
702 ConstantExprKind::FnDef(shim_ref)
703 }
704 hax::ImplAssocItemValue::DefaultedFn { .. } => ConstantExprKind::Opaque(
705 "shim for default methods aren't yet supported".to_string(),
706 ),
707 _ => return Ok(None),
708 };
709
710 Ok(Some(const_kind))
711 }
712
713 fn gen_vtable_instance_init_body(
721 &mut self,
722 span: Span,
723 impl_def: &hax::FullDef,
724 vtable_struct_ref: TypeDeclRef,
725 ) -> Result<Body, Error> {
726 let hax::FullDefKind::TraitImpl {
727 trait_pred,
728 implied_impl_exprs,
729 items,
730 ..
731 } = impl_def.kind()
732 else {
733 unreachable!()
734 };
735
736 let trait_def = self.hax_def(&trait_pred.trait_ref)?;
737 let hax::FullDefKind::Trait {
738 implied_predicates: implied_preds,
739 ..
740 } = trait_def.kind()
741 else {
742 unreachable!()
743 };
744
745 let implemented_trait = self.translate_trait_decl_ref(span, &trait_pred.trait_ref)?;
746 let self_ty = &implemented_trait.generics.types[0];
748
749 let mut builder = BodyBuilder::new(span, 0);
750 let ret_ty = Ty::new(TyKind::Adt(vtable_struct_ref.clone()));
751 let ret_place = builder.new_var(Some("ret".into()), ret_ty.clone());
752
753 let vtable_data = self.prepare_vtable_fields(&trait_def, implied_preds)?;
754 let field_tys = {
757 let vtable_decl_id = vtable_struct_ref.id.as_adt().unwrap().clone();
758 let ItemRef::Type(vtable_def) = self.t_ctx.get_or_translate(vtable_decl_id.into())?
759 else {
760 unreachable!()
761 };
762 let fields = match &vtable_def.kind {
763 TypeDeclKind::Struct(fields) => fields,
764 TypeDeclKind::Opaque => return Ok(Body::Opaque),
765 TypeDeclKind::Error(error) => return Err(Error::new(span, error.clone())),
766 _ => unreachable!(),
767 };
768 fields
769 .iter()
770 .map(|f| &f.ty)
771 .cloned()
772 .map(|ty| ty.substitute(&vtable_struct_ref.generics))
773 .collect_vec()
774 };
775
776 let mut aggregate_fields = vec![];
778 let mut items_iter = items.iter();
779 for (field, ty) in vtable_data.fields.into_iter().zip(field_tys) {
780 let mk_const = |kind| {
781 Operand::Const(Box::new(ConstantExpr {
782 kind,
783 ty: ty.clone(),
784 }))
785 };
786 let op = match field {
787 TrVTableField::Size => {
788 let size_local = builder.new_var(Some("size".to_string()), ty);
789 builder.push_statement(StatementKind::Assign(
790 size_local.clone(),
791 Rvalue::NullaryOp(NullOp::SizeOf, self_ty.clone()),
792 ));
793 Operand::Move(size_local)
794 }
795 TrVTableField::Align => {
796 let align_local = builder.new_var(Some("align".to_string()), ty);
797 builder.push_statement(StatementKind::Assign(
798 align_local.clone(),
799 Rvalue::NullaryOp(NullOp::AlignOf, self_ty.clone()),
800 ));
801 Operand::Move(align_local)
802 }
803 TrVTableField::Drop => {
804 let drop_shim = self.translate_item(
805 span,
806 impl_def.this(),
807 TransItemSourceKind::VTableDropShim,
808 )?;
809 mk_const(ConstantExprKind::FnDef(drop_shim))
810 }
811 TrVTableField::Method(..) => 'a: {
812 for item in items_iter.by_ref() {
815 if let Some(kind) = self.add_method_to_vtable_value(span, impl_def, item)? {
816 break 'a mk_const(kind);
817 }
818 }
819 unreachable!()
820 }
821 TrVTableField::SuperTrait(clause_id, _) => {
822 let impl_expr = &implied_impl_exprs[clause_id.index()];
823 let vtable = self.translate_vtable_instance_const(span, impl_expr)?;
824 Operand::Const(vtable)
825 }
826 };
827 aggregate_fields.push(op);
828 }
829
830 builder.push_statement(StatementKind::Assign(
832 ret_place,
833 Rvalue::Aggregate(
834 AggregateKind::Adt(vtable_struct_ref.clone(), None, None),
835 aggregate_fields,
836 ),
837 ));
838
839 Ok(Body::Unstructured(builder.build()))
840 }
841
842 pub(crate) fn translate_vtable_instance_init(
843 mut self,
844 init_func_id: FunDeclId,
845 item_meta: ItemMeta,
846 impl_def: &hax::FullDef,
847 impl_kind: &TraitImplSource,
848 ) -> Result<FunDecl, Error> {
849 let span = item_meta.span;
850 self.check_no_monomorphize(span)?;
851
852 let (impl_ref, vtable_struct_ref) =
853 self.get_vtable_instance_info(span, impl_def, impl_kind)?;
854 let init_for = self.register_item(
855 span,
856 impl_def.this(),
857 TransItemSourceKind::VTableInstance(*impl_kind),
858 );
859
860 let sig = FunSig {
862 is_unsafe: false,
863 inputs: vec![],
864 output: Ty::new(TyKind::Adt(vtable_struct_ref.clone())),
865 };
866
867 let body = match impl_kind {
868 _ if item_meta.opacity.with_private_contents().is_opaque() => Body::Opaque,
869 TraitImplSource::Normal => {
870 self.gen_vtable_instance_init_body(span, impl_def, vtable_struct_ref)?
871 }
872 _ => {
873 raise_error!(
874 self,
875 span,
876 "Don't know how to generate a vtable for a virtual impl {impl_kind:?}"
877 );
878 }
879 };
880
881 Ok(FunDecl {
882 def_id: init_func_id,
883 item_meta: item_meta,
884 generics: self.into_generics(),
885 signature: sig,
886 src: ItemSource::VTableInstance { impl_ref },
887 is_global_initializer: Some(init_for),
888 body,
889 })
890 }
891
892 fn translate_vtable_shim_body(
910 &mut self,
911 span: Span,
912 target_receiver: &Ty,
913 shim_signature: &FunSig,
914 impl_func_def: &hax::FullDef,
915 ) -> Result<Body, Error> {
916 let mut builder = BodyBuilder::new(span, shim_signature.inputs.len());
917
918 let ret_place = builder.new_var(None, shim_signature.output.clone());
919 let mut method_args = shim_signature
920 .inputs
921 .iter()
922 .map(|ty| builder.new_var(None, ty.clone()))
923 .collect_vec();
924 let target_self = builder.new_var(None, target_receiver.clone());
925
926 let shim_self = mem::replace(&mut method_args[0], target_self.clone());
928
929 let rval = Rvalue::UnaryOp(
933 UnOp::Cast(CastKind::Concretize(
934 shim_self.ty().clone(),
935 target_self.ty().clone(),
936 )),
937 Operand::Move(shim_self.clone()),
938 );
939 builder.push_statement(StatementKind::Assign(target_self.clone(), rval));
940
941 let fun_id = self.register_item(span, &impl_func_def.this(), TransItemSourceKind::Fun);
942 let generics = self.outermost_binder().params.identity_args();
943 builder.call(Call {
944 func: FnOperand::Regular(FnPtr::new(FnPtrKind::Fun(fun_id), generics)),
945 args: method_args
946 .into_iter()
947 .map(|arg| Operand::Move(arg))
948 .collect(),
949 dest: ret_place,
950 });
951
952 Ok(Body::Unstructured(builder.build()))
953 }
954
955 fn translate_vtable_drop_shim_body(
967 &mut self,
968 span: Span,
969 shim_receiver: &Ty,
970 target_receiver: &Ty,
971 trait_pred: &TraitPredicate,
972 ) -> Result<Body, Error> {
973 let mut builder = BodyBuilder::new(span, 1);
974
975 builder.new_var(Some("ret".into()), Ty::mk_unit());
976 let dyn_self = builder.new_var(Some("dyn_self".into()), shim_receiver.clone());
977 let target_self = builder.new_var(Some("target_self".into()), target_receiver.clone());
978
979 let rval = Rvalue::UnaryOp(
981 UnOp::Cast(CastKind::Concretize(
982 dyn_self.ty().clone(),
983 target_self.ty().clone(),
984 )),
985 Operand::Move(dyn_self.clone()),
986 );
987 builder.push_statement(StatementKind::Assign(target_self.clone(), rval));
988
989 let destruct_trait = self.tcx.lang_items().destruct_trait().unwrap();
994 let impl_expr: hax::ImplExpr = {
995 let s = self.hax_state_with_id();
996 let rustc_trait_args = trait_pred.trait_ref.rustc_args(s);
997 let generics = self.tcx.mk_args(&rustc_trait_args[..1]); let tref =
999 rustc_middle::ty::TraitRef::new_from_args(self.tcx, destruct_trait, generics);
1000 hax::solve_trait(s, rustc_middle::ty::Binder::dummy(tref))
1001 };
1002 let tref = self.translate_trait_impl_expr(span, &impl_expr)?;
1003
1004 let drop_arg = target_self.clone().deref();
1006 builder.insert_drop(drop_arg, tref);
1007
1008 Ok(Body::Unstructured(builder.build()))
1009 }
1010
1011 pub(crate) fn translate_vtable_drop_shim(
1012 mut self,
1013 fun_id: FunDeclId,
1014 item_meta: ItemMeta,
1015 impl_def: &hax::FullDef,
1016 ) -> Result<FunDecl, Error> {
1017 let span = item_meta.span;
1018
1019 let hax::FullDefKind::TraitImpl {
1020 dyn_self: Some(dyn_self),
1021 trait_pred,
1022 ..
1023 } = impl_def.kind()
1024 else {
1025 raise_error!(
1026 self,
1027 span,
1028 "Trying to generate a vtable drop shim for a non-trait impl"
1029 );
1030 };
1031
1032 let ref_dyn_self =
1034 TyKind::RawPtr(self.translate_ty(span, dyn_self)?, RefKind::Mut).into_ty();
1035 let ref_target_self = {
1037 let impl_trait = self.translate_trait_ref(span, &trait_pred.trait_ref)?;
1038 TyKind::RawPtr(impl_trait.generics.types[0].clone(), RefKind::Mut).into_ty()
1039 };
1040
1041 let signature = FunSig {
1043 is_unsafe: true,
1044 inputs: vec![ref_dyn_self.clone()],
1045 output: Ty::mk_unit(),
1046 };
1047
1048 let body: Body = self.translate_vtable_drop_shim_body(
1049 span,
1050 &ref_dyn_self,
1051 &ref_target_self,
1052 trait_pred,
1053 )?;
1054
1055 Ok(FunDecl {
1056 def_id: fun_id,
1057 item_meta,
1058 generics: self.into_generics(),
1059 signature,
1060 src: ItemSource::VTableMethodShim,
1061 is_global_initializer: None,
1062 body,
1063 })
1064 }
1065
1066 pub(crate) fn translate_vtable_shim(
1067 mut self,
1068 fun_id: FunDeclId,
1069 item_meta: ItemMeta,
1070 impl_func_def: &hax::FullDef,
1071 ) -> Result<FunDecl, Error> {
1072 let span = item_meta.span;
1073 self.check_no_monomorphize(span)?;
1074
1075 let hax::FullDefKind::AssocFn {
1076 vtable_sig: Some(vtable_sig),
1077 sig: target_signature,
1078 ..
1079 } = impl_func_def.kind()
1080 else {
1081 raise_error!(
1082 self,
1083 span,
1084 "Trying to generate a vtable shim for a non-vtable-safe method"
1085 );
1086 };
1087
1088 let signature = self.translate_fun_sig(span, &vtable_sig.value)?;
1090 let target_receiver = self.translate_ty(span, &target_signature.value.inputs[0])?;
1092
1093 trace!(
1094 "[VtableShim] Obtained dyn signature with receiver type: {}",
1095 signature.inputs[0].with_ctx(&self.into_fmt())
1096 );
1097
1098 let body = if item_meta.opacity.with_private_contents().is_opaque() {
1099 Body::Opaque
1100 } else {
1101 self.translate_vtable_shim_body(span, &target_receiver, &signature, impl_func_def)?
1102 };
1103
1104 Ok(FunDecl {
1105 def_id: fun_id,
1106 item_meta,
1107 generics: self.into_generics(),
1108 signature,
1109 src: ItemSource::VTableMethodShim,
1110 is_global_initializer: None,
1111 body,
1112 })
1113 }
1114}