Skip to main content

charon_driver/translate/
translate_trait_objects.rs

1use crate::hax;
2use crate::hax::TraitPredicate;
3use charon_lib::ast::ullbc_ast_utils::BodyBuilder;
4use itertools::Itertools;
5use rustc_span::kw;
6use std::mem;
7
8use super::{
9    translate_crate::TransItemSourceKind, translate_ctx::*, translate_generics::BindingLevel,
10};
11use charon_lib::formatter::IntoFormatter;
12use charon_lib::ids::IndexVec;
13use charon_lib::pretty::FmtWithCtx;
14use charon_lib::ullbc_ast::*;
15
16fn usize_ty() -> Ty {
17    Ty::new(TyKind::Literal(LiteralTy::UInt(UIntTy::Usize)))
18}
19
20// Vtable method values that are used to vtable initilization functions.
21// In poly mode, they are const values of shim function pointers direcly filled in vtable fields.
22// In mono mode, they are used for construction of casting statements (see `mk_cast` in `gen_vtable_instance_init_body` for details).
23enum VtableMethodValue {
24    Const(ConstantExprKind),
25    /// The method name, type of the shim function pointer, and shim function pointer.
26    Cast((String, Ty, FnPtr)),
27}
28
29/// Takes a `T` valid in the context of a trait ref and transforms it into a `T` valid in the
30/// context of its vtable definition, i.e. no longer mentions the `Self` type or `Self` clause. If
31/// `new_self` is `Some`, we replace any mention of the `Self` type with it; otherwise we panic if
32/// `Self` is mentioned.
33/// If `for_method` is true, we're handling a value coming from a `AssocFn`, which takes the `Self`
34/// clause as its first clause parameter. Otherwise we're in trait scope, where the `Self` clause
35/// is represented with `TraitRefKind::SelfId`.
36fn dynify<T: TyVisitable>(mut x: T, new_self: Option<Ty>, for_method: bool) -> T {
37    struct ReplaceSelfVisitor {
38        new_self: Option<Ty>,
39        for_method: bool,
40    }
41    impl VarsVisitor for ReplaceSelfVisitor {
42        fn visit_type_var(&mut self, v: TypeDbVar) -> Option<Ty> {
43            if let DeBruijnVar::Bound(DeBruijnId::ZERO, type_id) = v {
44                // Replace type 0 and decrement the others.
45                Some(if let Some(new_id) = type_id.index().checked_sub(1) {
46                    TyKind::TypeVar(DeBruijnVar::Bound(DeBruijnId::ZERO, TypeVarId::new(new_id)))
47                        .into_ty()
48                } else {
49                    self.new_self.clone().expect(
50                        "Found unexpected `Self`
51                        type when constructing vtable",
52                    )
53                })
54            } else {
55                None
56            }
57        }
58
59        fn visit_clause_var(&mut self, v: ClauseDbVar) -> Option<TraitRefKind> {
60            if let DeBruijnVar::Bound(DeBruijnId::ZERO, clause_id) = v {
61                if self.for_method && clause_id == TraitClauseId::ZERO {
62                    // That's the `Self` clause.
63                    Some(TraitRefKind::Dyn)
64                } else {
65                    panic!("Found unexpected clause var when constructing vtable: {v}")
66                }
67            } else {
68                None
69            }
70        }
71
72        fn visit_self_clause(&mut self) -> Option<TraitRefKind> {
73            Some(TraitRefKind::Dyn)
74        }
75    }
76    x.visit_vars(&mut ReplaceSelfVisitor {
77        new_self,
78        for_method,
79    });
80    x
81}
82
83/// Translate the `dyn Trait` type.
84impl<'tcx> ItemTransCtx<'tcx, '_> {
85    pub fn check_at_most_one_pred_has_methods(
86        &mut self,
87        span: Span,
88        preds: &hax::GenericPredicates,
89    ) -> Result<(), Error> {
90        // Only the first clause is allowed to have methods.
91        for pred in preds.predicates.iter().skip(1) {
92            if let hax::ClauseKind::Trait(trait_predicate) = pred.clause.kind.hax_skip_binder_ref()
93            {
94                let trait_def_id = &trait_predicate.trait_ref.def_id;
95                let trait_def = self.poly_hax_def(trait_def_id)?;
96                let has_methods = match trait_def.kind() {
97                    hax::FullDefKind::Trait { items, .. } => items
98                        .iter()
99                        .any(|assoc| matches!(assoc.kind, hax::AssocKind::Fn { .. })),
100                    hax::FullDefKind::TraitAlias { .. } => false,
101                    _ => unreachable!(),
102                };
103                if has_methods {
104                    raise_error!(
105                        self,
106                        span,
107                        "`dyn Trait` with multiple method-bearing predicates is not supported"
108                    );
109                }
110            }
111        }
112        Ok(())
113    }
114
115    pub fn translate_dyn_binder<T, U>(
116        &mut self,
117        span: Span,
118        binder: &hax::DynBinder<T>,
119        f: impl FnOnce(&mut Self, Ty, &T) -> Result<U, Error>,
120    ) -> Result<Binder<U>, Error> {
121        // This is a robustness check: the current version of Rustc
122        // accepts at most one method-bearing predicate in a trait object.
123        // But things may change in the future.
124        self.check_at_most_one_pred_has_methods(span, &binder.predicates)?;
125
126        // Add a binder that contains the existentially quantified type.
127        self.binding_levels.push(BindingLevel::new());
128
129        // Add the existentially quantified type.
130        let ty_id = self
131            .innermost_binder_mut()
132            .push_type_var(binder.existential_ty.index, binder.existential_ty.name);
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        // In mono mode we keep a single opaque vtable per trait declaration.
256        if self.monomorphize() {
257            let item_src =
258                TransItemSource::monomorphic_trait(&tref.def_id, TransItemSourceKind::VTable);
259            let id: ItemId = self.register_and_enqueue(span, item_src);
260            let id = id
261                .try_into()
262                .expect("translated trait decl should be a trait decl id");
263            return Ok(Some(TypeDeclRef {
264                id,
265                generics: Box::new(GenericArgs::empty()),
266            }));
267        }
268
269        // Don't enqueue the vtable for translation by default. It will be enqueued if used in a
270        // `dyn Trait`.
271        let mut vtable_ref: TypeDeclRef =
272            self.translate_item_maybe_enqueue(span, tref, TransItemSourceKind::VTable, enqueue)?;
273        // Remove the `Self` type variable from the generic parameters.
274        vtable_ref
275            .generics
276            .types
277            .remove_and_shift_ids(TypeVarId::ZERO);
278
279        // The vtable type also takes associated types as parameters.
280        let assoc_tys: Vec<_> = tref
281            .trait_associated_types(self.hax_state_with_id())
282            .iter()
283            .map(|ty| self.translate_ty(span, ty))
284            .try_collect()?;
285        vtable_ref.generics.types.extend(assoc_tys);
286
287        Ok(Some(vtable_ref))
288    }
289
290    fn prepare_vtable_fields(
291        &mut self,
292        poly_trait_def: &hax::FullDef<'tcx>,
293        trait_id: TraitDeclId,
294        implied_predicates: &hax::GenericPredicates,
295    ) -> Result<VTableData, Error> {
296        let mut supertrait_map: IndexVec<TraitClauseId, _> =
297            (0..implied_predicates.predicates.len())
298                .map(|_| None)
299                .collect();
300        let mut fields = IndexVec::new();
301
302        // Basic fields.
303        fields.push(TrVTableField::Size);
304        fields.push(TrVTableField::Align);
305        fields.push(TrVTableField::Drop);
306
307        // Method fields.
308        if let hax::FullDefKind::Trait { items, .. } = poly_trait_def.kind() {
309            for item in items {
310                let item_def_id = &item.def_id;
311                // This is ok because dyn-compatible methods don't have generics.
312                let poly_item_def = self.poly_hax_def(item_def_id)?;
313                if let hax::FullDefKind::AssocFn {
314                    sig,
315                    vtable_sig: Some(_),
316                    ..
317                } = poly_item_def.kind()
318                {
319                    let id = self.translate_trait_method_id_no_enqueue(trait_id, item_def_id)?;
320                    fields.push(TrVTableField::Method(id, sig.clone()));
321                }
322            }
323        }
324
325        // Supertrait fields.
326        for (i, pred) in implied_predicates.iter_trait_clauses().enumerate() {
327            let trait_clause_id = TraitClauseId::from_raw(i); // One trait clause id per trait clause
328            let clause = &pred.clause;
329            let hax::ClauseKind::Trait(pred) = clause.kind.hax_skip_binder_ref() else {
330                unreachable!()
331            };
332            // If a clause looks like `Self: OtherTrait<...>`, we consider it a supertrait.
333            if self.pred_is_for_self(&pred.trait_ref) {
334                if !self.trait_is_dyn_compatible(&pred.trait_ref.def_id)? {
335                    // We add fake `Destruct` supertraits, but these are not dyn-compatible.
336                    self.assert_is_destruct(&pred.trait_ref);
337                    continue;
338                }
339                supertrait_map[trait_clause_id] = Some(fields.next_idx());
340                fields.push(TrVTableField::SuperTrait(trait_clause_id, clause.clone()));
341            }
342        }
343
344        Ok(VTableData {
345            fields,
346            supertrait_map,
347        })
348    }
349
350    /// The Charon+Hax machinery will add Destruct super-traits to trait bounds,
351    /// however for `dyn Trait` the Destruct super-trait is unexepcted, as it is not
352    /// dyn-compatible.
353    /// We use this function to ensure that any non dyn-compatible super-trait is
354    /// Destruct and can be safely ignored.
355    fn assert_is_destruct(&self, tref: &hax::TraitRef) {
356        assert!(
357            tref.def_id
358                .as_real_def_id()
359                .is_some_and(|id| self.tcx.is_lang_item(id, rustc_hir::LangItem::Destruct)),
360            "unexpected non-dyn compatible supertrait: {:?}",
361            tref.def_id
362        );
363    }
364
365    fn gen_vtable_struct_fields(
366        &mut self,
367        span: Span,
368        self_trait_ref: &TraitRef,
369        vtable_data: &VTableData,
370    ) -> Result<IndexVec<FieldId, Field>, Error> {
371        let mut fields = IndexVec::new();
372        let mut supertrait_counter = 0..;
373        for field in &vtable_data.fields {
374            let (name, ty) = match field {
375                TrVTableField::Size => ("size".into(), usize_ty()),
376                TrVTableField::Align => ("align".into(), usize_ty()),
377                TrVTableField::Drop => {
378                    // In Mono mode, drop shims are opaque function pointers.
379                    if self.monomorphize() {
380                        let erased_ptr_ty = Ty::new(TyKind::RawPtr(Ty::mk_unit(), RefKind::Shared));
381                        ("drop".into(), erased_ptr_ty)
382                    } else {
383                        let self_ty =
384                            TyKind::TypeVar(DeBruijnVar::new_at_zero(TypeVarId::ZERO)).into_ty();
385                        let drop_ty = Ty::new(TyKind::FnPtr(self.drop_glue_fn_ptr_sig(self_ty)));
386                        ("drop".into(), drop_ty)
387                    }
388                }
389                TrVTableField::Method(item_id, sig) => {
390                    let item_name = self
391                        .translated
392                        .assoc_item_name(self_trait_ref.trait_id(), *item_id);
393                    let field_name = format!("method_{}", item_name.0);
394                    // In Mono mode, method shims are opaque function pointers.
395                    if self.monomorphize() {
396                        let erased_ptr_ty = Ty::new(TyKind::RawPtr(Ty::mk_unit(), RefKind::Shared));
397                        (field_name, erased_ptr_ty)
398                    } else {
399                        // The method is defined in a context that has an extra `Self: Trait` clause, so
400                        // we translate it bound first.
401                        let bound_sig = self.inside_binder(BinderKind::Other, |ctx| {
402                            ctx.innermost_binder_mut()
403                                .trait_preds
404                                .insert(hax::GenericPredicateId::TraitSelf, TraitClauseId::ZERO);
405                            ctx.translate_poly_fun_sig(span, sig)
406                        })?;
407                        let sig = bound_sig.apply(&{
408                            let mut generics = GenericArgs::empty();
409                            // Provide the `Self` clause.
410                            generics.trait_refs.push(self_trait_ref.clone());
411                            generics
412                        });
413                        let ty = TyKind::FnPtr(sig).into_ty();
414                        (field_name, ty)
415                    }
416                }
417                TrVTableField::SuperTrait(_, clause) => {
418                    let vtbl_struct =
419                        self.translate_region_binder(span, &clause.kind, |ctx, kind| {
420                            let hax::ClauseKind::Trait(pred) = kind else {
421                                unreachable!()
422                            };
423                            ctx.translate_vtable_struct_ref(span, &pred.trait_ref)
424                        })?;
425                    let vtbl_struct = self.erase_region_binder(vtbl_struct);
426                    let ty = Ty::new(TyKind::Ref(
427                        Region::Static,
428                        Ty::new(TyKind::Adt(vtbl_struct)),
429                        RefKind::Shared,
430                    ));
431                    let name = format!("super_trait_{}", supertrait_counter.next().unwrap());
432                    (name, ty)
433                }
434            };
435            fields.push(Field {
436                span,
437                attr_info: AttrInfo::dummy_public(),
438                name: Some(name),
439                ty,
440            });
441        }
442        Ok(fields)
443    }
444
445    /// Construct the type of the vtable for this trait.
446    ///
447    /// It's a struct that has for generics the generics of the trait + one parameter for each
448    /// associated type of the trait and its parents.
449    ///
450    /// struct TraitVTable<TraitArgs.., AssocTys..> {
451    ///   size: usize,
452    ///   align: usize,
453    ///   drop: fn(*mut dyn Trait<...>),
454    ///   method_name: fn(&dyn Trait<...>, Args..) -> Output,
455    ///   ... other methods
456    ///   super_trait_0: &'static SuperTrait0VTable
457    ///   ... other supertraits
458    /// }
459    pub(crate) fn translate_vtable_struct(
460        mut self,
461        type_id: TypeDeclId,
462        item_meta: ItemMeta,
463        trait_def: &hax::FullDef<'tcx>,
464    ) -> Result<TypeDecl, Error> {
465        let mono = self.monomorphize();
466        let span = item_meta.span;
467        if !self.trait_is_dyn_compatible(trait_def.def_id())? {
468            raise_error!(
469                self,
470                span,
471                "Trying to compute the vtable type \
472                for a non-dyn-compatible trait"
473            );
474        }
475
476        let (hax::FullDefKind::Trait {
477            self_predicate,
478            dyn_self,
479            implied_predicates,
480            ..
481        }
482        | hax::FullDefKind::TraitAlias {
483            self_predicate,
484            dyn_self,
485            implied_predicates,
486            ..
487        }) = trait_def.kind()
488        else {
489            panic!()
490        };
491        let Some(dyn_self) = dyn_self else {
492            panic!("Trying to generate a vtable for a non-dyn-compatible trait")
493        };
494
495        let self_trait_ref = TraitRef::new(
496            TraitRefKind::SelfId,
497            RegionBinder::empty(self.translate_trait_predicate(span, self_predicate)?),
498        );
499        let trait_id = self_trait_ref.trait_id();
500
501        let mut field_map = IndexVec::new();
502        let mut supertrait_map: IndexVec<TraitClauseId, _> =
503            (0..implied_predicates.predicates.len())
504                .map(|_| None)
505                .collect();
506        let (mut kind, layout) = if item_meta.opacity.with_private_contents().is_opaque() {
507            (TypeDeclKind::Opaque, SeqHashMap::default())
508        } else {
509            // First construct fields that use the real method signatures (which may use the `Self`
510            // type). We fixup the types and generics below.
511            let vtable_data =
512                self.prepare_vtable_fields(trait_def, trait_id, implied_predicates)?;
513            let fields = self.gen_vtable_struct_fields(span, &self_trait_ref, &vtable_data)?;
514
515            let kind = TypeDeclKind::Struct(fields);
516            let l = self.generate_naive_layout(span, &kind)?;
517            supertrait_map = vtable_data.supertrait_map;
518            field_map = vtable_data.fields.map_ref(|tr_field| match *tr_field {
519                TrVTableField::Size => VTableField::Size,
520                TrVTableField::Align => VTableField::Align,
521                TrVTableField::Drop => VTableField::Drop,
522                TrVTableField::Method(id, ..) => VTableField::Method(id),
523                TrVTableField::SuperTrait(clause_id, ..) => VTableField::SuperTrait(clause_id),
524            });
525            let layout = [(self.get_target_triple(), l)].into();
526            (kind, layout)
527        };
528
529        let mut generics = Default::default();
530
531        let dyn_predicate = if mono {
532            DynPredicate {
533                binder: Binder {
534                    params: GenericParams::empty(),
535                    skip_binder: TyKind::Error(
536                        "mono vtable dyn predicate is intentionally erased".to_string(),
537                    )
538                    .into_ty(),
539                    kind: BinderKind::Dyn,
540                },
541            }
542        } else {
543            // The `dyn Trait<Args..>` type for this trait.
544            // This is only used in poly mode
545            let mut dyn_self = {
546                let dyn_self = self.translate_ty(span, dyn_self)?;
547                let TyKind::DynTrait(mut dyn_pred) = dyn_self.kind().clone() else {
548                    panic!("incorrect `dyn_self`")
549                };
550
551                // Add one generic parameter for each associated type of this trait and its parents. We
552                // then use that in `dyn_self`
553                for (i, ty_constraint) in dyn_pred
554                    .binder
555                    .params
556                    .trait_type_constraints
557                    .iter_mut()
558                    .enumerate()
559                {
560                    let name = format!("Ty{i}");
561                    let new_ty = self
562                        .the_only_binder_mut()
563                        .params
564                        .types
565                        .push_with(|index| TypeParam { index, name });
566                    // Moving that type under two levels of binders: the `DynPredicate` binder and the
567                    // type constraint binder.
568                    let new_ty =
569                        TyKind::TypeVar(DeBruijnVar::bound(DeBruijnId::new(2), new_ty)).into_ty();
570                    ty_constraint.skip_binder.ty = new_ty;
571                }
572                TyKind::DynTrait(dyn_pred).into_ty()
573            };
574
575            // Replace any use of `Self` with `dyn Trait<...>`, and remove the `Self` type variable
576            // from the generic parameters.
577            generics = self.into_generics();
578            {
579                dyn_self = dynify(dyn_self, None, false);
580                generics = dynify(generics, Some(dyn_self.clone()), false);
581                kind = dynify(kind, Some(dyn_self.clone()), true);
582                generics.types.remove_and_shift_ids(TypeVarId::ZERO);
583                generics.types.iter_mut().for_each(|ty| {
584                    ty.index -= 1;
585                });
586            }
587
588            dyn_self
589                .kind()
590                .as_dyn_trait()
591                .expect("incorrect `dyn_self`")
592                .clone()
593        };
594        Ok(TypeDecl {
595            def_id: type_id,
596            item_meta,
597            generics,
598            src: ItemSource::VTableTy {
599                dyn_predicate,
600                field_map,
601                supertrait_map,
602            },
603            kind,
604            layout,
605            // A vtable struct is always sized
606            ptr_metadata: PtrMetadata::None,
607        })
608    }
609}
610
611/// Generate a vtable value.
612impl<'tcx> ItemTransCtx<'tcx, '_> {
613    /// Construct a constant that represents a reference to the vtable corresponding to this this trait proof.
614    pub fn translate_vtable_instance_const(
615        &mut self,
616        span: Span,
617        trait_proof: &hax::TraitProof,
618    ) -> Result<Box<ConstantExpr>, Error> {
619        let tref = trait_proof.pred.hax_skip_binder_ref();
620        if !self.trait_is_dyn_compatible(&tref.def_id)? {
621            raise_error!(
622                self,
623                span,
624                "Trait {:?} should be dyn-compatible",
625                tref.def_id
626            );
627        }
628
629        let vtbl_ty = {
630            let vtbl_ty = self.translate_region_binder(span, &trait_proof.pred, |ctx, tref| {
631                ctx.translate_vtable_struct_ref(span, tref)
632            })?;
633            let vtbl_ty = self.erase_region_binder(vtbl_ty);
634            TyKind::Adt(vtbl_ty).into_ty()
635        };
636        let ty = TyKind::Ref(Region::Static, vtbl_ty.clone(), RefKind::Shared).into_ty();
637
638        let kind = {
639            if let hax::TraitProofKind::Concrete(impl_item) = &trait_proof.kind {
640                // We could return `VTableRef` but we need to enqueue the translation of the static
641                // so may as well reuse that to normalize a bit.
642                let vtable_instance =
643                    self.translate_region_binder(span, &trait_proof.pred, |ctx, tref| {
644                        ctx.translate_vtable_instance_ref(span, tref, impl_item)
645                    })?;
646                let vtable_instance = self.erase_region_binder(vtable_instance);
647                let vtable_instance = Box::new(ConstantExpr {
648                    kind: ConstantExprKind::Global(vtable_instance),
649                    ty: vtbl_ty,
650                });
651                ConstantExprKind::Ref(vtable_instance, None)
652            } else {
653                ConstantExprKind::VTableRef(self.translate_trait_proof(span, trait_proof)?)
654            }
655        };
656
657        Ok(Box::new(ConstantExpr { kind, ty }))
658    }
659
660    /// You may want `translate_vtable_instance_const` instead.
661    pub fn translate_vtable_instance_ref(
662        &mut self,
663        span: Span,
664        trait_ref: &hax::TraitRef,
665        impl_ref: &hax::ItemRef,
666    ) -> Result<GlobalDeclRef, Error> {
667        Ok(self
668            .translate_vtable_instance_ref_maybe_enqueue(true, span, trait_ref, impl_ref)?
669            .expect("trait should be dyn-compatible"))
670    }
671
672    pub fn translate_vtable_instance_ref_no_enqueue(
673        &mut self,
674        span: Span,
675        trait_ref: &hax::TraitRef,
676        impl_ref: &hax::ItemRef,
677    ) -> Result<Option<GlobalDeclRef>, Error> {
678        self.translate_vtable_instance_ref_maybe_enqueue(false, span, trait_ref, impl_ref)
679    }
680
681    pub fn translate_vtable_instance_ref_maybe_enqueue(
682        &mut self,
683        enqueue: bool,
684        span: Span,
685        trait_ref: &hax::TraitRef,
686        impl_ref: &hax::ItemRef,
687    ) -> Result<Option<GlobalDeclRef>, Error> {
688        if !self.trait_is_dyn_compatible(&trait_ref.def_id)? {
689            return Ok(None);
690        }
691        // Don't enqueue the vtable for translation by default. It will be enqueued if used in a
692        // `dyn Trait` coercion.
693        // TODO(dyn): To do this properly we'd need to know for each clause whether it ultimately
694        // ends up used in a vtable cast.
695        let vtable_ref: GlobalDeclRef = self.translate_item_maybe_enqueue(
696            span,
697            impl_ref,
698            TransItemSourceKind::VTableInstance(TraitImplSource::Normal),
699            enqueue,
700        )?;
701        Ok(Some(vtable_ref))
702    }
703
704    /// Local helper function to get the vtable struct reference and trait declaration reference
705    fn get_vtable_instance_info(
706        &mut self,
707        span: Span,
708        impl_def: &hax::FullDef<'tcx>,
709        impl_kind: &TraitImplSource,
710    ) -> Result<(Option<TraitImplRef>, TypeDeclRef), Error> {
711        let implemented_trait = match impl_def.kind() {
712            hax::FullDefKind::TraitImpl { trait_pred, .. } => &trait_pred.trait_ref,
713            _ => unreachable!(),
714        };
715        let vtable_struct_ref = self.translate_vtable_struct_ref(span, implemented_trait)?;
716        if self.monomorphize() {
717            return Ok((None, vtable_struct_ref));
718        }
719        let impl_ref = self.translate_item(
720            span,
721            impl_def.this(),
722            TransItemSourceKind::TraitImpl(*impl_kind),
723        )?;
724        Ok((Some(impl_ref), vtable_struct_ref))
725    }
726
727    /// E.g.,
728    /// ```
729    /// global {impl Trait for Foo}::vtable<Args..>: Trait::{vtable}<TraitArgs.., AssocTys..> {
730    ///     size: size_of(Foo),
731    ///     align: align_of(Foo),
732    ///     drop: <Foo as Destruct>::drop_glue,
733    ///     method_0: <Foo as Trait>::method_0::{shim},
734    ///     method_1: <Foo as Trait>::method_1::{shim},
735    ///     ...
736    ///     super_trait_0: SuperImpl0<..>::{vtable_instance}::<..>,
737    ///     super_trait_1: SuperImpl1<..>::{vtable_instance}::<..>,
738    ///     ...
739    /// }
740    /// ```
741    pub(crate) fn translate_vtable_instance(
742        mut self,
743        global_id: GlobalDeclId,
744        item_meta: ItemMeta,
745        impl_def: &hax::FullDef<'tcx>,
746        impl_kind: &TraitImplSource,
747    ) -> Result<GlobalDecl, Error> {
748        let span = item_meta.span;
749
750        let (src, vtable_struct_ref) =
751            match self.get_vtable_instance_info(span, impl_def, impl_kind)? {
752                (Some(impl_ref), vtable_struct_ref) => {
753                    (ItemSource::VTableInstance { impl_ref }, vtable_struct_ref)
754                }
755                (None, vtable_struct_ref) => (ItemSource::VTableInstanceMono, vtable_struct_ref),
756            };
757
758        // Initializer function for this global.
759        let init = self.register_item(
760            span,
761            impl_def.this(),
762            TransItemSourceKind::VTableInstanceInitializer(*impl_kind),
763        );
764        let ty = Ty::new(TyKind::Adt(vtable_struct_ref));
765        let value = ConstantExpr {
766            kind: ConstantExprKind::Call(
767                FnPtr::new(
768                    FnPtrKind::Fun(FunId::Regular(init)),
769                    self.outermost_generics().identity_args(),
770                ),
771                vec![],
772            ),
773            ty: ty.clone(),
774        };
775
776        Ok(GlobalDecl {
777            def_id: global_id,
778            item_meta,
779            generics: self.into_generics(),
780            src,
781            // it should be static to have its own address
782            global_kind: GlobalKind::Static,
783            ty,
784            value,
785        })
786    }
787
788    fn add_method_to_vtable_value(
789        &mut self,
790        span: Span,
791        trait_id: TraitDeclId,
792        item: &hax::ImplAssocItem,
793    ) -> Result<Option<VtableMethodValue>, Error> {
794        // Exit if the item isn't a vtable safe method.
795        let item_def = self.poly_hax_def(&item.decl_def_id)?;
796        let hax::FullDefKind::AssocFn {
797            vtable_sig: Some(_),
798            ..
799        } = item_def.kind()
800        else {
801            return Ok(None);
802        };
803
804        // The method is vtable safe so it has no generics, hence we can skip the binder.
805        let vtable_value = match &item.value {
806            Some(value) => {
807                let item_ref = &value.skip_binder.item;
808                let shim_ref =
809                    self.translate_fn_ptr(span, item_ref, TransItemSourceKind::VTableMethod)?;
810                // In mono mode, we cannot get real types of shim functions by looking up the ones in `struct vtable`
811                // because they are erased function pointers.
812                // Therefore, below we compute real types that are used for casting.
813                if self.monomorphize() {
814                    // Manually translate region params for dyn trait.
815                    // We create a new binding level by `translate_item_generics`
816                    // and restore the orginal one after computing `method_ty`.
817                    assert!(self.binding_levels.len() == 1);
818                    let orginal_binding = self.binding_levels.pop();
819                    let assoc_fun_def = self.hax_def(item_ref)?;
820                    self.translate_item_generics(
821                        span,
822                        &assoc_fun_def,
823                        &TransItemSourceKind::VTableMethod,
824                    )?;
825                    let vtable_sig = match assoc_fun_def.kind() {
826                        hax::FullDefKind::AssocFn {
827                            vtable_sig: Some(vtable_sig),
828                            ..
829                        } => vtable_sig.clone(),
830                        _ => unreachable!("MONO: only assoc fun is supported"),
831                    };
832
833                    let signature = self.translate_fun_sig(span, &vtable_sig.value)?;
834                    // Add regions. this is ad-hoc...
835                    let method_ty = Ty::new(TyKind::FnPtr(RegionBinder {
836                        regions: self.outermost_generics().regions.clone(),
837                        skip_binder: signature,
838                    }));
839
840                    // Restore the orignal binding_levels.
841                    self.binding_levels.pop();
842                    if let Some(binding_level) = orginal_binding {
843                        self.binding_levels.push(binding_level);
844                    }
845
846                    let method_id = self.translate_trait_method_id(trait_id, item.decl_def_id())?;
847                    let method_name = self.translated.assoc_item_name(trait_id, method_id);
848
849                    VtableMethodValue::Cast((method_name.to_string(), method_ty, shim_ref))
850                } else {
851                    VtableMethodValue::Const(ConstantExprKind::FnPtr(shim_ref))
852                }
853            }
854            None => VtableMethodValue::Const(ConstantExprKind::Opaque(
855                "shim for default methods aren't yet supported".into(),
856            )),
857        };
858
859        Ok(Some(vtable_value))
860    }
861
862    /// Generate the body of the vtable instance function.
863    /// This is for `impl Trait for T` implementation, it does NOT handle builtin impls.
864    /// ```ignore
865    /// let ret@0 : VTable;
866    /// ret@0 = VTable { ... };
867    /// return;
868    /// ```
869    fn gen_vtable_instance_init_body(
870        &mut self,
871        span: Span,
872        impl_def: &hax::FullDef<'tcx>,
873        vtable_struct_ref: TypeDeclRef,
874    ) -> Result<Body, Error> {
875        let hax::FullDefKind::TraitImpl {
876            trait_pred,
877            implied_trait_proofs,
878            items,
879            ..
880        } = impl_def.kind()
881        else {
882            unreachable!()
883        };
884
885        let trait_def = self.hax_def(&trait_pred.trait_ref)?;
886        // We use `poly_trait_def` to fetch `implied_preds`, which is used to fetch supertrait in `prepare_vtable_fields`.
887        let poly_trait_def = self.poly_hax_def(&trait_pred.trait_ref.def_id)?;
888        let hax::FullDefKind::Trait {
889            implied_predicates: implied_preds,
890            ..
891        } = poly_trait_def.kind()
892        else {
893            unreachable!()
894        };
895
896        let implemented_trait = self.translate_trait_decl_ref(span, &trait_pred.trait_ref)?;
897        let trait_id = implemented_trait.id;
898        // The type this impl is for.
899        let self_ty = &implemented_trait.generics.types[0];
900
901        let mut builder = BodyBuilder::new(span, 0);
902        let ret_ty = Ty::new(TyKind::Adt(vtable_struct_ref.clone()));
903        let ret_place = builder.new_var(Some("ret".into()), ret_ty.clone());
904
905        let vtable_data = self.prepare_vtable_fields(&poly_trait_def, trait_id, implied_preds)?;
906        // Retrieve the expected field types from the struct definition. This avoids complicated
907        // substitutions.
908        let field_tys = {
909            let vtable_decl_id = *vtable_struct_ref.id.as_adt().unwrap();
910            let ItemRef::Type(vtable_def) = self.t_ctx.get_or_translate(vtable_decl_id.into())?
911            else {
912                unreachable!()
913            };
914            let fields = match &vtable_def.kind {
915                TypeDeclKind::Struct(fields) => fields,
916                TypeDeclKind::Opaque => return Ok(Body::Opaque),
917                TypeDeclKind::Error(error) => return Err(Error::new(span, error.clone())),
918                _ => unreachable!(),
919            };
920            fields
921                .iter()
922                .map(|f| &f.ty)
923                .cloned()
924                .map(|ty| ty.substitute(&vtable_struct_ref.generics))
925                .collect_vec()
926        };
927
928        // Construct a list with one operand per vtable field.
929        let mut aggregate_fields = vec![];
930        let mut items_iter = items.iter();
931        for (field, ty) in vtable_data.fields.into_iter().zip(field_tys) {
932            // In poly mode, all fields of vtables can be filled with const values.
933            let mk_const = |kind| {
934                Operand::Const(Box::new(ConstantExpr {
935                    kind,
936                    ty: ty.clone(),
937                }))
938            };
939            // In mono mode, we need to additioanlly cast shim function pointers to opaque ones before filling them.
940            // Therefore, `mk_cast` receives `(method_name, method_ty, method_shim)` to construct casting statements.
941            // For example, for the trait declaration and trait implementation in Rust:
942            // ```
943            // trait Trait {
944            //      fn method(&self);
945            // }
946            // impl Trait for i32 {
947            //      fn method(&self) {}
948            // }
949            // ```
950            //  , `mk_cast` will generate the followging statements inside the vtable initialization function:
951            // ```
952            // fn vtable_init() -> vtable {
953            //      ...
954            //      let method_local: fn<'_0_1>(&'_0_1 (dyn Trait + '1));
955            //      let cast_local: *const ();
956            //
957            //      method_local = const {shim}<'1>
958            //      cast_local = cast<fn<'_0_1>(&'_0_1 (dyn Trait + '2)), *const ()>(move method_local)
959            //      ...
960            // }
961            // ```
962            let mut mk_cast = |(method_name, method_ty, method_shim): (String, Ty, FnPtr)| {
963                let method_local = builder.new_var(Some(method_name.clone()), method_ty.clone());
964                let shim = Rvalue::Use(
965                    Operand::Const(Box::new(ConstantExpr {
966                        kind: ConstantExprKind::FnPtr(method_shim.clone()),
967                        ty: method_ty.clone(),
968                    })),
969                    WithRetag::No,
970                );
971                let cast_local = builder.new_var(
972                    Some("erased_".to_string() + method_name.as_str()),
973                    ty.clone(),
974                );
975                let cast = Rvalue::UnaryOp(
976                    UnOp::Cast(CastKind::RawPtr(
977                        method_local.ty().clone(),
978                        cast_local.ty().clone(),
979                    )),
980                    Operand::Move(method_local.clone()),
981                );
982
983                builder.push_statement(StatementKind::Assign(method_local.clone(), shim));
984                builder.push_statement(StatementKind::Assign(cast_local.clone(), cast));
985                Operand::Move(cast_local)
986            };
987            let op = match field {
988                TrVTableField::Size => {
989                    let size_local = builder.new_var(Some("size".to_string()), ty);
990                    builder.push_statement(StatementKind::Assign(
991                        size_local.clone(),
992                        Rvalue::NullaryOp(NullOp::SizeOf, self_ty.clone()),
993                    ));
994                    Operand::Move(size_local)
995                }
996                TrVTableField::Align => {
997                    let align_local = builder.new_var(Some("align".to_string()), ty);
998                    builder.push_statement(StatementKind::Assign(
999                        align_local.clone(),
1000                        Rvalue::NullaryOp(NullOp::AlignOf, self_ty.clone()),
1001                    ));
1002                    Operand::Move(align_local)
1003                }
1004                TrVTableField::Drop => {
1005                    let drop_shim = self.translate_item(
1006                        span,
1007                        impl_def.this(),
1008                        TransItemSourceKind::VTableDropShim,
1009                    )?;
1010                    if self.monomorphize() {
1011                        // manually compute the type of drop shim function.
1012                        let hax::FullDefKind::Trait { dyn_self, .. } = trait_def.kind() else {
1013                            panic!()
1014                        };
1015
1016                        let Some(dyn_self) = dyn_self else {
1017                            panic!(
1018                                "MONO: Trying to generate a vtable for a non-dyn-compatible trait"
1019                            )
1020                        };
1021                        let ref_dyn_self =
1022                            TyKind::RawPtr(self.translate_ty(span, dyn_self)?, RefKind::Mut)
1023                                .into_ty();
1024                        let signature = FunSig {
1025                            is_unsafe: true,
1026                            abi: Abi::rust(),
1027                            inputs: vec![ref_dyn_self.clone()],
1028                            output: Ty::mk_unit(),
1029                        };
1030                        let drop_ty = Ty::new(TyKind::FnPtr(RegionBinder::empty(signature)));
1031
1032                        mk_cast(("drop".to_string(), drop_ty.clone(), drop_shim))
1033                    } else {
1034                        mk_const(ConstantExprKind::FnPtr(drop_shim))
1035                    }
1036                }
1037                TrVTableField::Method(..) => 'a: {
1038                    // Bit of a hack: we know the methods are in the right order. This is easier
1039                    // than trying to index into the items list by name.
1040                    for item in items_iter.by_ref() {
1041                        if let Some(kind) = self.add_method_to_vtable_value(span, trait_id, item)? {
1042                            match kind {
1043                                VtableMethodValue::Const(const_kind) => {
1044                                    break 'a mk_const(const_kind);
1045                                }
1046                                VtableMethodValue::Cast(method) => break 'a mk_cast(method),
1047                            }
1048                        }
1049                    }
1050                    unreachable!()
1051                }
1052                TrVTableField::SuperTrait(clause_id, _) => {
1053                    let trait_proof = &implied_trait_proofs[clause_id.index()];
1054                    let vtable = self.translate_vtable_instance_const(span, trait_proof)?;
1055                    Operand::Const(vtable)
1056                }
1057            };
1058            aggregate_fields.push(op);
1059        }
1060
1061        // Construct the final struct.
1062        builder.push_statement(StatementKind::Assign(
1063            ret_place,
1064            Rvalue::Aggregate(
1065                AggregateKind::Adt(vtable_struct_ref.clone(), None, None),
1066                aggregate_fields,
1067            ),
1068        ));
1069
1070        Ok(Body::Unstructured(builder.build()))
1071    }
1072
1073    pub(crate) fn translate_vtable_instance_init(
1074        mut self,
1075        init_func_id: FunDeclId,
1076        item_meta: ItemMeta,
1077        impl_def: &hax::FullDef<'tcx>,
1078        impl_kind: &TraitImplSource,
1079    ) -> Result<FunDecl, Error> {
1080        let span = item_meta.span;
1081
1082        let (src, vtable_struct_ref) =
1083            match self.get_vtable_instance_info(span, impl_def, impl_kind)? {
1084                (Some(impl_ref), vtable_struct_ref) => {
1085                    (ItemSource::VTableInstance { impl_ref }, vtable_struct_ref)
1086                }
1087                (None, vtable_struct_ref) => (ItemSource::VTableInstanceMono, vtable_struct_ref),
1088            };
1089
1090        let init_for = self.register_item(
1091            span,
1092            impl_def.this(),
1093            TransItemSourceKind::VTableInstance(*impl_kind),
1094        );
1095
1096        // Signature: `() -> VTable`.
1097        let sig = FunSig {
1098            is_unsafe: false,
1099            abi: Abi::rust(),
1100            inputs: vec![],
1101            output: Ty::new(TyKind::Adt(vtable_struct_ref.clone())),
1102        };
1103
1104        let body = match impl_kind {
1105            _ if item_meta.opacity.with_private_contents().is_opaque() => Body::Opaque,
1106            TraitImplSource::Normal => {
1107                self.gen_vtable_instance_init_body(span, impl_def, vtable_struct_ref)?
1108            }
1109            _ => {
1110                raise_error!(
1111                    self,
1112                    span,
1113                    "Don't know how to generate a vtable for a virtual impl {impl_kind:?}"
1114                );
1115            }
1116        };
1117
1118        Ok(FunDecl {
1119            def_id: init_func_id,
1120            item_meta,
1121            generics: self.into_generics(),
1122            signature: Box::new(sig),
1123            src,
1124            is_global_initializer: Some(init_for),
1125            body,
1126        })
1127    }
1128
1129    /// The target vtable shim body looks like:
1130    /// ```ignore
1131    /// local ret@0 : ReturnTy;
1132    /// // the shim receiver of this shim function
1133    /// local shim_self@1 : ShimReceiverTy;
1134    /// // the arguments of the impl function
1135    /// local arg1@2 : Arg1Ty;
1136    /// ...
1137    /// local argN@N : ArgNTy;
1138    /// // the target receiver of the impl function
1139    /// local target_self@(N+1) : TargetReceiverTy;
1140    /// // perform some conversion to cast / re-box the shim receiver to the target receiver
1141    /// ...
1142    /// target_self@(N+1) := concretize_cast<ShimReceiverTy, TargetReceiverTy>(shim_self@1);
1143    /// // call the impl function and assign the result to ret@0
1144    /// ret@0 := impl_func(target_self@(N+1), arg1@2, ..., argN@N);
1145    /// ```
1146    fn translate_vtable_shim_body(
1147        &mut self,
1148        span: Span,
1149        target_receiver: &Ty,
1150        shim_signature: &FunSig,
1151        impl_func_def: &hax::FullDef,
1152    ) -> Result<Body, Error> {
1153        let mut builder = BodyBuilder::new(span, shim_signature.inputs.len());
1154
1155        let ret_place = builder.new_var(None, shim_signature.output.clone());
1156        let mut method_args = shim_signature
1157            .inputs
1158            .iter()
1159            .map(|ty| builder.new_var(None, ty.clone()))
1160            .collect_vec();
1161        let target_self = builder.new_var(None, target_receiver.clone());
1162
1163        // Replace the `dyn Trait` receiver with the concrete one.
1164        let shim_self = mem::replace(&mut method_args[0], target_self.clone());
1165
1166        // Perform the core concretization cast.
1167        // FIXME: need to unpack & re-pack the structure for cases like `Rc`, `Arc`, `Pin` and
1168        // (when --raw-boxes is on) `Box`
1169        let rval = Rvalue::UnaryOp(
1170            UnOp::Cast(CastKind::Concretize(
1171                shim_self.ty().clone(),
1172                target_self.ty().clone(),
1173            )),
1174            Operand::Move(shim_self.clone()),
1175        );
1176        builder.push_statement(StatementKind::Assign(target_self.clone(), rval));
1177
1178        let fun_id = self.register_item(span, impl_func_def.this(), TransItemSourceKind::Fun);
1179        let generics = self.outermost_binder().params.identity_args();
1180        builder.call(Call {
1181            func: FnOperand::Regular(FnPtr::new(FnPtrKind::Fun(fun_id), generics)),
1182            args: method_args.into_iter().map(Operand::Move).collect(),
1183            dest: ret_place,
1184        });
1185
1186        Ok(Body::Unstructured(builder.build()))
1187    }
1188
1189    /// The target vtable drop_shim body looks like:
1190    /// ```ignore
1191    /// local ret@0 : ();
1192    /// // the shim receiver of this drop_shim function
1193    /// local shim_self@1 : ShimReceiverTy;
1194    /// // the target receiver of the drop_shim
1195    /// local target_self@2 : TargetReceiverTy;
1196    /// // perform some conversion to cast / re-box the drop_shim receiver to the target receiver
1197    /// target_self@2 := concretize_cast<ShimReceiverTy, TargetReceiverTy>(shim_self@1);
1198    /// Drop(*target_self@2);
1199    /// ```
1200    fn translate_vtable_drop_shim_body(
1201        &mut self,
1202        span: Span,
1203        shim_receiver: &Ty,
1204        target_receiver: &Ty,
1205        trait_pred: &TraitPredicate,
1206    ) -> Result<Body, Error> {
1207        let mut builder = BodyBuilder::new(span, 1);
1208
1209        builder.new_var(Some("ret".into()), Ty::mk_unit());
1210        let dyn_self = builder.new_var(Some("dyn_self".into()), shim_receiver.clone());
1211        let target_self = builder.new_var(Some("target_self".into()), target_receiver.clone());
1212
1213        // Perform the core concretization cast.
1214        let rval = Rvalue::UnaryOp(
1215            UnOp::Cast(CastKind::Concretize(
1216                dyn_self.ty().clone(),
1217                target_self.ty().clone(),
1218            )),
1219            Operand::Move(dyn_self.clone()),
1220        );
1221        builder.push_statement(StatementKind::Assign(target_self.clone(), rval));
1222
1223        let rustc_trait_args = trait_pred.trait_ref.rustc_args(self.hax_state_with_id());
1224        let rustc_self_ty = rustc_trait_args[0].as_type().unwrap();
1225        let fn_ptr = self.translate_drop_glue_method_call(span, rustc_self_ty)?;
1226
1227        // Drop(*target_self)
1228        let drop_arg = target_self.clone().deref();
1229        builder.insert_drop(drop_arg, fn_ptr);
1230
1231        Ok(Body::Unstructured(builder.build()))
1232    }
1233
1234    pub(crate) fn translate_vtable_drop_shim(
1235        mut self,
1236        fun_id: FunDeclId,
1237        item_meta: ItemMeta,
1238        impl_def: &hax::FullDef,
1239    ) -> Result<FunDecl, Error> {
1240        let span = item_meta.span;
1241
1242        let hax::FullDefKind::TraitImpl {
1243            dyn_self: Some(dyn_self),
1244            trait_pred,
1245            ..
1246        } = impl_def.kind()
1247        else {
1248            raise_error!(
1249                self,
1250                span,
1251                "Trying to generate a vtable drop shim for a non-dyn-compatible trait impl"
1252            );
1253        };
1254
1255        let borrow_region = self.drop_glue_region();
1256
1257        let dyn_self = self.translate_ty(span, dyn_self)?;
1258        // `&mut dyn Trait -> ()`
1259        let signature = self.drop_glue_method_sig(dyn_self.clone(), borrow_region);
1260
1261        // `&mut T` for `impl Trait for T`
1262        let target_self_ref = {
1263            let impl_trait = self.translate_trait_ref(span, &trait_pred.trait_ref)?;
1264            TyKind::Ref(
1265                borrow_region,
1266                impl_trait.generics.types[0].clone(),
1267                RefKind::Mut,
1268            )
1269            .into_ty()
1270        };
1271
1272        let body: Body = self.translate_vtable_drop_shim_body(
1273            span,
1274            &signature.inputs[0],
1275            &target_self_ref,
1276            trait_pred,
1277        )?;
1278
1279        Ok(FunDecl {
1280            def_id: fun_id,
1281            item_meta,
1282            generics: self.into_generics(),
1283            signature: Box::new(signature),
1284            src: ItemSource::VTableMethodShim,
1285            is_global_initializer: None,
1286            body,
1287        })
1288    }
1289
1290    pub(crate) fn translate_vtable_shim(
1291        mut self,
1292        fun_id: FunDeclId,
1293        item_meta: ItemMeta,
1294        impl_func_def: &hax::FullDef,
1295    ) -> Result<FunDecl, Error> {
1296        let span = item_meta.span;
1297
1298        let hax::FullDefKind::AssocFn {
1299            vtable_sig: Some(vtable_sig),
1300            sig: target_signature,
1301            ..
1302        } = impl_func_def.kind()
1303        else {
1304            raise_error!(
1305                self,
1306                span,
1307                "Trying to generate a vtable shim for a non-vtable-safe method"
1308            );
1309        };
1310
1311        // The signature of the shim function.
1312        let signature = self.translate_fun_sig(span, &vtable_sig.value)?;
1313        // The concrete receiver we will cast to.
1314        let target_receiver = self.translate_ty(span, &target_signature.value.inputs[0])?;
1315
1316        trace!(
1317            "[VtableShim] Obtained dyn signature with receiver type: {}",
1318            signature.inputs[0].with_ctx(&self.into_fmt())
1319        );
1320
1321        let body = if item_meta.opacity.with_private_contents().is_opaque() {
1322            Body::Opaque
1323        } else {
1324            self.translate_vtable_shim_body(span, &target_receiver, &signature, impl_func_def)?
1325        };
1326
1327        Ok(FunDecl {
1328            def_id: fun_id,
1329            item_meta,
1330            generics: self.into_generics(),
1331            signature: Box::new(signature),
1332            src: ItemSource::VTableMethodShim,
1333            is_global_initializer: None,
1334            body,
1335        })
1336    }
1337}