Skip to main content

charon_driver/translate/
translate_trait_objects.rs

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
18// Vtable method values that are used to vtable initilization functions.
19// In poly mode, they are const values of shim function pointers direcly filled in vtable fields.
20// In mono mode, they are used for construction of casting statements (see `mk_cast` in `gen_vtable_instance_init_body` for details).
21enum VtableMethodValue {
22    Const(ConstantExprKind),
23    /// The method name, type of the shim function pointer, and shim function pointer.
24    Cast((String, Ty, FnPtr)),
25}
26
27/// Takes a `T` valid in the context of a trait ref and transforms it into a `T` valid in the
28/// context of its vtable definition, i.e. no longer mentions the `Self` type or `Self` clause. If
29/// `new_self` is `Some`, we replace any mention of the `Self` type with it; otherwise we panic if
30/// `Self` is mentioned.
31/// If `for_method` is true, we're handling a value coming from a `AssocFn`, which takes the `Self`
32/// clause as its first clause parameter. Otherwise we're in trait scope, where the `Self` clause
33/// is represented with `TraitRefKind::SelfId`.
34fn 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                // Replace type 0 and decrement the others.
43                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                    // That's the `Self` clause.
61                    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
81/// Translate the `dyn Trait` type.
82impl<'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        // Only the first clause is allowed to have methods.
89        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        // This is a robustness check: the current version of Rustc
120        // accepts at most one method-bearing predicate in a trait object.
121        // But things may change in the future.
122        self.check_at_most_one_pred_has_methods(span, &binder.predicates)?;
123
124        // Add a binder that contains the existentially quantified type.
125        self.binding_levels.push(BindingLevel::new());
126
127        // Add the existentially quantified type.
128        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        // As illustrated inside translate_trait_decl, associated items take an extra explicit `Self: Trait` clause in Hax.
140        // Therefore, in mono mode, projection predicates in dyn binders may refer to clause vars with an
141        // extra slot (e.g. `Bound(0, 1)` instead of `Bound(0, 0)`).
142        // Hence, we normalize them so that associated type constraints point to trait clauses in the scope.
143        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/// Vtable field info used for translation (same deal as `charon_lib::VTableField` but with
175/// different data).
176#[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
190/// Generate the vtable struct.
191impl<'tcx> ItemTransCtx<'tcx, '_> {
192    /// Query whether a trait is dyn compatible.
193    /// TODO(dyn): for now we return `false` if the trait has any associated types, as we don't
194    /// handle associated types in vtables.
195    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    /// Check whether this trait ref is of the form `Self: Trait<...>`.
205    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    /// Given a trait ref, return a reference to its vtable struct, if it is dyn compatible.
245    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        // FIXME: preserve legacy behavior, maybe undesired.
256        let enqueue = enqueue || self.monomorphize();
257
258        // Don't enqueue the vtable for translation by default. It will be enqueued if used in a
259        // `dyn Trait`.
260        let mut vtable_ref: TypeDeclRef =
261            self.translate_item_maybe_enqueue(span, tref, TransItemSourceKind::VTable, enqueue)?;
262        // Remove the `Self` type variable from the generic parameters.
263        vtable_ref
264            .generics
265            .types
266            .remove_and_shift_ids(TypeVarId::ZERO);
267
268        if !self.monomorphize() {
269            // The vtable type also takes associated types as parameters.
270            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        // Basic fields.
294        fields.push(TrVTableField::Size);
295        fields.push(TrVTableField::Align);
296        fields.push(TrVTableField::Drop);
297
298        // Method fields.
299        if let hax::FullDefKind::Trait { items, .. } = poly_trait_def.kind() {
300            for item in items {
301                let item_def_id = &item.def_id;
302                // This is ok because dyn-compatible methods don't have generics.
303                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        // Supertrait fields.
317        for (i, pred) in implied_predicates.iter_trait_clauses().enumerate() {
318            let trait_clause_id = TraitClauseId::from_raw(i); // One trait clause id per trait clause
319            let clause = &pred.clause;
320            let hax::ClauseKind::Trait(pred) = clause.kind.hax_skip_binder_ref() else {
321                unreachable!()
322            };
323            // If a clause looks like `Self: OtherTrait<...>`, we consider it a supertrait.
324            if self.pred_is_for_self(&pred.trait_ref) {
325                if !self.trait_is_dyn_compatible(&pred.trait_ref.def_id)? {
326                    // We add fake `Destruct` supertraits, but these are not dyn-compatible.
327                    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    /// The Charon+Hax machinery will add Destruct super-traits to trait bounds,
342    /// however for `dyn Trait` the Destruct super-trait is unexepcted, as it is not
343    /// dyn-compatible.
344    /// We use this function to ensure that any non dyn-compatible super-trait is
345    /// Destruct and can be safely ignored.
346    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                    // In Mono mode, drop shims are opaque function pointers.
370                    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                    // In Mono mode, method shims are opaque function pointers.
386                    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                        // The method is defined in a context that has an extra `Self: Trait` clause, so
391                        // we translate it bound first.
392                        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                            // Provide the `Self` clause.
401                            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    /// Construct the type of the vtable for this trait.
438    ///
439    /// It's a struct that has for generics the generics of the trait + one parameter for each
440    /// associated type of the trait and its parents.
441    ///
442    /// struct TraitVTable<TraitArgs.., AssocTys..> {
443    ///   size: usize,
444    ///   align: usize,
445    ///   drop: fn(*mut dyn Trait<...>),
446    ///   method_name: fn(&dyn Trait<...>, Args..) -> Output,
447    ///   ... other methods
448    ///   super_trait_0: &'static SuperTrait0VTable
449    ///   ... other supertraits
450    /// }
451    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            // First construct fields that use the real method signatures (which may use the `Self`
502            // type). We fixup the types and generics below.
503            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            // The `dyn Trait<Args..>` type for this trait.
536            // This is only used in poly mode
537            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                // Add one generic parameter for each associated type of this trait and its parents. We
544                // then use that in `dyn_self`
545                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                    // Moving that type under two levels of binders: the `DynPredicate` binder and the
559                    // type constraint binder.
560                    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            // Replace any use of `Self` with `dyn Trait<...>`, and remove the `Self` type variable
568            // from the generic parameters.
569            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            // A vtable struct is always sized
598            ptr_metadata: PtrMetadata::None,
599        })
600    }
601}
602
603/// Generate a vtable value.
604impl<'tcx> ItemTransCtx<'tcx, '_> {
605    /// Construct a constant that represents a reference to the vtable corresponding to this this trait proof.
606    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                // We could return `VTableRef` but we need to enqueue the translation of the static
633                // so may as well reuse that to normalize a bit.
634                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    /// You may want `translate_vtable_instance_const` instead.
653    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        // Don't enqueue the vtable for translation by default. It will be enqueued if used in a
684        // `dyn Trait` coercion.
685        // TODO(dyn): To do this properly we'd need to know for each clause whether it ultimately
686        // ends up used in a vtable cast.
687        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    /// Local helper function to get the vtable struct reference and trait declaration reference
697    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    /// E.g.,
720    /// ```
721    /// global {impl Trait for Foo}::vtable<Args..>: Trait::{vtable}<TraitArgs.., AssocTys..> {
722    ///     size: size_of(Foo),
723    ///     align: align_of(Foo),
724    ///     drop: <Foo as Destruct>::drop_glue,
725    ///     method_0: <Foo as Trait>::method_0::{shim},
726    ///     method_1: <Foo as Trait>::method_1::{shim},
727    ///     ...
728    ///     super_trait_0: SuperImpl0<..>::{vtable_instance}::<..>,
729    ///     super_trait_1: SuperImpl1<..>::{vtable_instance}::<..>,
730    ///     ...
731    /// }
732    /// ```
733    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        // Initializer function for this global.
747        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            // it should be static to have its own address
770            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        // Exit if the item isn't a vtable safe method.
783        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        // The method is vtable safe so it has no generics, hence we can skip the binder.
793        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                // In mono mode, we cannot get real types of shim functions by looking up the ones in `struct vtable`
799                // because they are erased function pointers.
800                // Therefore, below we compute real types that are used for casting.
801                if self.monomorphize() {
802                    // Manually translate region params for dyn trait.
803                    // We create a new binding level by `translate_item_generics`
804                    // and restore the orginal one after computing `method_ty`.
805                    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                    // Add regions. this is ad-hoc...
823                    let method_ty = Ty::new(TyKind::FnPtr(RegionBinder {
824                        regions: self.outermost_generics().regions.clone(),
825                        skip_binder: signature,
826                    }));
827
828                    // Restore the orignal binding_levels.
829                    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    /// Generate the body of the vtable instance function.
851    /// This is for `impl Trait for T` implementation, it does NOT handle builtin impls.
852    /// ```ignore
853    /// let ret@0 : VTable;
854    /// ret@0 = VTable { ... };
855    /// return;
856    /// ```
857    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        // We use `poly_trait_def` to fetch `implied_preds`, which is used to fetch supertrait in `prepare_vtable_fields`.
875        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        // The type this impl is for.
887        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        // Retrieve the expected field types from the struct definition. This avoids complicated
895        // substitutions.
896        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        // Construct a list with one operand per vtable field.
917        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            // In poly mode, all fields of vtables can be filled with const values.
921            let mk_const = |kind| {
922                Operand::Const(Box::new(ConstantExpr {
923                    kind,
924                    ty: ty.clone(),
925                }))
926            };
927            // In mono mode, we need to additioanlly cast shim function pointers to opaque ones before filling them.
928            // Therefore, `mk_cast` receives `(method_name, method_ty, method_shim)` to construct casting statements.
929            // For example, for the trait declaration and trait implementation in Rust:
930            // ```
931            // trait Trait {
932            //      fn method(&self);
933            // }
934            // impl Trait for i32 {
935            //      fn method(&self) {}
936            // }
937            // ```
938            //  , `mk_cast` will generate the followging statements inside the vtable initialization function:
939            // ```
940            // fn vtable_init() -> vtable {
941            //      ...
942            //      let method_local: fn<'_0_1>(&'_0_1 (dyn Trait + '1));
943            //      let cast_local: *const ();
944            //
945            //      method_local = const {shim}<'1>
946            //      cast_local = cast<fn<'_0_1>(&'_0_1 (dyn Trait + '2)), *const ()>(move method_local)
947            //      ...
948            // }
949            // ```
950            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                        // manually compute the type of drop shim function.
1000                        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                    // Bit of a hack: we know the methods are in the right order. This is easier
1028                    // than trying to index into the items list by name.
1029                    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        // Construct the final struct.
1051        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        // Signature: `() -> VTable`.
1084        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    /// The target vtable shim body looks like:
1117    /// ```ignore
1118    /// local ret@0 : ReturnTy;
1119    /// // the shim receiver of this shim function
1120    /// local shim_self@1 : ShimReceiverTy;
1121    /// // the arguments of the impl function
1122    /// local arg1@2 : Arg1Ty;
1123    /// ...
1124    /// local argN@N : ArgNTy;
1125    /// // the target receiver of the impl function
1126    /// local target_self@(N+1) : TargetReceiverTy;
1127    /// // perform some conversion to cast / re-box the shim receiver to the target receiver
1128    /// ...
1129    /// target_self@(N+1) := concretize_cast<ShimReceiverTy, TargetReceiverTy>(shim_self@1);
1130    /// // call the impl function and assign the result to ret@0
1131    /// ret@0 := impl_func(target_self@(N+1), arg1@2, ..., argN@N);
1132    /// ```
1133    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        // Replace the `dyn Trait` receiver with the concrete one.
1151        let shim_self = mem::replace(&mut method_args[0], target_self.clone());
1152
1153        // Perform the core concretization cast.
1154        // FIXME: need to unpack & re-pack the structure for cases like `Rc`, `Arc`, `Pin` and
1155        // (when --raw-boxes is on) `Box`
1156        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    /// The target vtable drop_shim body looks like:
1177    /// ```ignore
1178    /// local ret@0 : ();
1179    /// // the shim receiver of this drop_shim function
1180    /// local shim_self@1 : ShimReceiverTy;
1181    /// // the target receiver of the drop_shim
1182    /// local target_self@2 : TargetReceiverTy;
1183    /// // perform some conversion to cast / re-box the drop_shim receiver to the target receiver
1184    /// target_self@2 := concretize_cast<ShimReceiverTy, TargetReceiverTy>(shim_self@1);
1185    /// Drop(*target_self@2);
1186    /// ```
1187    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        // Perform the core concretization cast.
1201        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        // Drop(*target_self)
1215        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        // `&mut dyn Trait -> ()`
1246        let signature = self.drop_glue_method_sig(dyn_self.clone(), borrow_region);
1247
1248        // `&mut T` for `impl Trait for T`
1249        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        // The signature of the shim function.
1298        let signature = self.translate_fun_sig(span, &vtable_sig.value)?;
1299        // The concrete receiver we will cast to.
1300        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}