Skip to main content

charon_driver/translate/
translate_trait_objects.rs

1use itertools::Itertools;
2use rustc_span::kw;
3use std::mem;
4
5use super::{
6    translate_closures::{callable_virtual_impl, recognize_fn_trait_impl_proof},
7    translate_crate::TransItemSourceKind,
8    translate_ctx::*,
9    translate_generics::BindingLevel,
10};
11use crate::hax;
12use crate::hax::TraitPredicate;
13use charon_lib::formatter::IntoFormatter;
14use charon_lib::pretty::FmtWithCtx;
15use charon_lib::ullbc_ast::*;
16
17// Vtable method values that are used to vtable initilization functions.
18// In poly mode, they are const values of shim function pointers direcly filled in vtable fields.
19// In mono mode, they are used for construction of casting statements (see `mk_cast` in `gen_vtable_instance_init_body` for details).
20enum VtableMethodValue {
21    Const(ConstantExprKind),
22    /// The method name, type of the shim function pointer, and shim function pointer.
23    Cast((String, Ty, FnPtr)),
24}
25
26/// Takes a `T` valid in the context of a trait ref and transforms it into a `T` valid in the
27/// context of its vtable definition, i.e. no longer mentions the `Self` type or `Self` clause. If
28/// `new_self` is `Some`, we replace any mention of the `Self` type with it; otherwise we panic if
29/// `Self` is mentioned.
30/// If `for_method` is true, we're handling a value coming from a `AssocFn`, which takes the `Self`
31/// clause as its first clause parameter. Otherwise we're in trait scope, where the `Self` clause
32/// is represented with `TraitRefKind::SelfId`.
33fn dynify<T: TyVisitable>(mut x: T, new_self: Option<Ty>, for_method: bool) -> T {
34    struct ReplaceSelfVisitor {
35        new_self: Option<Ty>,
36        for_method: bool,
37    }
38    impl VarsVisitor for ReplaceSelfVisitor {
39        fn visit_type_var(&mut self, v: TypeDbVar) -> Option<Ty> {
40            if let DeBruijnVar::Bound(DeBruijnId::ZERO, type_id) = v {
41                // Replace type 0 and decrement the others.
42                Some(if let Some(new_id) = type_id.index().checked_sub(1) {
43                    TyKind::TypeVar(DeBruijnVar::Bound(DeBruijnId::ZERO, TypeVarId::new(new_id)))
44                        .into_ty()
45                } else {
46                    self.new_self.clone().expect(
47                        "Found unexpected `Self`
48                        type when constructing vtable",
49                    )
50                })
51            } else {
52                None
53            }
54        }
55
56        fn visit_clause_var(&mut self, v: ClauseDbVar) -> Option<TraitRefKind> {
57            if let DeBruijnVar::Bound(DeBruijnId::ZERO, clause_id) = v {
58                if self.for_method && clause_id == TraitClauseId::ZERO {
59                    // That's the `Self` clause.
60                    Some(TraitRefKind::Dyn)
61                } else {
62                    panic!("Found unexpected clause var when constructing vtable: {v}")
63                }
64            } else {
65                None
66            }
67        }
68
69        fn visit_self_clause(&mut self) -> Option<TraitRefKind> {
70            Some(TraitRefKind::Dyn)
71        }
72    }
73    x.visit_vars(&mut ReplaceSelfVisitor {
74        new_self,
75        for_method,
76    });
77    x
78}
79
80/// Translate the `dyn Trait` type.
81impl<'tcx> ItemTransCtx<'tcx, '_> {
82    pub fn check_at_most_one_pred_has_methods(
83        &mut self,
84        span: Span,
85        preds: &hax::GenericPredicates,
86    ) -> Result<(), Error> {
87        // Only the first clause is allowed to have methods.
88        for pred in preds.predicates.iter().skip(1) {
89            if let hax::ClauseKind::Trait(trait_predicate) = pred.clause.kind.hax_skip_binder_ref()
90            {
91                let trait_def_id = &trait_predicate.trait_ref.def_id;
92                let trait_def = self.poly_hax_def(trait_def_id)?;
93                let has_methods = match trait_def.kind() {
94                    hax::FullDefKind::Trait { items, .. } => items
95                        .iter()
96                        .any(|assoc| matches!(assoc.kind, hax::AssocKind::Fn { .. })),
97                    hax::FullDefKind::TraitAlias { .. } => false,
98                    _ => unreachable!(),
99                };
100                if has_methods {
101                    raise_error!(
102                        self,
103                        span,
104                        "`dyn Trait` with multiple method-bearing predicates is not supported"
105                    );
106                }
107            }
108        }
109        Ok(())
110    }
111
112    pub fn translate_dyn_binder<T, U>(
113        &mut self,
114        span: Span,
115        binder: &hax::DynBinder<T>,
116        f: impl FnOnce(&mut Self, Ty, &T) -> Result<U, Error>,
117    ) -> Result<Binder<U>, Error> {
118        // This is a robustness check: the current version of Rustc
119        // accepts at most one method-bearing predicate in a trait object.
120        // But things may change in the future.
121        self.check_at_most_one_pred_has_methods(span, &binder.predicates)?;
122
123        // Add a binder that contains the existentially quantified type.
124        self.binding_levels.push(BindingLevel::new(None));
125
126        // Add the existentially quantified type.
127        let ty_id = self.innermost_binder_mut().push_type_var(
128            binder.existential_ty.index,
129            binder.existential_ty.name,
130            Variance::Unknown,
131        );
132        let ty = TyKind::TypeVar(DeBruijnVar::new_at_zero(ty_id)).into_ty();
133
134        self.register_predicates(&binder.predicates, PredicateOrigin::Dyn)?;
135
136        let val = f(self, ty, &binder.val)?;
137
138        // As illustrated inside translate_trait_decl, associated items take an extra explicit `Self: Trait` clause in Hax.
139        // Therefore, in mono mode, projection predicates in dyn binders may refer to clause vars with an
140        // extra slot (e.g. `Bound(0, 1)` instead of `Bound(0, 0)`).
141        // Hence, we normalize them so that associated type constraints point to trait clauses in the scope.
142        if self.monomorphize() {
143            struct ShiftDynClauseVars;
144            impl VarsVisitor for ShiftDynClauseVars {
145                fn visit_clause_var(&mut self, v: ClauseDbVar) -> Option<TraitRefKind> {
146                    if let DeBruijnVar::Bound(DeBruijnId::ZERO, clause_id) = v
147                        && let Some(new_id) = clause_id.index().checked_sub(1)
148                    {
149                        return Some(TraitRefKind::Clause(DeBruijnVar::Bound(
150                            DeBruijnId::ZERO,
151                            TraitClauseId::new(new_id),
152                        )));
153                    }
154                    None
155                }
156            }
157
158            self.innermost_generics_mut()
159                .trait_type_constraints
160                .iter_mut()
161                .for_each(|pred| pred.visit_vars(&mut ShiftDynClauseVars));
162        }
163
164        let params = self.binding_levels.pop().unwrap().params;
165        Ok(Binder {
166            params,
167            skip_binder: val,
168            kind: BinderKind::Dyn,
169        })
170    }
171}
172
173/// Vtable field info used for translation (same deal as `charon_lib::VTableField` but with
174/// different data).
175#[derive(Debug)]
176pub enum TrVTableField {
177    Size,
178    Align,
179    Drop,
180    Method(TraitMethodId, hax::Binder<hax::TyFnSig>),
181    SuperTrait(TraitClauseId, hax::Clause),
182}
183
184pub struct VTableData {
185    pub fields: IndexVec<FieldId, TrVTableField>,
186    pub supertrait_map: IndexVec<TraitClauseId, Option<FieldId>>,
187}
188
189/// What we need to know about an impl to fill in its vtable.
190struct VTableInstanceData<'a> {
191    implemented_trait_ref: &'a hax::TraitRef,
192    implied_trait_proofs: &'a [hax::TraitProof],
193    methods: VTableMethodSource<'a>,
194}
195
196/// Where the shims stored in a vtable's method fields come from.
197enum VTableMethodSource<'a> {
198    ImplMethods(IndexVec<TraitMethodId, &'a hax::ImplAssocItem>),
199    FnTraitShim(&'a hax::ItemRef, TransImplSource, &'a hax::PolyFnSig),
200}
201
202/// Generate the vtable struct.
203impl<'tcx> ItemTransCtx<'tcx, '_> {
204    /// Query whether a trait is dyn compatible.
205    /// TODO(dyn): for now we return `false` if the trait has any associated types, as we don't
206    /// handle associated types in vtables.
207    pub fn trait_is_dyn_compatible(&mut self, def_id: &hax::DefId) -> Result<bool, Error> {
208        let def = self.poly_hax_def(def_id)?;
209        Ok(match def.kind() {
210            hax::FullDefKind::Trait { dyn_self, .. }
211            | hax::FullDefKind::TraitAlias { dyn_self, .. } => dyn_self.is_some(),
212            _ => false,
213        })
214    }
215
216    /// Check whether this trait ref is of the form `Self: Trait<...>`.
217    fn pred_is_for_self(&self, tref: &hax::TraitRef) -> bool {
218        let first_ty = tref
219            .generic_args
220            .iter()
221            .filter_map(|arg| match arg {
222                hax::GenericArg::Type(ty) => Some(ty),
223                _ => None,
224            })
225            .next();
226        match first_ty {
227            None => false,
228            Some(first_ty) => match first_ty.kind() {
229                hax::TyKind::Param(param_ty) if param_ty.index == 0 => {
230                    assert_eq!(param_ty.name, kw::SelfUpper);
231                    true
232                }
233                _ => false,
234            },
235        }
236    }
237
238    pub fn translate_vtable_struct_ref(
239        &mut self,
240        span: Span,
241        tref: &hax::TraitRef,
242    ) -> Result<TypeDeclRef, Error> {
243        Ok(self
244            .translate_vtable_struct_ref_maybe_enqueue(true, span, tref)?
245            .expect("trait should be dyn-compatible"))
246    }
247
248    pub fn translate_vtable_struct_ref_no_enqueue(
249        &mut self,
250        span: Span,
251        tref: &hax::TraitRef,
252    ) -> Result<Option<TypeDeclRef>, Error> {
253        self.translate_vtable_struct_ref_maybe_enqueue(false, span, tref)
254    }
255
256    /// Given a trait ref, return a reference to its vtable struct, if it is dyn compatible.
257    pub fn translate_vtable_struct_ref_maybe_enqueue(
258        &mut self,
259        enqueue: bool,
260        span: Span,
261        tref: &hax::TraitRef,
262    ) -> Result<Option<TypeDeclRef>, Error> {
263        if !self.trait_is_dyn_compatible(&tref.def_id)? {
264            return Ok(None);
265        }
266
267        // FIXME: preserve legacy behavior, maybe undesired.
268        let enqueue = enqueue || self.monomorphize();
269
270        // Don't enqueue the vtable for translation by default. It will be enqueued if used in a
271        // `dyn Trait`.
272        let mut vtable_ref = self.translate_type_decl_ref_maybe_enqueue(
273            span,
274            tref,
275            TransItemSourceKind::VTable,
276            enqueue,
277        )?;
278        // Remove the `Self` type variable from the generic parameters.
279        vtable_ref
280            .generics
281            .types
282            .remove_and_shift_ids(TypeVarId::ZERO);
283
284        if !self.monomorphize() {
285            // The vtable type also takes associated types as parameters.
286            let assoc_tys: Vec<_> = tref
287                .trait_associated_types(self.hax_state_with_id())
288                .iter()
289                .map(|ty| self.translate_ty(span, ty))
290                .try_collect()?;
291            vtable_ref.generics.types.extend(assoc_tys);
292        }
293
294        Ok(Some(vtable_ref))
295    }
296
297    fn prepare_vtable_fields(
298        &mut self,
299        poly_trait_def: &hax::FullDef<'tcx>,
300        trait_id: TraitDeclId,
301        implied_predicates: &hax::GenericPredicates,
302    ) -> Result<VTableData, Error> {
303        let mut supertrait_map: IndexVec<TraitClauseId, _> =
304            (0..implied_predicates.predicates.len())
305                .map(|_| None)
306                .collect();
307        let mut fields = IndexVec::new();
308
309        // Basic fields.
310        fields.push(TrVTableField::Size);
311        fields.push(TrVTableField::Align);
312        fields.push(TrVTableField::Drop);
313
314        // Method fields.
315        if let hax::FullDefKind::Trait { items, .. } = poly_trait_def.kind() {
316            for item in items {
317                let item_def_id = &item.def_id;
318                // This is ok because dyn-compatible methods don't have generics.
319                let poly_item_def = self.poly_hax_def(item_def_id)?;
320                if let hax::FullDefKind::AssocFn {
321                    vtable_sig: Some(sig),
322                    ..
323                } = poly_item_def.kind()
324                {
325                    let id = self.translate_trait_method_id_no_enqueue(trait_id, item_def_id)?;
326                    fields.push(TrVTableField::Method(id, sig.clone()));
327                }
328            }
329        }
330
331        // Supertrait fields.
332        for (i, pred) in implied_predicates.iter_trait_clauses().enumerate() {
333            let trait_clause_id = TraitClauseId::from_usize(i); // One trait clause id per trait clause
334            let clause = &pred.clause;
335            let hax::ClauseKind::Trait(pred) = clause.kind.hax_skip_binder_ref() else {
336                unreachable!()
337            };
338            // If a clause looks like `Self: OtherTrait<...>`, we consider it a supertrait.
339            if self.pred_is_for_self(&pred.trait_ref) {
340                if !self.trait_is_dyn_compatible(&pred.trait_ref.def_id)? {
341                    // We add fake `Destruct` supertraits, but these are not dyn-compatible.
342                    self.assert_is_destruct(&pred.trait_ref);
343                    continue;
344                }
345                supertrait_map[trait_clause_id] = Some(fields.next_idx());
346                fields.push(TrVTableField::SuperTrait(trait_clause_id, clause.clone()));
347            }
348        }
349
350        Ok(VTableData {
351            fields,
352            supertrait_map,
353        })
354    }
355
356    /// The Charon+Hax machinery will add Destruct super-traits to trait bounds,
357    /// however for `dyn Trait` the Destruct super-trait is unexepcted, as it is not
358    /// dyn-compatible.
359    /// We use this function to ensure that any non dyn-compatible super-trait is
360    /// Destruct and can be safely ignored.
361    fn assert_is_destruct(&self, tref: &hax::TraitRef) {
362        assert!(
363            tref.def_id
364                .as_real_def_id()
365                .is_some_and(|id| self.tcx.is_lang_item(id, rustc_attr_ir::LangItem::Destruct)),
366            "unexpected non-dyn compatible supertrait: {:?}",
367            tref.def_id
368        );
369    }
370
371    fn gen_vtable_struct_fields(
372        &mut self,
373        span: Span,
374        self_trait_ref: &TraitRef,
375        vtable_data: &VTableData,
376    ) -> Result<IndexVec<FieldId, Field>, Error> {
377        let mut fields = IndexVec::new();
378        let mut supertrait_counter = 0..;
379        for field in &vtable_data.fields {
380            let (name, ty) = match field {
381                TrVTableField::Size => ("size".into(), Ty::mk_usize()),
382                TrVTableField::Align => ("align".into(), Ty::mk_usize()),
383                TrVTableField::Drop => {
384                    // In Mono mode, drop shims are opaque function pointers.
385                    if self.monomorphize() {
386                        let erased_ptr_ty = Ty::new(TyKind::RawPtr(Ty::mk_unit(), RefKind::Shared));
387                        ("drop".into(), erased_ptr_ty)
388                    } else {
389                        let self_ty =
390                            TyKind::TypeVar(DeBruijnVar::new_at_zero(TypeVarId::ZERO)).into_ty();
391                        let drop_ty = Ty::new(TyKind::FnPtr(self.drop_glue_fn_ptr_sig(self_ty)));
392                        ("drop".into(), drop_ty)
393                    }
394                }
395                TrVTableField::Method(item_id, sig) => {
396                    let item_name = self
397                        .translated
398                        .assoc_item_name(self_trait_ref.trait_id(), *item_id);
399                    let field_name = format!("method_{}", item_name.0);
400                    // In Mono mode, method shims are opaque function pointers.
401                    if self.monomorphize() {
402                        let erased_ptr_ty = Ty::new(TyKind::RawPtr(Ty::mk_unit(), RefKind::Shared));
403                        (field_name, erased_ptr_ty)
404                    } else {
405                        let sig = self.translate_poly_fun_sig(span, sig)?;
406                        let ty = TyKind::FnPtr(sig).into_ty();
407                        (field_name, ty)
408                    }
409                }
410                TrVTableField::SuperTrait(_, clause) => {
411                    let vtbl_struct =
412                        self.translate_region_binder(span, &clause.kind, |ctx, kind| {
413                            let hax::ClauseKind::Trait(pred) = kind else {
414                                unreachable!()
415                            };
416                            ctx.translate_vtable_struct_ref(span, &pred.trait_ref)
417                        })?;
418                    let vtbl_struct = self.erase_region_binder(vtbl_struct);
419                    let ty = Ty::new(TyKind::Ref(
420                        Region::Static,
421                        Ty::new(TyKind::Adt(vtbl_struct)),
422                        RefKind::Shared,
423                    ));
424                    let name = format!("super_trait_{}", supertrait_counter.next().unwrap());
425                    (name, ty)
426                }
427            };
428            fields.push(Field {
429                span,
430                attr_info: AttrInfo::dummy_public(),
431                name,
432                is_positional: false,
433                ty,
434            });
435        }
436        Ok(fields)
437    }
438
439    /// Construct the type of the vtable for this trait.
440    ///
441    /// It's a struct that has for generics the generics of the trait + one parameter for each
442    /// associated type of the trait and its parents.
443    ///
444    /// struct TraitVTable<TraitArgs.., AssocTys..> {
445    ///   size: usize,
446    ///   align: usize,
447    ///   drop: fn(*mut dyn Trait<...>),
448    ///   method_name: fn(&dyn Trait<...>, Args..) -> Output,
449    ///   by_value_method: fn(*mut dyn Trait<...>, Args..) -> Output,
450    ///   ... other methods
451    ///   super_trait_0: &'static SuperTrait0VTable
452    ///   ... other supertraits
453    /// }
454    pub(crate) fn translate_vtable_struct(
455        mut self,
456        type_id: TypeDeclId,
457        item_meta: ItemMeta,
458        trait_def: &hax::FullDef<'tcx>,
459    ) -> Result<TypeDecl, Error> {
460        let mono = self.monomorphize();
461        let span = item_meta.span;
462        if !self.trait_is_dyn_compatible(trait_def.def_id())? {
463            raise_error!(
464                self,
465                span,
466                "Trying to compute the vtable type \
467                for a non-dyn-compatible trait"
468            );
469        }
470
471        let (hax::FullDefKind::Trait {
472            self_predicate,
473            dyn_self,
474            implied_predicates,
475            ..
476        }
477        | hax::FullDefKind::TraitAlias {
478            self_predicate,
479            dyn_self,
480            implied_predicates,
481            ..
482        }) = trait_def.kind()
483        else {
484            panic!()
485        };
486        let Some(dyn_self) = dyn_self else {
487            panic!("Trying to generate a vtable for a non-dyn-compatible trait")
488        };
489
490        let self_trait_ref = TraitRef::new(
491            TraitRefKind::SelfId,
492            RegionBinder::empty(self.translate_trait_predicate(span, self_predicate)?),
493        );
494        let trait_id = self_trait_ref.trait_id();
495
496        let mut field_map = IndexVec::new();
497        let mut supertrait_map: IndexVec<TraitClauseId, _> =
498            (0..implied_predicates.predicates.len())
499                .map(|_| None)
500                .collect();
501        let (mut kind, layout) = if item_meta.opacity.with_private_contents().is_opaque() {
502            (TypeDeclKind::Opaque, SeqHashMap::default())
503        } else {
504            // First construct fields that use the real method signatures (which may use the `Self`
505            // type). We fixup the types and generics below.
506            let vtable_data =
507                self.prepare_vtable_fields(trait_def, trait_id, implied_predicates)?;
508            let fields = self.gen_vtable_struct_fields(span, &self_trait_ref, &vtable_data)?;
509
510            let kind = TypeDeclKind::Struct(fields);
511            let l = self.generate_naive_layout(span, &kind)?;
512            supertrait_map = vtable_data.supertrait_map;
513            field_map = vtable_data.fields.map_ref(|tr_field| match *tr_field {
514                TrVTableField::Size => VTableField::Size,
515                TrVTableField::Align => VTableField::Align,
516                TrVTableField::Drop => VTableField::Drop,
517                TrVTableField::Method(id, ..) => VTableField::Method(id),
518                TrVTableField::SuperTrait(clause_id, ..) => VTableField::SuperTrait(clause_id),
519            });
520            let layout = [(self.get_target_triple(), l)].into();
521            (kind, layout)
522        };
523
524        let mut generics = Default::default();
525
526        let dyn_predicate = if mono {
527            DynPredicate {
528                binder: Binder {
529                    params: GenericParams::empty(),
530                    skip_binder: TyKind::Error(
531                        "mono vtable dyn predicate is intentionally erased".to_string(),
532                    )
533                    .into_ty(),
534                    kind: BinderKind::Dyn,
535                },
536            }
537        } else {
538            // The `dyn Trait<Args..>` type for this trait.
539            // This is only used in poly mode
540            let mut dyn_self = {
541                let dyn_self = self.translate_ty(span, dyn_self)?;
542                let TyKind::DynTrait(mut dyn_pred) = dyn_self.kind().clone() else {
543                    panic!("incorrect `dyn_self`")
544                };
545
546                // Add one generic parameter for each associated type of this trait and its parents. We
547                // then use that in `dyn_self`
548                for (i, ty_constraint) in dyn_pred
549                    .binder
550                    .params
551                    .trait_type_constraints
552                    .iter_mut()
553                    .enumerate()
554                {
555                    let name = format!("Ty{i}");
556                    let new_ty = self
557                        .the_only_binder_mut()
558                        .params
559                        .types
560                        .push_with(|index| TypeParam::new(index, name, Variance::Invariant));
561                    // Moving that type under two levels of binders: the `DynPredicate` binder and the
562                    // type constraint binder.
563                    let new_ty =
564                        TyKind::TypeVar(DeBruijnVar::bound(DeBruijnId::new(2), new_ty)).into_ty();
565                    ty_constraint.skip_binder.ty = new_ty;
566                }
567                TyKind::DynTrait(dyn_pred).into_ty()
568            };
569
570            // Replace any use of `Self` with `dyn Trait<...>`, and remove the `Self` type variable
571            // from the generic parameters.
572            generics = self.into_generics();
573            {
574                dyn_self = dynify(dyn_self, None, false);
575                generics = dynify(generics, Some(dyn_self.clone()), false);
576                kind = dynify(kind, Some(dyn_self.clone()), true);
577                generics.types.remove_and_shift_ids(TypeVarId::ZERO);
578                generics.types.iter_mut().for_each(|ty| {
579                    ty.index -= 1;
580                });
581            }
582
583            dyn_self
584                .kind()
585                .as_dyn_trait()
586                .expect("incorrect `dyn_self`")
587                .clone()
588        };
589        Ok(TypeDecl {
590            def_id: type_id,
591            item_meta,
592            generics,
593            src: TypeSource::VTable {
594                dyn_predicate,
595                field_map,
596                supertrait_map,
597            },
598            kind,
599            layout,
600            // A vtable struct is always sized
601            ptr_metadata: PtrMetadata::None,
602        })
603    }
604}
605
606/// Generate a vtable value.
607impl<'tcx> ItemTransCtx<'tcx, '_> {
608    /// Construct a constant that represents a reference to the vtable corresponding to this this trait proof.
609    pub fn translate_vtable_instance_const(
610        &mut self,
611        span: Span,
612        trait_proof: &hax::TraitProof,
613    ) -> Result<ConstantExpr, Error> {
614        let tref = trait_proof.pred.hax_skip_binder_ref();
615        if !self.trait_is_dyn_compatible(&tref.def_id)? {
616            raise_error!(
617                self,
618                span,
619                "Trait {:?} should be dyn-compatible",
620                tref.def_id
621            );
622        }
623
624        let vtbl_ty = {
625            let vtbl_ty = self.translate_region_binder(span, &trait_proof.pred, |ctx, tref| {
626                ctx.translate_vtable_struct_ref(span, tref)
627            })?;
628            let vtbl_ty = self.erase_region_binder(vtbl_ty);
629            TyKind::Adt(vtbl_ty).into_ty()
630        };
631        let ty = TyKind::Ref(Region::Static, vtbl_ty.clone(), RefKind::Shared).into_ty();
632
633        let fn_trait_impl = recognize_fn_trait_impl_proof(trait_proof);
634        let kind = match &trait_proof.kind {
635            // The marker trait vtable translation pipeline would give incorrect results for the
636            // `Fn*` impl of a function pointer, which has no item to hang the impl off.
637            // FIXME(dyn): translate vtables for the `Fn*` impls of function pointers
638            _ if let Some((self_ty, _)) = &fn_trait_impl
639                && !matches!(
640                    self_ty.hax_skip_binder_ref().kind(),
641                    hax::TyKind::Closure(..) | hax::TyKind::FnDef { .. }
642                ) =>
643            {
644                ConstantExprKind::VTableRef(self.translate_trait_proof(span, trait_proof)?)
645            }
646            hax::TraitProofKind::Concrete { .. } | hax::TraitProofKind::Builtin { .. } => {
647                // We could return `VTableRef` but we need to enqueue the translation of the static
648                // so may as well reuse that to normalize a bit.
649                let vtable_instance =
650                    self.translate_region_binder(span, &trait_proof.pred, |ctx, tref| {
651                        // We're inside the binder of `trait_proof.pred`, so we can skip the
652                        // binder of the `Self` type.
653                        let (impl_item, impl_kind) = match (&trait_proof.kind, fn_trait_impl) {
654                            (hax::TraitProofKind::Concrete(impl_item), _) => {
655                                (impl_item, TransImplSource::Normal)
656                            }
657                            // This is a builtin `Fn*` impl for a callable.
658                            (_, Some((self_ty, kind))) => {
659                                match self_ty.hax_skip_binder_ref().kind() {
660                                    hax::TyKind::Closure(args) => {
661                                        (&args.item, TransImplSource::Callable(kind))
662                                    }
663                                    hax::TyKind::FnDef { item, .. } => {
664                                        (item, TransImplSource::Callable(kind))
665                                    }
666                                    _ => unreachable!("builtin `Fn*` impl for {self_ty:?}"),
667                                }
668                            }
669                            (_, None) => (tref, TransImplSource::Marker),
670                        };
671                        ctx.translate_vtable_instance_ref(span, tref, impl_item, impl_kind)
672                    })?;
673                let vtable_instance = self.erase_region_binder(vtable_instance);
674                let vtable_instance =
675                    ConstantExpr::new(ConstantExprKind::Global(vtable_instance), vtbl_ty);
676                ConstantExprKind::Ref(vtable_instance, None)
677            }
678            _ => ConstantExprKind::VTableRef(self.translate_trait_proof(span, trait_proof)?),
679        };
680
681        Ok(ConstantExpr::new(kind, ty))
682    }
683
684    /// You may want `translate_vtable_instance_const` instead.
685    pub fn translate_vtable_instance_ref(
686        &mut self,
687        span: Span,
688        trait_ref: &hax::TraitRef,
689        vtable_item: &hax::ItemRef,
690        impl_kind: TransImplSource,
691    ) -> Result<GlobalDeclRef, Error> {
692        Ok(self
693            .translate_vtable_instance_ref_maybe_enqueue(
694                true,
695                span,
696                trait_ref,
697                vtable_item,
698                impl_kind,
699            )?
700            .expect("trait should be dyn-compatible"))
701    }
702
703    pub fn translate_vtable_instance_ref_no_enqueue(
704        &mut self,
705        span: Span,
706        trait_ref: &hax::TraitRef,
707        vtable_item: &hax::ItemRef,
708        impl_kind: TransImplSource,
709    ) -> Result<Option<GlobalDeclRef>, Error> {
710        self.translate_vtable_instance_ref_maybe_enqueue(
711            false,
712            span,
713            trait_ref,
714            vtable_item,
715            impl_kind,
716        )
717    }
718
719    pub fn translate_vtable_instance_ref_maybe_enqueue(
720        &mut self,
721        enqueue: bool,
722        span: Span,
723        trait_ref: &hax::TraitRef,
724        vtable_item: &hax::ItemRef,
725        impl_kind: TransImplSource,
726    ) -> Result<Option<GlobalDeclRef>, Error> {
727        if !self.trait_is_dyn_compatible(&trait_ref.def_id)? {
728            return Ok(None);
729        }
730        // Don't enqueue the vtable for translation by default. It will be enqueued if used in a
731        // `dyn Trait` coercion.
732        // TODO(dyn): To do this properly we'd need to know for each clause whether it ultimately
733        // ends up used in a vtable cast.
734        let vtable_ref: GlobalDeclRef = self.translate_item_maybe_enqueue(
735            span,
736            vtable_item,
737            TransItemSourceKind::VTableInstance(impl_kind),
738            enqueue,
739        )?;
740        Ok(Some(vtable_ref))
741    }
742
743    /// Local helper function to get the vtable struct reference and trait declaration reference
744    fn get_vtable_instance_info(
745        &mut self,
746        span: Span,
747        impl_def: &hax::FullDef<'tcx>,
748        impl_kind: TransImplSource,
749    ) -> Result<(Option<TraitImplRef>, TypeDeclRef), Error> {
750        let implemented_trait = self
751            .vtable_instance_data(impl_def, impl_kind)
752            .implemented_trait_ref;
753        let vtable_struct_ref = self.translate_vtable_struct_ref(span, implemented_trait)?;
754        let impl_ref = if impl_kind == TransImplSource::Marker || self.monomorphize() {
755            None
756        } else {
757            Some(self.translate_item(
758                span,
759                impl_def.this(),
760                TransItemSourceKind::TraitImpl(impl_kind),
761            )?)
762        };
763        Ok((impl_ref, vtable_struct_ref))
764    }
765
766    /// E.g.,
767    /// ```
768    /// global {impl Trait for Foo}::vtable<Args..>: Trait::{vtable}<TraitArgs.., AssocTys..> {
769    ///     size: size_of(Foo),
770    ///     align: align_of(Foo),
771    ///     drop: <Foo as Destruct>::drop_glue,
772    ///     method_0: <Foo as Trait>::method_0::{shim},
773    ///     method_1: <Foo as Trait>::method_1::{shim},
774    ///     ...
775    ///     super_trait_0: SuperImpl0<..>::{vtable_instance}::<..>,
776    ///     super_trait_1: SuperImpl1<..>::{vtable_instance}::<..>,
777    ///     ...
778    /// }
779    /// ```
780    pub(crate) fn translate_vtable_instance(
781        mut self,
782        global_id: GlobalDeclId,
783        item_meta: ItemMeta,
784        impl_def: &hax::FullDef<'tcx>,
785        impl_kind: TransImplSource,
786    ) -> Result<GlobalDecl, Error> {
787        let span = item_meta.span;
788
789        let (impl_ref, vtable_struct_ref) =
790            self.get_vtable_instance_info(span, impl_def, impl_kind)?;
791        let src = GlobalSource::VTableInstance { impl_ref };
792
793        // Initializer function for this global.
794        let init = self.register_item(
795            span,
796            impl_def.this(),
797            TransItemSourceKind::VTableInstanceInitializer(impl_kind),
798        );
799        let ty = Ty::new(TyKind::Adt(vtable_struct_ref));
800        let value = ConstantExpr::new(
801            ConstantExprKind::Call(
802                FnPtr::new(
803                    FnPtrKind::Fun(init),
804                    self.outermost_generics().identity_args(),
805                ),
806                vec![],
807            ),
808            ty.clone(),
809        );
810
811        Ok(GlobalDecl {
812            def_id: global_id,
813            item_meta,
814            generics: self.into_generics(),
815            src,
816            // it should be static to have its own address
817            global_kind: GlobalKind::Static,
818            ty,
819            value,
820        })
821    }
822
823    /// Gather what we need to fill in the vtable of this impl.
824    fn vtable_instance_data<'a>(
825        &self,
826        impl_def: &'a hax::FullDef<'tcx>,
827        impl_kind: TransImplSource,
828    ) -> VTableInstanceData<'a> {
829        match (impl_kind, impl_def.kind()) {
830            // The def is the closure or fn item; the impl is one of its virtual `Fn*` impls.
831            (TransImplSource::Callable(target_kind), _) => {
832                let vimpl = callable_virtual_impl(impl_def, target_kind);
833                let vtable_sig = vimpl.methods[0]
834                    .1
835                    .as_ref()
836                    .expect("a callable with a vtable must be dyn-compatible");
837                VTableInstanceData {
838                    implemented_trait_ref: &vimpl.trait_pred.trait_ref,
839                    implied_trait_proofs: &vimpl.implied_trait_proofs,
840                    methods: VTableMethodSource::FnTraitShim(
841                        impl_def.this(),
842                        impl_kind,
843                        vtable_sig,
844                    ),
845                }
846            }
847            (
848                TransImplSource::Normal,
849                hax::FullDefKind::TraitImpl {
850                    trait_pred,
851                    items,
852                    implied_trait_proofs,
853                    ..
854                },
855            ) => {
856                // The methods are indexed in the order provided by hax, which is the order of the
857                // trait declaration.
858                let methods: IndexVec<TraitMethodId, _> = items
859                    .iter()
860                    .filter(|item| matches!(item.decl_def_id.kind, hax::DefKind::AssocFn))
861                    .collect();
862                VTableInstanceData {
863                    implemented_trait_ref: &trait_pred.trait_ref,
864                    implied_trait_proofs,
865                    methods: VTableMethodSource::ImplMethods(methods),
866                }
867            }
868            (
869                TransImplSource::Marker,
870                hax::FullDefKind::Trait {
871                    self_predicate,
872                    implied_trait_proofs,
873                    ..
874                },
875            ) => VTableInstanceData {
876                implemented_trait_ref: &self_predicate.trait_ref,
877                implied_trait_proofs,
878                methods: VTableMethodSource::ImplMethods(IndexVec::new()),
879            },
880            _ => unreachable!(),
881        }
882    }
883
884    /// The shim to store in the next method field of a vtable.
885    fn vtable_method_value(
886        &mut self,
887        span: Span,
888        trait_id: TraitDeclId,
889        method_id: TraitMethodId,
890        implemented_trait: &hax::TraitRef,
891        methods: &VTableMethodSource<'_>,
892    ) -> Result<VtableMethodValue, Error> {
893        match methods {
894            VTableMethodSource::ImplMethods(methods) => {
895                let item = methods[method_id];
896                // The method is vtable safe so it has no generics, hence we can skip the binder.
897                let item_ref = match &item.value {
898                    Some(value) => value.skip_binder.item.clone(),
899                    // The impl doesn't provide this method, so we get the trait's default.
900                    None => {
901                        let hax_state = self.hax_state_with_id();
902                        let trait_args = implemented_trait.rustc_args(hax_state);
903                        hax::ItemRef::translate_from_hax_def_id(
904                            hax_state,
905                            item.decl_def_id.clone(),
906                            trait_args,
907                        )
908                    }
909                };
910                let shim = self.translate_fn_ptr(
911                    span,
912                    &item_ref,
913                    TransItemSourceKind::VTableMethod(TransImplSource::Normal),
914                )?;
915
916                // In mono mode the vtable fields are erased pointers, so we must compute the real type of
917                // each shim to cast it from.
918                if !self.monomorphize() {
919                    return Ok(VtableMethodValue::Const(ConstantExprKind::FnPtr(shim)));
920                }
921
922                // Manually translate region params for dyn trait.
923                // We create a new binding level by `translate_item_generics`
924                // and restore the orginal one after computing `method_ty`.
925                assert!(self.binding_levels.len() == 1);
926                let orginal_binding = self.binding_levels.pop();
927                let assoc_fun_def = self.hax_def(&item_ref)?;
928                self.translate_item_generics(
929                    span,
930                    &assoc_fun_def,
931                    &TransItemSourceKind::VTableMethod(TransImplSource::Normal),
932                )?;
933                let vtable_sig = match assoc_fun_def.kind() {
934                    hax::FullDefKind::AssocFn {
935                        vtable_sig: Some(vtable_sig),
936                        ..
937                    } => vtable_sig.clone(),
938                    _ => unreachable!("MONO: only assoc fun is supported"),
939                };
940
941                let signature = self.translate_fun_sig(span, &vtable_sig.value)?;
942                // Add regions. this is ad-hoc...
943                let method_ty = Ty::new(TyKind::FnPtr(RegionBinder {
944                    regions: self.outermost_generics().regions.clone(),
945                    skip_binder: signature,
946                }));
947
948                // Restore the orignal binding_levels.
949                self.binding_levels.pop();
950                if let Some(binding_level) = orginal_binding {
951                    self.binding_levels.push(binding_level);
952                }
953
954                self.mark_method_as_used(trait_id, method_id);
955                let method_name = self
956                    .translated
957                    .assoc_item_name(trait_id, method_id)
958                    .to_string();
959                Ok(VtableMethodValue::Cast((method_name, method_ty, shim)))
960            }
961            &VTableMethodSource::FnTraitShim(item, impl_source, vtable_sig) => {
962                let shim = self.translate_fn_ptr(
963                    span,
964                    item,
965                    TransItemSourceKind::VTableMethod(impl_source),
966                )?;
967                if !self.monomorphize() {
968                    return Ok(VtableMethodValue::Const(ConstantExprKind::FnPtr(shim)));
969                }
970                // In mono mode the vtable field is an erased pointer, so we must compute the real
971                // type of the shim to cast from.
972                let bound_sig = self.translate_region_binder(span, vtable_sig, |ctx, sig| {
973                    ctx.translate_fun_sig(span, sig)
974                })?;
975                let method_ty = TyKind::FnPtr(bound_sig).into_ty();
976                let method_name = self
977                    .translated
978                    .assoc_item_name(trait_id, method_id)
979                    .to_string();
980                Ok(VtableMethodValue::Cast((method_name, method_ty, shim)))
981            }
982        }
983    }
984
985    /// Generate the body of the vtable instance function.
986    /// ```ignore
987    /// let ret@0 : VTable;
988    /// ret@0 = VTable { ... };
989    /// return;
990    /// ```
991    fn gen_vtable_instance_init_body(
992        &mut self,
993        span: Span,
994        impl_def: &hax::FullDef<'tcx>,
995        vtable_struct_ref: TypeDeclRef,
996        impl_kind: TransImplSource,
997    ) -> Result<Body, Error> {
998        let VTableInstanceData {
999            implemented_trait_ref,
1000            implied_trait_proofs,
1001            methods,
1002        } = self.vtable_instance_data(impl_def, impl_kind);
1003
1004        let trait_def = self.hax_def(implemented_trait_ref)?;
1005        // We use `poly_trait_def` to fetch `implied_preds`, which is used to fetch supertrait in `prepare_vtable_fields`.
1006        let poly_trait_def = self.poly_hax_def(&implemented_trait_ref.def_id)?;
1007        let hax::FullDefKind::Trait {
1008            implied_predicates: implied_preds,
1009            ..
1010        } = poly_trait_def.kind()
1011        else {
1012            unreachable!()
1013        };
1014
1015        let implemented_trait = self.translate_trait_decl_ref(span, implemented_trait_ref)?;
1016        let trait_id = implemented_trait.id;
1017        // The type this impl is for.
1018        let self_ty = &implemented_trait.generics.types[0];
1019
1020        let mut builder = BodyBuilder::new(span, 0);
1021        let ret_ty = Ty::new(TyKind::Adt(vtable_struct_ref.clone()));
1022        let ret_place = builder.new_var(Some("ret".into()), ret_ty.clone());
1023
1024        let vtable_data = self.prepare_vtable_fields(&poly_trait_def, trait_id, implied_preds)?;
1025        // Retrieve the expected field types from the struct definition. This avoids complicated
1026        // substitutions.
1027        let field_tys = {
1028            let ItemRef::Type(vtable_def) =
1029                self.t_ctx.get_or_translate(vtable_struct_ref.id.into())?
1030            else {
1031                unreachable!()
1032            };
1033            let fields = match &vtable_def.kind {
1034                TypeDeclKind::Struct(fields) => fields,
1035                TypeDeclKind::Opaque => return Ok(Body::Opaque),
1036                TypeDeclKind::Error(error) => return Err(Error::new(span, error.clone())),
1037                _ => unreachable!(),
1038            };
1039            fields
1040                .iter()
1041                .map(|f| &f.ty)
1042                .cloned()
1043                .map(|ty| ty.substitute(&vtable_struct_ref.generics))
1044                .collect_vec()
1045        };
1046
1047        // Construct a list with one operand per vtable field.
1048        let mut aggregate_fields = vec![];
1049        for (field, ty) in vtable_data.fields.into_iter().zip(field_tys) {
1050            // In poly mode, all fields of vtables can be filled with const values.
1051            let mk_const = |kind| Operand::Const(ConstantExpr::new(kind, ty.clone()));
1052            // In mono mode, we need to additioanlly cast shim function pointers to opaque ones before filling them.
1053            // Therefore, `mk_cast` receives `(method_name, method_ty, method_shim)` to construct casting statements.
1054            // For example, for the trait declaration and trait implementation in Rust:
1055            // ```
1056            // trait Trait {
1057            //      fn method(&self);
1058            // }
1059            // impl Trait for i32 {
1060            //      fn method(&self) {}
1061            // }
1062            // ```
1063            //  , `mk_cast` will generate the followging statements inside the vtable initialization function:
1064            // ```
1065            // fn vtable_init() -> vtable {
1066            //      ...
1067            //      let method_local: fn<'_0_1>(&'_0_1 (dyn Trait + '1));
1068            //      let cast_local: *const ();
1069            //
1070            //      method_local = const {shim}<'1>
1071            //      cast_local = cast<fn<'_0_1>(&'_0_1 (dyn Trait + '2)), *const ()>(move method_local)
1072            //      ...
1073            // }
1074            // ```
1075            let mut mk_cast = |(method_name, method_ty, method_shim): (String, Ty, FnPtr)| {
1076                let method_local = builder.new_var(Some(method_name.clone()), method_ty.clone());
1077                let shim = Rvalue::Use(
1078                    Operand::Const(ConstantExpr::new(
1079                        ConstantExprKind::FnPtr(method_shim.clone()),
1080                        method_ty.clone(),
1081                    )),
1082                    WithRetag::No,
1083                );
1084                let cast_local = builder.new_var(
1085                    Some("erased_".to_string() + method_name.as_str()),
1086                    ty.clone(),
1087                );
1088                let cast = Rvalue::UnaryOp(
1089                    UnOp::Cast(CastKind::RawPtr(
1090                        method_local.ty().clone(),
1091                        cast_local.ty().clone(),
1092                    )),
1093                    Operand::Move(method_local.clone()),
1094                );
1095
1096                builder.push_statement(StatementKind::Assign(method_local.clone(), shim));
1097                builder.push_statement(StatementKind::Assign(cast_local.clone(), cast));
1098                Operand::Move(cast_local)
1099            };
1100            let op = match field {
1101                TrVTableField::Size => mk_const(ConstantExprKind::SizeOf(self_ty.clone())),
1102                TrVTableField::Align => mk_const(ConstantExprKind::AlignOf(self_ty.clone())),
1103                TrVTableField::Drop => {
1104                    let drop_shim = self.translate_item(
1105                        span,
1106                        impl_def.this(),
1107                        TransItemSourceKind::VTableDropShim(impl_kind),
1108                    )?;
1109                    if self.monomorphize() {
1110                        // manually compute the type of drop shim function.
1111                        let hax::FullDefKind::Trait { dyn_self, .. } = trait_def.kind() else {
1112                            panic!()
1113                        };
1114
1115                        let Some(dyn_self) = dyn_self else {
1116                            panic!(
1117                                "MONO: Trying to generate a vtable for a non-dyn-compatible trait"
1118                            )
1119                        };
1120                        let ref_dyn_self =
1121                            TyKind::RawPtr(self.translate_ty(span, dyn_self)?, RefKind::Mut)
1122                                .into_ty();
1123                        let signature = FunSig {
1124                            is_unsafe: true,
1125                            abi: Abi::rust(),
1126                            is_variadic: false,
1127                            inputs: vec![ref_dyn_self.clone()],
1128                            output: Ty::mk_unit(),
1129                        };
1130                        let drop_ty = Ty::new(TyKind::FnPtr(RegionBinder::empty(signature)));
1131
1132                        mk_cast(("drop".to_string(), drop_ty.clone(), drop_shim))
1133                    } else {
1134                        mk_const(ConstantExprKind::FnPtr(drop_shim))
1135                    }
1136                }
1137                TrVTableField::Method(method_id, _) => {
1138                    let value = self.vtable_method_value(
1139                        span,
1140                        trait_id,
1141                        method_id,
1142                        implemented_trait_ref,
1143                        &methods,
1144                    )?;
1145                    match value {
1146                        VtableMethodValue::Const(const_kind) => mk_const(const_kind),
1147                        VtableMethodValue::Cast(method) => mk_cast(method),
1148                    }
1149                }
1150                TrVTableField::SuperTrait(clause_id, _) => {
1151                    let trait_proof = &implied_trait_proofs[clause_id.index()];
1152                    Operand::Const(self.translate_vtable_instance_const(span, trait_proof)?)
1153                }
1154            };
1155            aggregate_fields.push(op);
1156        }
1157
1158        // Construct the final struct.
1159        builder.push_statement(StatementKind::Assign(
1160            ret_place,
1161            Rvalue::Aggregate(
1162                AggregateKind::Adt(vtable_struct_ref.clone(), None, None),
1163                aggregate_fields,
1164            ),
1165        ));
1166
1167        Ok(Body::Unstructured(builder.build()))
1168    }
1169
1170    pub(crate) fn translate_vtable_instance_init(
1171        mut self,
1172        init_func_id: FunDeclId,
1173        item_meta: ItemMeta,
1174        impl_def: &hax::FullDef<'tcx>,
1175        impl_kind: TransImplSource,
1176    ) -> Result<FunDecl, Error> {
1177        let span = item_meta.span;
1178
1179        let (_, vtable_struct_ref) = self.get_vtable_instance_info(span, impl_def, impl_kind)?;
1180
1181        let init_for = self.register_item(
1182            span,
1183            impl_def.this(),
1184            TransItemSourceKind::VTableInstance(impl_kind),
1185        );
1186        let src = FunSource::GlobalInitializer(GlobalDeclRef {
1187            id: init_for,
1188            generics: Box::new(self.outermost_generics().identity_args()),
1189        });
1190
1191        // Signature: `() -> VTable`.
1192        let sig = FunSig {
1193            is_unsafe: false,
1194            abi: Abi::rust(),
1195            is_variadic: false,
1196            inputs: vec![],
1197            output: Ty::new(TyKind::Adt(vtable_struct_ref.clone())),
1198        };
1199
1200        let body = match impl_kind {
1201            _ if item_meta.opacity.with_private_contents().is_opaque() => Body::Opaque,
1202            TransImplSource::Marker | TransImplSource::Normal | TransImplSource::Callable(..) => {
1203                self.gen_vtable_instance_init_body(span, impl_def, vtable_struct_ref, impl_kind)?
1204            }
1205            _ => {
1206                raise_error!(
1207                    self,
1208                    span,
1209                    "Don't know how to generate a vtable for a virtual impl {impl_kind:?}"
1210                );
1211            }
1212        };
1213
1214        Ok(FunDecl {
1215            def_id: init_func_id,
1216            item_meta,
1217            generics: self.into_generics(),
1218            signature: Box::new(sig),
1219            src,
1220            body,
1221        })
1222    }
1223
1224    /// The target vtable shim body looks like:
1225    /// ```ignore
1226    /// local ret@0 : ReturnTy;
1227    /// // the shim receiver of this shim function
1228    /// local shim_self@1 : ShimReceiverTy;
1229    /// // the arguments of the impl function
1230    /// local arg1@2 : Arg1Ty;
1231    /// ...
1232    /// local argN@N : ArgNTy;
1233    /// // the target receiver of the impl function
1234    /// local target_self@(N+1) : TargetReceiverTy;
1235    /// // perform some conversion to cast / re-box the shim receiver to the target receiver
1236    /// ...
1237    /// target_self@(N+1) := concretize_cast<ShimReceiverTy, TargetReceiverTy>(shim_self@1);
1238    /// // call the impl function and assign the result to ret@0
1239    /// ret@0 := impl_func(target_self@(N+1), arg1@2, ..., argN@N);
1240    /// ```
1241    ///
1242    /// For a method that takes `self: Self` by value, the shim receiver is `*mut dyn Trait`, so
1243    /// we concretize the pointer and move out of it:
1244    /// ```ignore
1245    /// target_self@(N+1) := concretize_cast<*mut dyn Trait, *mut TargetReceiverTy>(shim_self@1);
1246    /// ret@0 := impl_func(move (*target_self@(N+1)), arg1@2, ..., argN@N);
1247    /// ```
1248    fn translate_vtable_shim_body(
1249        &mut self,
1250        span: Span,
1251        target_receiver: &Ty,
1252        shim_signature: &FunSig,
1253        receiver_is_by_value: bool,
1254        target_fn: FnPtr,
1255    ) -> Result<Body, Error> {
1256        let mut builder = BodyBuilder::new(span, shim_signature.inputs.len());
1257
1258        let ret_place = builder.new_var(None, shim_signature.output.clone());
1259        let mut method_args = shim_signature
1260            .inputs
1261            .iter()
1262            .map(|ty| builder.new_var(None, ty.clone()))
1263            .collect_vec();
1264
1265        let cast_target_ty = if receiver_is_by_value {
1266            TyKind::RawPtr(target_receiver.clone(), RefKind::Mut).into_ty()
1267        } else {
1268            target_receiver.clone()
1269        };
1270        let target_self = builder.new_var(None, cast_target_ty);
1271
1272        // Replace the `dyn Trait` receiver with the concrete one.
1273        let receiver_arg = if receiver_is_by_value {
1274            target_self.clone().deref()
1275        } else {
1276            target_self.clone()
1277        };
1278        let shim_self = mem::replace(&mut method_args[0], receiver_arg);
1279
1280        // Perform the core concretization cast.
1281        // FIXME: need to unpack & re-pack the structure for cases like `Rc`, `Arc`, `Pin` and
1282        // (when --raw-boxes is on) `Box`
1283        let rval = Rvalue::UnaryOp(
1284            UnOp::Cast(CastKind::Concretize(
1285                shim_self.ty().clone(),
1286                target_self.ty().clone(),
1287            )),
1288            Operand::Move(shim_self.clone()),
1289        );
1290        builder.push_statement(StatementKind::Assign(target_self.clone(), rval));
1291
1292        builder.call(Call {
1293            func: FnOperand::Regular(target_fn),
1294            args: method_args.into_iter().map(Operand::Move).collect(),
1295            dest: ret_place,
1296        });
1297
1298        Ok(Body::Unstructured(builder.build()))
1299    }
1300
1301    /// The target vtable drop_shim body looks like:
1302    /// ```ignore
1303    /// local ret@0 : ();
1304    /// // the shim receiver of this drop_shim function
1305    /// local shim_self@1 : ShimReceiverTy;
1306    /// // the target receiver of the drop_shim
1307    /// local target_self@2 : TargetReceiverTy;
1308    /// // perform some conversion to cast / re-box the drop_shim receiver to the target receiver
1309    /// target_self@2 := concretize_cast<ShimReceiverTy, TargetReceiverTy>(shim_self@1);
1310    /// Drop(*target_self@2);
1311    /// ```
1312    fn translate_vtable_drop_shim_body(
1313        &mut self,
1314        span: Span,
1315        shim_receiver: &Ty,
1316        target_receiver: &Ty,
1317        trait_pred: &TraitPredicate,
1318    ) -> Result<Body, Error> {
1319        let mut builder = BodyBuilder::new(span, 1);
1320
1321        builder.new_var(Some("ret".into()), Ty::mk_unit());
1322        let dyn_self = builder.new_var(Some("dyn_self".into()), shim_receiver.clone());
1323        let target_self = builder.new_var(Some("target_self".into()), target_receiver.clone());
1324
1325        // Perform the core concretization cast.
1326        let rval = Rvalue::UnaryOp(
1327            UnOp::Cast(CastKind::Concretize(
1328                dyn_self.ty().clone(),
1329                target_self.ty().clone(),
1330            )),
1331            Operand::Move(dyn_self.clone()),
1332        );
1333        builder.push_statement(StatementKind::Assign(target_self.clone(), rval));
1334
1335        let rustc_trait_args = trait_pred.trait_ref.rustc_args(self.hax_state_with_id());
1336        let rustc_self_ty = rustc_trait_args[0].as_type().unwrap();
1337        let fn_ptr = self.translate_drop_glue_method_call(span, rustc_self_ty)?;
1338
1339        // Drop(*target_self)
1340        let drop_arg = target_self.clone().deref();
1341        builder.insert_drop(drop_arg, fn_ptr);
1342
1343        Ok(Body::Unstructured(builder.build()))
1344    }
1345
1346    pub(crate) fn translate_vtable_drop_shim(
1347        mut self,
1348        fun_id: FunDeclId,
1349        item_meta: ItemMeta,
1350        impl_def: &hax::FullDef,
1351        impl_kind: TransImplSource,
1352    ) -> Result<FunDecl, Error> {
1353        let span = item_meta.span;
1354
1355        let (dyn_self, trait_pred) = match (impl_kind, impl_def.kind()) {
1356            // The def is the closure or fn item; the impl is one of its virtual `Fn*` impls.
1357            (TransImplSource::Callable(target_kind), _) => {
1358                let vimpl = callable_virtual_impl(impl_def, target_kind);
1359                (vimpl.dyn_self.clone(), &vimpl.trait_pred)
1360            }
1361            (
1362                TransImplSource::Normal,
1363                hax::FullDefKind::TraitImpl {
1364                    dyn_self,
1365                    trait_pred,
1366                    ..
1367                },
1368            ) => (dyn_self.clone(), trait_pred),
1369            (
1370                TransImplSource::Marker,
1371                hax::FullDefKind::Trait {
1372                    dyn_self,
1373                    self_predicate,
1374                    ..
1375                },
1376            ) => (dyn_self.clone(), self_predicate),
1377            _ => unreachable!(),
1378        };
1379        let Some(dyn_self) = dyn_self else {
1380            raise_error!(
1381                self,
1382                span,
1383                "Trying to generate a vtable drop shim for a non-dyn-compatible trait"
1384            );
1385        };
1386
1387        let borrow_region = self.drop_glue_region();
1388
1389        let dyn_self = self.translate_ty(span, &dyn_self)?;
1390        // `&mut dyn Trait -> ()`
1391        let signature = self.drop_glue_method_sig(dyn_self.clone(), borrow_region);
1392
1393        // `&mut T` for `impl Trait for T`
1394        let target_self_ref = {
1395            let impl_trait = self.translate_trait_ref(span, &trait_pred.trait_ref)?;
1396            TyKind::Ref(
1397                borrow_region,
1398                impl_trait.generics.types[0].clone(),
1399                RefKind::Mut,
1400            )
1401            .into_ty()
1402        };
1403
1404        let body: Body = self.translate_vtable_drop_shim_body(
1405            span,
1406            &signature.inputs[0],
1407            &target_self_ref,
1408            trait_pred,
1409        )?;
1410
1411        Ok(FunDecl {
1412            def_id: fun_id,
1413            item_meta,
1414            generics: self.into_generics(),
1415            signature: Box::new(signature),
1416            src: FunSource::VTableShim,
1417            body,
1418        })
1419    }
1420
1421    pub(crate) fn translate_vtable_shim(
1422        mut self,
1423        fun_id: FunDeclId,
1424        item_meta: ItemMeta,
1425        def: &hax::FullDef<'tcx>,
1426        impl_kind: TransImplSource,
1427    ) -> Result<FunDecl, Error> {
1428        let span = item_meta.span;
1429
1430        let signature: FunSig;
1431        // the concrete receiver we will cast to
1432        let target_receiver: Ty;
1433        let receiver_is_by_value: bool;
1434        // the item that implements the method.
1435        let target_item: TransItemSourceKind;
1436
1437        if let TransImplSource::Callable(target_kind) = impl_kind {
1438            let vimpl = callable_virtual_impl(def, target_kind);
1439            let vtable_sig = &vimpl.methods[0]
1440                .1
1441                .as_ref()
1442                .expect("a callable with a vtable must be dyn-compatible");
1443            // Its only late-bound region is the one of the `call`/`call_mut` method, for which
1444            // we have a dedicated parameter.
1445            signature = {
1446                let bound_sig = self.translate_region_binder(span, vtable_sig, |ctx, sig| {
1447                    ctx.translate_fun_sig(span, sig)
1448                })?;
1449                bound_sig.apply(
1450                    self.the_only_binder()
1451                        .closure_call_method_region
1452                        .iter()
1453                        .map(|r| Region::Var(DeBruijnVar::new_at_zero(*r)))
1454                        .collect(),
1455                )
1456            };
1457            // The receiver is `&closure`, `&mut closure` or `closure` depending on the trait.
1458            target_receiver = {
1459                let hax::GenericArg::Type(self_ty) = &vimpl.trait_pred.trait_ref.generic_args[0]
1460                else {
1461                    unreachable!("no `Self` type arg on a `Fn*` trait ref")
1462                };
1463                let state_ty = self.translate_ty(span, self_ty)?;
1464                match target_kind {
1465                    ClosureKind::FnOnce => state_ty,
1466                    ClosureKind::Fn | ClosureKind::FnMut => {
1467                        let rid = self.the_only_binder().closure_call_method_region.unwrap();
1468                        let region = Region::Var(DeBruijnVar::new_at_zero(rid));
1469                        let mutability = RefKind::mutable(target_kind == ClosureKind::FnMut);
1470                        TyKind::Ref(region, state_ty, mutability).into_ty()
1471                    }
1472                }
1473            };
1474            receiver_is_by_value = target_kind == ClosureKind::FnOnce;
1475            target_item = TransItemSourceKind::CallableMethod(target_kind);
1476        } else {
1477            let hax::FullDefKind::AssocFn {
1478                vtable_sig: Some(vtable_sig),
1479                sig: target_signature,
1480                associated_item,
1481                ..
1482            } = def.kind()
1483            else {
1484                raise_error!(
1485                    self,
1486                    span,
1487                    "Trying to generate a vtable shim for a non-vtable-safe method"
1488                );
1489            };
1490            signature = self.translate_fun_sig(span, &vtable_sig.value)?;
1491            target_receiver = self.translate_ty(span, &target_signature.value.inputs[0])?;
1492            receiver_is_by_value = hax::vtable_receiver_is_by_value(
1493                self.tcx,
1494                associated_item
1495                    .implemented_trait_item_id()
1496                    .real_rust_def_id(),
1497            );
1498            target_item = TransItemSourceKind::Fun;
1499        };
1500
1501        trace!(
1502            "[VtableShim] Obtained dyn signature with receiver type: {}",
1503            signature.inputs[0].with_ctx(&self.into_fmt())
1504        );
1505
1506        let body = if item_meta.opacity.with_private_contents().is_opaque() {
1507            Body::Opaque
1508        } else {
1509            let fun_id = self.register_item(span, def.this(), target_item);
1510            let target_fn = FnPtr::new(
1511                FnPtrKind::Fun(fun_id),
1512                self.outermost_binder().params.identity_args(),
1513            );
1514            self.translate_vtable_shim_body(
1515                span,
1516                &target_receiver,
1517                &signature,
1518                receiver_is_by_value,
1519                target_fn,
1520            )?
1521        };
1522
1523        Ok(FunDecl {
1524            def_id: fun_id,
1525            item_meta,
1526            generics: self.into_generics(),
1527            signature: Box::new(signature),
1528            src: FunSource::VTableShim,
1529            body,
1530        })
1531    }
1532}