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