charon_driver/translate/
translate_trait_objects.rs

1use charon_lib::ast::ullbc_ast_utils::BodyBuilder;
2use hax::TraitPredicate;
3use itertools::Itertools;
4use std::mem;
5
6use super::{
7    translate_crate::TransItemSourceKind, translate_ctx::*, translate_generics::BindingLevel,
8};
9use charon_lib::formatter::IntoFormatter;
10use charon_lib::ids::Vector;
11use charon_lib::pretty::FmtWithCtx;
12use charon_lib::ullbc_ast::*;
13
14fn dummy_public_attr_info() -> AttrInfo {
15    AttrInfo {
16        public: true,
17        ..Default::default()
18    }
19}
20
21fn usize_ty() -> Ty {
22    Ty::new(TyKind::Literal(LiteralTy::UInt(UIntTy::Usize)))
23}
24
25/// Takes a `T` valid in the context of a trait ref and transforms it into a `T` valid in the
26/// context of its vtable definition, i.e. no longer mentions the `Self` type or `Self` clause. If
27/// `new_self` is `Some`, we replace any mention of the `Self` type with it; otherwise we panic if
28/// `Self` is mentioned.
29/// If `for_method` is true, we're handling a value coming from a `AssocFn`, which takes the `Self`
30/// clause as its first clause parameter. Otherwise we're in trait scope, where the `Self` clause
31/// is represented with `TraitRefKind::SelfId`.
32fn dynify<T: TyVisitable>(mut x: T, new_self: Option<Ty>, for_method: bool) -> T {
33    struct ReplaceSelfVisitor {
34        new_self: Option<Ty>,
35        for_method: bool,
36    }
37    impl VarsVisitor for ReplaceSelfVisitor {
38        fn visit_type_var(&mut self, v: TypeDbVar) -> Option<Ty> {
39            if let DeBruijnVar::Bound(DeBruijnId::ZERO, type_id) = v {
40                // Replace type 0 and decrement the others.
41                Some(if let Some(new_id) = type_id.index().checked_sub(1) {
42                    TyKind::TypeVar(DeBruijnVar::Bound(DeBruijnId::ZERO, TypeVarId::new(new_id)))
43                        .into_ty()
44                } else {
45                    self.new_self.clone().expect(
46                        "Found unexpected `Self` 
47                        type when constructing vtable",
48                    )
49                })
50            } else {
51                None
52            }
53        }
54
55        fn visit_clause_var(&mut self, v: ClauseDbVar) -> Option<TraitRefKind> {
56            if let DeBruijnVar::Bound(DeBruijnId::ZERO, clause_id) = v {
57                if self.for_method && clause_id == TraitClauseId::ZERO {
58                    // That's the `Self` clause.
59                    Some(TraitRefKind::Dyn)
60                } else {
61                    panic!("Found unexpected clause var when constructing vtable: {v}")
62                }
63            } else {
64                None
65            }
66        }
67
68        fn visit_self_clause(&mut self) -> Option<TraitRefKind> {
69            Some(TraitRefKind::Dyn)
70        }
71    }
72    x.visit_vars(&mut ReplaceSelfVisitor {
73        new_self,
74        for_method,
75    });
76    x
77}
78
79//// Translate the `dyn Trait` type.
80impl ItemTransCtx<'_, '_> {
81    pub fn check_at_most_one_pred_has_methods(
82        &mut self,
83        span: Span,
84        preds: &hax::GenericPredicates,
85    ) -> Result<(), Error> {
86        // Only the first clause is allowed to have methods.
87        for (clause, _) in preds.predicates.iter().skip(1) {
88            if let hax::ClauseKind::Trait(trait_predicate) = clause.kind.hax_skip_binder_ref() {
89                let trait_def_id = &trait_predicate.trait_ref.def_id;
90                let trait_def = self.poly_hax_def(trait_def_id)?;
91                let has_methods = match trait_def.kind() {
92                    hax::FullDefKind::Trait { items, .. } => items
93                        .iter()
94                        .any(|assoc| matches!(assoc.kind, hax::AssocKind::Fn { .. })),
95                    hax::FullDefKind::TraitAlias { .. } => false,
96                    _ => unreachable!(),
97                };
98                if has_methods {
99                    raise_error!(
100                        self,
101                        span,
102                        "`dyn Trait` with multiple method-bearing predicates is not supported"
103                    );
104                }
105            }
106        }
107        Ok(())
108    }
109
110    pub fn translate_existential_predicates(
111        &mut self,
112        span: Span,
113        self_ty: &hax::ParamTy,
114        preds: &hax::GenericPredicates,
115        region: &hax::Region,
116    ) -> Result<DynPredicate, Error> {
117        // This is a robustness check: the current version of Rustc
118        // accepts at most one method-bearing predicate in a trait object.
119        // But things may change in the future.
120        self.check_at_most_one_pred_has_methods(span, preds)?;
121
122        // Translate the region outside the binder.
123        let region = self.translate_region(span, region)?;
124        let region = region.move_under_binder();
125
126        // Add a binder that contains the existentially quantified type.
127        self.binding_levels.push(BindingLevel::new(true));
128
129        // Add the existentially quantified type.
130        let ty_id = self
131            .innermost_binder_mut()
132            .push_type_var(self_ty.index, self_ty.name.clone());
133        let ty = TyKind::TypeVar(DeBruijnVar::new_at_zero(ty_id)).into_ty();
134
135        self.innermost_binder_mut()
136            .params
137            .types_outlive
138            .push(RegionBinder::empty(OutlivesPred(ty.clone(), region)));
139        self.register_predicates(preds, PredicateOrigin::Dyn)?;
140
141        let params = self.binding_levels.pop().unwrap().params;
142        let binder = Binder {
143            params: params,
144            skip_binder: ty,
145            kind: BinderKind::Dyn,
146        };
147        Ok(DynPredicate { binder })
148    }
149}
150
151//// Generate the vtable struct.
152impl ItemTransCtx<'_, '_> {
153    /// Query whether a trait is dyn compatible.
154    /// TODO(dyn): for now we return `false` if the trait has any associated types, as we don't
155    /// handle associated types in vtables.
156    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    /// Check whether this trait ref is of the form `Self: Trait<...>`.
166    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, "Self");
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<Option<TypeDeclRef>, Error> {
192        self.translate_vtable_struct_ref_maybe_enqueue(true, span, tref)
193    }
194
195    pub fn translate_vtable_struct_ref_no_enqueue(
196        &mut self,
197        span: Span,
198        tref: &hax::TraitRef,
199    ) -> Result<Option<TypeDeclRef>, Error> {
200        self.translate_vtable_struct_ref_maybe_enqueue(false, span, tref)
201    }
202
203    /// Given a trait ref, return a reference to its vtable struct, if it is dyn compatible.
204    pub fn translate_vtable_struct_ref_maybe_enqueue(
205        &mut self,
206        enqueue: bool,
207        span: Span,
208        tref: &hax::TraitRef,
209    ) -> Result<Option<TypeDeclRef>, Error> {
210        if !self.trait_is_dyn_compatible(&tref.def_id)? {
211            return Ok(None);
212        }
213        // Don't enqueue the vtable for translation by default. It will be enqueued if used in a
214        // `dyn Trait`.
215        let mut vtable_ref: TypeDeclRef =
216            self.translate_item_maybe_enqueue(span, enqueue, tref, TransItemSourceKind::VTable)?;
217        // Remove the `Self` type variable from the generic parameters.
218        vtable_ref
219            .generics
220            .types
221            .remove_and_shift_ids(TypeVarId::ZERO);
222
223        // The vtable type also takes associated types as parameters.
224        let assoc_tys: Vec<_> = tref
225            .trait_associated_types(self.hax_state_with_id())
226            .iter()
227            .map(|ty| self.translate_ty(span, ty))
228            .try_collect()?;
229        vtable_ref.generics.types.extend(assoc_tys);
230
231        Ok(Some(vtable_ref))
232    }
233
234    /// Add a `method_name: fn(...) -> ...` field for the method.
235    fn add_method_to_vtable_def(
236        &mut self,
237        span: Span,
238        trait_def: &hax::FullDef,
239        mut mk_field: impl FnMut(String, Ty),
240        item: &hax::AssocItem,
241    ) -> Result<(), Error> {
242        let item_def_id = &item.def_id;
243        let item_def = self.hax_def(
244            &trait_def
245                .this()
246                .with_def_id(&self.t_ctx.hax_state, item_def_id),
247        )?;
248        let hax::FullDefKind::AssocFn {
249            sig,
250            vtable_sig: Some(_),
251            ..
252        } = item_def.kind()
253        else {
254            return Ok(());
255        };
256
257        let item_name = self.t_ctx.translate_trait_item_name(item_def_id)?;
258        // It's ok to translate the method signature in the context of the trait because
259        // `vtable_sig: Some(_)` ensures the method has no generics of its own.
260        let sig = self.translate_fun_sig(span, sig)?;
261        let ty = TyKind::FnPtr(sig).into_ty();
262
263        mk_field(format!("method_{}", item_name.0), ty);
264        Ok(())
265    }
266
267    /// Add `super_trait_n: &'static SuperTraitNVTable` fields.
268    fn add_supertraits_to_vtable_def(
269        &mut self,
270        span: Span,
271        mut mk_field: impl FnMut(String, Ty),
272        implied_predicates: &hax::GenericPredicates,
273    ) -> Result<(), Error> {
274        let mut counter = (0..).into_iter();
275        for (clause, _span) in &implied_predicates.predicates {
276            if let hax::ClauseKind::Trait(pred) = clause.kind.hax_skip_binder_ref() {
277                // If a clause looks like `Self: OtherTrait<...>`, we consider it a supertrait.
278                if !self.pred_is_for_self(&pred.trait_ref) {
279                    continue;
280                }
281                let vtbl_struct = self
282                    .translate_region_binder(span, &clause.kind, |ctx, _| {
283                        ctx.translate_vtable_struct_ref(span, &pred.trait_ref)
284                    })?
285                    .erase()
286                    .expect("parent trait should be dyn compatible");
287                let ty = Ty::new(TyKind::Ref(
288                    Region::Static,
289                    Ty::new(TyKind::Adt(vtbl_struct)),
290                    RefKind::Shared,
291                ));
292                mk_field(format!("super_trait_{}", counter.next().unwrap()), ty);
293            }
294        }
295        Ok(())
296    }
297
298    fn gen_vtable_struct_fields(
299        &mut self,
300        span: Span,
301        trait_def: &hax::FullDef,
302        implied_predicates: &hax::GenericPredicates,
303    ) -> Result<Vector<FieldId, Field>, Error> {
304        let mut fields = Vector::new();
305        let mut mk_field = |name, ty| {
306            fields.push(Field {
307                span,
308                attr_info: dummy_public_attr_info(),
309                name: Some(name),
310                ty,
311            });
312        };
313
314        // Add the basic fields.
315        // Field: `size: usize`
316        mk_field("size".into(), usize_ty());
317        // Field: `align: usize`
318        mk_field("align".into(), usize_ty());
319        // Field: `drop: fn(*mut Self)` -- `Self` is just a placeholder, will be dynified below.
320        mk_field("drop".into(), {
321            let self_ty = TyKind::TypeVar(DeBruijnVar::new_at_zero(TypeVarId::ZERO)).into_ty();
322            let self_ptr = TyKind::RawPtr(self_ty, RefKind::Mut).into_ty();
323            Ty::new(TyKind::FnPtr(RegionBinder::empty((
324                [self_ptr].into(),
325                Ty::mk_unit(),
326            ))))
327        });
328
329        // Add the method pointers (trait aliases don't have methods).
330        if let hax::FullDefKind::Trait { items, .. } = trait_def.kind() {
331            for item in items {
332                self.add_method_to_vtable_def(span, trait_def, &mut mk_field, item)?;
333            }
334        }
335
336        // Add the supertrait vtables.
337        self.add_supertraits_to_vtable_def(span, &mut mk_field, implied_predicates)?;
338
339        Ok(fields)
340    }
341
342    /// This is a temporary check until we support `dyn Trait` with `--monomorphize`.
343    pub(crate) fn check_no_monomorphize(&self, span: Span) -> Result<(), Error> {
344        if self.monomorphize() {
345            raise_error!(
346                self,
347                span,
348                "`dyn Trait` is not yet supported with `--monomorphize`"
349            )
350        }
351        Ok(())
352    }
353
354    /// Construct the type of the vtable for this trait.
355    ///
356    /// It's a struct that has for generics the generics of the trait + one parameter for each
357    /// associated type of the trait and its parents.
358    ///
359    /// struct TraitVTable<TraitArgs.., AssocTys..> {
360    ///   size: usize,
361    ///   align: usize,
362    ///   drop: fn(*mut dyn Trait<...>),
363    ///   method_name: fn(&dyn Trait<...>, Args..) -> Output,
364    ///   ... other methods
365    ///   super_trait_0: &'static SuperTrait0VTable
366    ///   ... other supertraits
367    /// }
368    pub(crate) fn translate_vtable_struct(
369        mut self,
370        type_id: TypeDeclId,
371        item_meta: ItemMeta,
372        trait_def: &hax::FullDef,
373    ) -> Result<TypeDecl, Error> {
374        let span = item_meta.span;
375        if !self.trait_is_dyn_compatible(trait_def.def_id())? {
376            raise_error!(
377                self,
378                span,
379                "Trying to compute the vtable type \
380                for a non-dyn-compatible trait"
381            );
382        }
383        self.check_no_monomorphize(span)?;
384
385        self.translate_def_generics(span, trait_def)?;
386
387        let (hax::FullDefKind::Trait {
388            dyn_self,
389            implied_predicates,
390            ..
391        }
392        | hax::FullDefKind::TraitAlias {
393            dyn_self,
394            implied_predicates,
395            ..
396        }) = trait_def.kind()
397        else {
398            panic!()
399        };
400        let Some(dyn_self) = dyn_self else {
401            panic!("Trying to generate a vtable for a non-dyn-compatible trait")
402        };
403
404        // The `dyn Trait<Args..>` type for this trait.
405        let mut dyn_self = {
406            let dyn_self = self.translate_ty(span, dyn_self)?;
407            let TyKind::DynTrait(mut dyn_pred) = dyn_self.kind().clone() else {
408                panic!("incorrect `dyn_self`")
409            };
410
411            // Add one generic parameter for each associated type of this trait and its parents. We
412            // then use that in `dyn_self`
413            for (i, ty_constraint) in dyn_pred
414                .binder
415                .params
416                .trait_type_constraints
417                .iter_mut()
418                .enumerate()
419            {
420                let name = format!("Ty{i}");
421                let new_ty = self
422                    .the_only_binder_mut()
423                    .params
424                    .types
425                    .push_with(|index| TypeParam { index, name });
426                // Moving that type under two levels of binders: the `DynPredicate` binder and the
427                // type constraint binder.
428                let new_ty =
429                    TyKind::TypeVar(DeBruijnVar::bound(DeBruijnId::new(2), new_ty)).into_ty();
430                ty_constraint.skip_binder.ty = new_ty;
431            }
432            TyKind::DynTrait(dyn_pred).into_ty()
433        };
434
435        let (mut kind, layout) = if item_meta.opacity.with_private_contents().is_opaque() {
436            (TypeDeclKind::Opaque, None)
437        } else {
438            // First construct fields that use the real method signatures (which may use the `Self`
439            // type). We fixup the types and generics below.
440            let fields = self.gen_vtable_struct_fields(span, trait_def, implied_predicates)?;
441            let kind = TypeDeclKind::Struct(fields);
442            let layout = self.generate_naive_layout(span, &kind)?;
443            (kind, Some(layout))
444        };
445
446        // Replace any use of `Self` with `dyn Trait<...>`, and remove the `Self` type variable
447        // from the generic parameters.
448        let mut generics = self.into_generics();
449        {
450            dyn_self = dynify(dyn_self, None, false);
451            generics = dynify(generics, Some(dyn_self.clone()), false);
452            kind = dynify(kind, Some(dyn_self.clone()), true);
453            generics.types.remove_and_shift_ids(TypeVarId::ZERO);
454            generics.types.iter_mut().for_each(|ty| {
455                ty.index -= 1;
456            });
457        }
458
459        let dyn_predicate = dyn_self
460            .kind()
461            .as_dyn_trait()
462            .expect("incorrect `dyn_self`");
463        Ok(TypeDecl {
464            def_id: type_id,
465            item_meta: item_meta,
466            generics: generics,
467            src: ItemSource::VTableTy {
468                dyn_predicate: dyn_predicate.clone(),
469            },
470            kind,
471            layout,
472            // A vtable struct is always sized
473            ptr_metadata: PtrMetadata::None,
474            repr: None,
475        })
476    }
477}
478
479//// Generate a vtable value.
480impl ItemTransCtx<'_, '_> {
481    pub fn translate_vtable_instance_ref(
482        &mut self,
483        span: Span,
484        trait_ref: &hax::TraitRef,
485        impl_ref: &hax::ItemRef,
486    ) -> Result<Option<GlobalDeclRef>, Error> {
487        self.translate_vtable_instance_ref_maybe_enqueue(true, span, trait_ref, impl_ref)
488    }
489
490    pub fn translate_vtable_instance_ref_no_enqueue(
491        &mut self,
492        span: Span,
493        trait_ref: &hax::TraitRef,
494        impl_ref: &hax::ItemRef,
495    ) -> Result<Option<GlobalDeclRef>, Error> {
496        self.translate_vtable_instance_ref_maybe_enqueue(false, span, trait_ref, impl_ref)
497    }
498
499    pub fn translate_vtable_instance_ref_maybe_enqueue(
500        &mut self,
501        enqueue: bool,
502        span: Span,
503        trait_ref: &hax::TraitRef,
504        impl_ref: &hax::ItemRef,
505    ) -> Result<Option<GlobalDeclRef>, Error> {
506        if !self.trait_is_dyn_compatible(&trait_ref.def_id)? {
507            return Ok(None);
508        }
509        // Don't enqueue the vtable for translation by default. It will be enqueued if used in a
510        // `dyn Trait` coercion.
511        // TODO(dyn): To do this properly we'd need to know for each clause whether it ultimately
512        // ends up used in a vtable cast.
513        let vtable_ref: GlobalDeclRef = self.translate_item_maybe_enqueue(
514            span,
515            enqueue,
516            impl_ref,
517            TransItemSourceKind::VTableInstance(TraitImplSource::Normal),
518        )?;
519        Ok(Some(vtable_ref))
520    }
521
522    /// Local helper function to get the vtable struct reference and trait declaration reference
523    fn get_vtable_instance_info<'a>(
524        &mut self,
525        span: Span,
526        impl_def: &'a hax::FullDef,
527        impl_kind: &TraitImplSource,
528    ) -> Result<(TraitImplRef, TypeDeclRef), Error> {
529        let implemented_trait = match impl_def.kind() {
530            hax::FullDefKind::TraitImpl { trait_pred, .. } => &trait_pred.trait_ref,
531            _ => unreachable!(),
532        };
533        let vtable_struct_ref = self
534            .translate_vtable_struct_ref(span, implemented_trait)?
535            .expect("trait should be dyn-compatible");
536        let impl_ref = self.translate_item(
537            span,
538            impl_def.this(),
539            TransItemSourceKind::TraitImpl(*impl_kind),
540        )?;
541        Ok((impl_ref, vtable_struct_ref))
542    }
543
544    /// E.g.,
545    /// ```
546    /// global {impl Trait for Foo}::vtable<Args..>: Trait::{vtable}<TraitArgs.., AssocTys..> {
547    ///     size: size_of(Foo),
548    ///     align: align_of(Foo),
549    ///     drop: <Foo as Destruct>::drop_in_place,
550    ///     method_0: <Foo as Trait>::method_0::{shim},
551    ///     method_1: <Foo as Trait>::method_1::{shim},
552    ///     ...
553    ///     super_trait_0: SuperImpl0<..>::{vtable_instance}::<..>,
554    ///     super_trait_1: SuperImpl1<..>::{vtable_instance}::<..>,
555    ///     ...
556    /// }
557    /// ```
558    pub(crate) fn translate_vtable_instance(
559        mut self,
560        global_id: GlobalDeclId,
561        item_meta: ItemMeta,
562        impl_def: &hax::FullDef,
563        impl_kind: &TraitImplSource,
564    ) -> Result<GlobalDecl, Error> {
565        let span = item_meta.span;
566        self.translate_def_generics(span, impl_def)?;
567        self.check_no_monomorphize(span)?;
568
569        let (impl_ref, vtable_struct_ref) =
570            self.get_vtable_instance_info(span, impl_def, impl_kind)?;
571        // Initializer function for this global.
572        let init = self.register_item(
573            span,
574            impl_def.this(),
575            TransItemSourceKind::VTableInstanceInitializer(*impl_kind),
576        );
577
578        Ok(GlobalDecl {
579            def_id: global_id,
580            item_meta,
581            generics: self.into_generics(),
582            src: ItemSource::VTableInstance { impl_ref },
583            // it should be static to have its own address
584            global_kind: GlobalKind::Static,
585            ty: Ty::new(TyKind::Adt(vtable_struct_ref)),
586            init,
587        })
588    }
589
590    fn add_method_to_vtable_value(
591        &mut self,
592        span: Span,
593        impl_def: &hax::FullDef,
594        item: &hax::ImplAssocItem,
595        mut mk_field: impl FnMut(ConstantExprKind),
596    ) -> Result<(), Error> {
597        // Exit if the item isn't a vtable safe method.
598        match self.poly_hax_def(&item.decl_def_id)?.kind() {
599            hax::FullDefKind::AssocFn {
600                vtable_sig: Some(_),
601                ..
602            } => {}
603            _ => return Ok(()),
604        }
605
606        let const_kind = match &item.value {
607            hax::ImplAssocItemValue::Provided {
608                def_id: item_def_id,
609                ..
610            } => {
611                // The method is vtable safe so it has no generics, hence we can reuse the impl
612                // generics -- the lifetime binder will be added as `Erased` in `translate_fn_ptr`.
613                let item_ref = impl_def.this().with_def_id(self.hax_state(), item_def_id);
614                let shim_ref = self
615                    .translate_fn_ptr(span, &item_ref, TransItemSourceKind::VTableMethod)?
616                    .erase();
617                ConstantExprKind::FnPtr(shim_ref)
618            }
619            hax::ImplAssocItemValue::DefaultedFn { .. } => ConstantExprKind::Opaque(
620                "shim for default methods \
621                    aren't yet supported"
622                    .to_string(),
623            ),
624            _ => return Ok(()),
625        };
626
627        mk_field(const_kind);
628
629        Ok(())
630    }
631
632    fn add_supertraits_to_vtable_value(
633        &mut self,
634        span: Span,
635        trait_def: &hax::FullDef,
636        impl_def: &hax::FullDef,
637        mut mk_field: impl FnMut(ConstantExprKind),
638    ) -> Result<(), Error> {
639        let hax::FullDefKind::TraitImpl {
640            implied_impl_exprs, ..
641        } = impl_def.kind()
642        else {
643            unreachable!()
644        };
645        let hax::FullDefKind::Trait {
646            implied_predicates, ..
647        } = trait_def.kind()
648        else {
649            unreachable!()
650        };
651        for ((clause, _), impl_expr) in implied_predicates.predicates.iter().zip(implied_impl_exprs)
652        {
653            let hax::ClauseKind::Trait(pred) = clause.kind.hax_skip_binder_ref() else {
654                continue;
655            };
656            // If a clause looks like `Self: OtherTrait<...>`, we consider it a supertrait.
657            if !self.pred_is_for_self(&pred.trait_ref) {
658                continue;
659            }
660
661            let vtable_def_ref = self
662                .translate_region_binder(span, &impl_expr.r#trait, |ctx, tref| {
663                    ctx.translate_vtable_struct_ref(span, tref)
664                })?
665                .erase()
666                .expect("parent trait should be dyn compatible");
667            let fn_ptr_ty = TyKind::Adt(vtable_def_ref).into_ty();
668            let kind = match &impl_expr.r#impl {
669                hax::ImplExprAtom::Concrete(impl_item) => {
670                    let vtable_instance_ref = self
671                        .translate_region_binder(span, &impl_expr.r#trait, |ctx, tref| {
672                            ctx.translate_vtable_instance_ref(span, tref, impl_item)
673                        })?
674                        .erase()
675                        .expect("parent trait should be dyn compatible");
676                    let global = Box::new(ConstantExpr {
677                        kind: ConstantExprKind::Global(vtable_instance_ref),
678                        ty: fn_ptr_ty,
679                    });
680                    ConstantExprKind::Ref(global)
681                }
682                // TODO(dyn): builtin impls
683                _ => ConstantExprKind::Opaque("missing supertrait vtable".into()),
684            };
685            mk_field(kind);
686        }
687        Ok(())
688    }
689
690    /// Generate the body of the vtable instance function.
691    /// This is for `impl Trait for T` implementation, it does NOT handle builtin impls.
692    /// ```ignore
693    /// let ret@0 : VTable;
694    /// ret@0 = VTable { ... };
695    /// return;
696    /// ```
697    fn gen_vtable_instance_init_body(
698        &mut self,
699        span: Span,
700        impl_def: &hax::FullDef,
701        vtable_struct_ref: TypeDeclRef,
702    ) -> Result<Body, Error> {
703        let hax::FullDefKind::TraitImpl {
704            trait_pred, items, ..
705        } = impl_def.kind()
706        else {
707            unreachable!()
708        };
709        let trait_def = self.hax_def(&trait_pred.trait_ref)?;
710        let implemented_trait = self.translate_trait_decl_ref(span, &trait_pred.trait_ref)?;
711        // The type this impl is for.
712        let self_ty = &implemented_trait.generics.types[0];
713
714        let mut builder = BodyBuilder::new(span, 0);
715        let ret_ty = Ty::new(TyKind::Adt(vtable_struct_ref.clone()));
716        let ret_place = builder.new_var(Some("ret".into()), ret_ty.clone());
717
718        // Retreive the expected field types from the struct definition. This avoids complicated
719        // substitutions.
720        let field_tys = {
721            let vtable_decl_id = vtable_struct_ref.id.as_adt().unwrap().clone();
722            let ItemRef::Type(vtable_def) = self.t_ctx.get_or_translate(vtable_decl_id.into())?
723            else {
724                unreachable!()
725            };
726            let TypeDeclKind::Struct(fields) = &vtable_def.kind else {
727                unreachable!()
728            };
729            fields
730                .iter()
731                .map(|f| &f.ty)
732                .cloned()
733                .map(|ty| ty.substitute(&vtable_struct_ref.generics))
734                .collect_vec()
735        };
736
737        let mut aggregate_fields = vec![];
738        // For each vtable field, assign the desired value to a new local.
739        let mut field_ty_iter = field_tys.into_iter();
740
741        let size_ty = field_ty_iter.next().unwrap();
742        let size_local = builder.new_var(Some("size".to_string()), size_ty);
743        builder.push_statement(StatementKind::Assign(
744            size_local.clone(),
745            Rvalue::NullaryOp(NullOp::SizeOf, self_ty.clone()),
746        ));
747        aggregate_fields.push(Operand::Move(size_local));
748
749        let align_ty = field_ty_iter.next().unwrap();
750        let align_local = builder.new_var(Some("align".to_string()), align_ty);
751        builder.push_statement(StatementKind::Assign(
752            align_local.clone(),
753            Rvalue::NullaryOp(NullOp::AlignOf, self_ty.clone()),
754        ));
755        aggregate_fields.push(Operand::Move(align_local));
756
757        // Helper to fill in the remaining fields with constant values.
758        let mut mk_field = |kind| {
759            let ty = field_ty_iter.next().unwrap();
760            aggregate_fields.push(Operand::Const(Box::new(ConstantExpr { kind, ty })));
761        };
762
763        let drop_shim =
764            self.translate_item(span, impl_def.this(), TransItemSourceKind::VTableDropShim)?;
765
766        mk_field(ConstantExprKind::FnPtr(drop_shim));
767
768        for item in items {
769            self.add_method_to_vtable_value(span, impl_def, item, &mut mk_field)?;
770        }
771
772        self.add_supertraits_to_vtable_value(span, &trait_def, impl_def, &mut mk_field)?;
773
774        if field_ty_iter.next().is_some() {
775            raise_error!(
776                self,
777                span,
778                "Missed some fields in vtable value construction"
779            )
780        }
781
782        // Construct the final struct.
783        builder.push_statement(StatementKind::Assign(
784            ret_place,
785            Rvalue::Aggregate(
786                AggregateKind::Adt(vtable_struct_ref.clone(), None, None),
787                aggregate_fields,
788            ),
789        ));
790
791        Ok(Body::Unstructured(builder.build()))
792    }
793
794    pub(crate) fn translate_vtable_instance_init(
795        mut self,
796        init_func_id: FunDeclId,
797        item_meta: ItemMeta,
798        impl_def: &hax::FullDef,
799        impl_kind: &TraitImplSource,
800    ) -> Result<FunDecl, Error> {
801        let span = item_meta.span;
802        self.translate_def_generics(span, impl_def)?;
803        self.check_no_monomorphize(span)?;
804
805        let (impl_ref, vtable_struct_ref) =
806            self.get_vtable_instance_info(span, impl_def, impl_kind)?;
807        let init_for = self.register_item(
808            span,
809            impl_def.this(),
810            TransItemSourceKind::VTableInstance(*impl_kind),
811        );
812
813        // Signature: `() -> VTable`.
814        let sig = FunSig {
815            is_unsafe: false,
816            generics: self.the_only_binder().params.clone(),
817            inputs: vec![],
818            output: Ty::new(TyKind::Adt(vtable_struct_ref.clone())),
819        };
820
821        let body = match impl_kind {
822            _ if item_meta.opacity.with_private_contents().is_opaque() => Body::Opaque,
823            TraitImplSource::Normal => {
824                self.gen_vtable_instance_init_body(span, impl_def, vtable_struct_ref)?
825            }
826            _ => {
827                raise_error!(
828                    self,
829                    span,
830                    "Don't know how to generate a vtable for a virtual impl {impl_kind:?}"
831                );
832            }
833        };
834
835        Ok(FunDecl {
836            def_id: init_func_id,
837            item_meta: item_meta,
838            signature: sig,
839            src: ItemSource::VTableInstance { impl_ref },
840            is_global_initializer: Some(init_for),
841            body,
842        })
843    }
844
845    /// The target vtable shim body looks like:
846    /// ```ignore
847    /// local ret@0 : ReturnTy;
848    /// // the shim receiver of this shim function
849    /// local shim_self@1 : ShimReceiverTy;
850    /// // the arguments of the impl function
851    /// local arg1@2 : Arg1Ty;
852    /// ...
853    /// local argN@N : ArgNTy;
854    /// // the target receiver of the impl function
855    /// local target_self@(N+1) : TargetReceiverTy;
856    /// // perform some conversion to cast / re-box the shim receiver to the target receiver
857    /// ...
858    /// target_self@(N+1) := concretize_cast<ShimReceiverTy, TargetReceiverTy>(shim_self@1);
859    /// // call the impl function and assign the result to ret@0
860    /// ret@0 := impl_func(target_self@(N+1), arg1@2, ..., argN@N);
861    /// ```
862    fn translate_vtable_shim_body(
863        &mut self,
864        span: Span,
865        target_receiver: &Ty,
866        shim_signature: &FunSig,
867        impl_func_def: &hax::FullDef,
868    ) -> Result<Body, Error> {
869        let mut builder = BodyBuilder::new(span, shim_signature.inputs.len());
870
871        let ret_place = builder.new_var(None, shim_signature.output.clone());
872        let mut method_args = shim_signature
873            .inputs
874            .iter()
875            .map(|ty| builder.new_var(None, ty.clone()))
876            .collect_vec();
877        let target_self = builder.new_var(None, target_receiver.clone());
878
879        // Replace the `dyn Trait` receiver with the concrete one.
880        let shim_self = mem::replace(&mut method_args[0], target_self.clone());
881
882        // Perform the core concretization cast.
883        // FIXME: need to unpack & re-pack the structure for cases like `Rc`, `Arc`, `Pin` and
884        // (when --raw-boxes is on) `Box`
885        let rval = Rvalue::UnaryOp(
886            UnOp::Cast(CastKind::Concretize(
887                shim_self.ty().clone(),
888                target_self.ty().clone(),
889            )),
890            Operand::Move(shim_self.clone()),
891        );
892        builder.push_statement(StatementKind::Assign(target_self.clone(), rval));
893
894        let fun_id = self.register_item(span, &impl_func_def.this(), TransItemSourceKind::Fun);
895        let generics = self.outermost_binder().params.identity_args();
896        builder.call(Call {
897            func: FnOperand::Regular(FnPtr::new(FnPtrKind::Fun(fun_id), generics)),
898            args: method_args
899                .into_iter()
900                .map(|arg| Operand::Move(arg))
901                .collect(),
902            dest: ret_place,
903        });
904
905        Ok(Body::Unstructured(builder.build()))
906    }
907
908    /// The target vtable drop_shim body looks like:
909    /// ```ignore
910    /// local ret@0 : ();
911    /// // the shim receiver of this drop_shim function
912    /// local shim_self@1 : ShimReceiverTy;
913    /// // the target receiver of the drop_shim
914    /// local target_self@2 : TargetReceiverTy;
915    /// // perform some conversion to cast / re-box the drop_shim receiver to the target receiver
916    /// target_self@2 := concretize_cast<ShimReceiverTy, TargetReceiverTy>(shim_self@1);
917    /// Drop(*target_self@2);
918    /// ```
919    fn translate_vtable_drop_shim_body(
920        &mut self,
921        span: Span,
922        shim_receiver: &Ty,
923        target_receiver: &Ty,
924        trait_pred: &TraitPredicate,
925    ) -> Result<Body, Error> {
926        let mut builder = BodyBuilder::new(span, 1);
927
928        builder.new_var(Some("ret".into()), Ty::mk_unit());
929        let dyn_self = builder.new_var(Some("dyn_self".into()), shim_receiver.clone());
930        let target_self = builder.new_var(Some("target_self".into()), target_receiver.clone());
931
932        // Perform the core concretization cast.
933        let rval = Rvalue::UnaryOp(
934            UnOp::Cast(CastKind::Concretize(
935                dyn_self.ty().clone(),
936                target_self.ty().clone(),
937            )),
938            Operand::Move(dyn_self.clone()),
939        );
940        builder.push_statement(StatementKind::Assign(target_self.clone(), rval));
941
942        // Build a reference to `impl Destruct for T`. Given the
943        // target_receiver type `T`, use Hax to solve `T: Destruct`
944        // and translate the resolved result to `TraitRef` of the
945        // `drop_in_place`
946        let destruct_trait = self.tcx.lang_items().destruct_trait().unwrap();
947        let impl_expr: hax::ImplExpr = {
948            let s = self.hax_state_with_id();
949            let rustc_trait_args = trait_pred.trait_ref.rustc_args(s);
950            let generics = self.tcx.mk_args(&rustc_trait_args[..1]); // keep only the `Self` type
951            let tref =
952                rustc_middle::ty::TraitRef::new_from_args(self.tcx, destruct_trait, generics);
953            hax::solve_trait(s, rustc_middle::ty::Binder::dummy(tref))
954        };
955        let tref = self.translate_trait_impl_expr(span, &impl_expr)?;
956
957        // Drop(*target_self)
958        let drop_arg = target_self.clone().deref();
959        builder.insert_drop(drop_arg, tref);
960
961        Ok(Body::Unstructured(builder.build()))
962    }
963
964    pub(crate) fn translate_vtable_drop_shim(
965        mut self,
966        fun_id: FunDeclId,
967        item_meta: ItemMeta,
968        impl_def: &hax::FullDef,
969    ) -> Result<FunDecl, Error> {
970        let span = item_meta.span;
971        self.translate_def_generics(span, impl_def)?;
972
973        let hax::FullDefKind::TraitImpl {
974            dyn_self: Some(dyn_self),
975            trait_pred,
976            ..
977        } = impl_def.kind()
978        else {
979            raise_error!(
980                self,
981                span,
982                "Trying to generate a vtable drop shim for a non-trait impl"
983            );
984        };
985
986        // `*mut dyn Trait`
987        let ref_dyn_self =
988            TyKind::RawPtr(self.translate_ty(span, dyn_self)?, RefKind::Mut).into_ty();
989        // `*mut T` for `impl Trait for T`
990        let ref_target_self = {
991            let impl_trait = self.translate_trait_ref(span, &trait_pred.trait_ref)?;
992            TyKind::RawPtr(impl_trait.generics.types[0].clone(), RefKind::Mut).into_ty()
993        };
994
995        // `*mut dyn Trait -> ()`
996        let signature = FunSig {
997            is_unsafe: false,
998            generics: self.the_only_binder().params.clone(),
999            inputs: vec![ref_dyn_self.clone()],
1000            output: Ty::mk_unit(),
1001        };
1002
1003        let body: Body = self.translate_vtable_drop_shim_body(
1004            span,
1005            &ref_dyn_self,
1006            &ref_target_self,
1007            trait_pred,
1008        )?;
1009
1010        Ok(FunDecl {
1011            def_id: fun_id,
1012            item_meta,
1013            signature,
1014            src: ItemSource::VTableMethodShim,
1015            is_global_initializer: None,
1016            body,
1017        })
1018    }
1019
1020    pub(crate) fn translate_vtable_shim(
1021        mut self,
1022        fun_id: FunDeclId,
1023        item_meta: ItemMeta,
1024        impl_func_def: &hax::FullDef,
1025    ) -> Result<FunDecl, Error> {
1026        let span = item_meta.span;
1027        self.check_no_monomorphize(span)?;
1028
1029        let hax::FullDefKind::AssocFn {
1030            vtable_sig: Some(vtable_sig),
1031            sig: target_signature,
1032            ..
1033        } = impl_func_def.kind()
1034        else {
1035            raise_error!(
1036                self,
1037                span,
1038                "Trying to generate a vtable shim for a non-vtable-safe method"
1039            );
1040        };
1041
1042        // Replace to get the true signature of the shim function.
1043        // As `translate_function_signature` will use the `sig` field of the `hax::FullDef`
1044        // TODO: this is a hack.
1045        let shim_func_def = {
1046            let mut def = impl_func_def.clone();
1047            let hax::FullDefKind::AssocFn { sig, .. } = &mut def.kind else {
1048                unreachable!()
1049            };
1050            *sig = vtable_sig.clone();
1051            def
1052        };
1053
1054        // Compute the correct signature for the shim
1055        let signature = self.translate_function_signature(&shim_func_def, &item_meta)?;
1056
1057        let target_receiver = self.translate_ty(span, &target_signature.value.inputs[0])?;
1058
1059        trace!(
1060            "[VtableShim] Obtained dyn signature with receiver type: {}",
1061            signature.inputs[0].with_ctx(&self.into_fmt())
1062        );
1063
1064        let body = if item_meta.opacity.with_private_contents().is_opaque() {
1065            Body::Opaque
1066        } else {
1067            self.translate_vtable_shim_body(span, &target_receiver, &signature, impl_func_def)?
1068        };
1069
1070        Ok(FunDecl {
1071            def_id: fun_id,
1072            item_meta,
1073            signature,
1074            src: ItemSource::VTableMethodShim,
1075            is_global_initializer: None,
1076            body,
1077        })
1078    }
1079}