1use rustc_middle::ty;
2
3use super::translate_ctx::*;
4use crate::hax;
5use crate::hax::FullDefKind;
6use crate::translate::translate_crate::TransItemSourceKind;
7use charon_lib::{ast::*, formatter::IntoFormatter, pretty::FmtWithCtx};
8
9impl<'tcx> ItemTransCtx<'tcx, '_> {
10 pub fn translate_drop_in_place_method_id(
11 &mut self,
12 destruct_trait_def_id: &hax::DefId,
13 destruct_trait_id: TraitDeclId,
14 ) -> Result<TraitMethodId, Error> {
15 self.register_assoc_items(destruct_trait_def_id, destruct_trait_id)?;
16 let method_id = TraitMethodId::ZERO; Ok(method_id)
18 }
19
20 pub fn translate_drop_in_place_method_ref(
21 &mut self,
22 span: Span,
23 item_ref: &hax::ItemRef,
24 destruct_trait_def_id: &hax::DefId,
25 destruct_trait_id: TraitDeclId,
26 impl_kind: Option<TraitImplSource>,
27 ) -> Result<(FunDeclId, TraitMethodId), Error> {
28 let method_id =
29 self.translate_drop_in_place_method_id(destruct_trait_def_id, destruct_trait_id)?;
30 let fun_id = self.register_item(
31 span,
32 item_ref,
33 TransItemSourceKind::DropInPlaceMethod(impl_kind),
34 );
35 Ok((fun_id, method_id))
36 }
37
38 pub fn translate_drop_in_place_method_call(
40 &mut self,
41 span: Span,
42 ty: ty::Ty<'tcx>,
43 ) -> Result<FnPtr, Error> {
44 let impl_expr = hax::solve_destruct(self.hax_state_with_id(), ty);
45 let tref = self.translate_trait_impl_expr(span, &impl_expr)?;
46 let (fun_id, method_id) = self.translate_drop_in_place_method_ref(
47 span,
48 impl_expr.r#trait.hax_skip_binder_ref(),
49 &impl_expr.r#trait.hax_skip_binder_ref().def_id,
50 tref.trait_id(),
51 None,
52 )?;
53 let fn_ptr = FnPtr {
54 kind: Box::new(FnPtrKind::Trait(tref, method_id, fun_id)),
55 generics: Box::new(GenericArgs::empty()),
56 };
57 Ok(fn_ptr)
58 }
59
60 fn translate_drop_in_place_method_body(
61 &mut self,
62 span: Span,
63 def: &hax::FullDef<'tcx>,
64 self_ty: &Ty,
65 ) -> Result<Body, Error> {
66 let (hax::FullDefKind::Adt { .. } | hax::FullDefKind::Closure { .. }) = def.kind() else {
67 return Ok(Body::Missing);
68 };
69
70 let translate_glue = self.options.translate_poly_drop_glue
73 || self.monomorphize()
74 || def
75 .this
76 .def_id
77 .underlying_rust_def_id()
78 .is_none_or(|def_id| self.tcx.generics_of(def_id).is_empty());
79 if !translate_glue {
80 return Ok(Body::Missing);
81 }
82
83 let body = {
84 let ctx = std::panic::AssertUnwindSafe(&mut *self);
85 let def = std::panic::AssertUnwindSafe(def);
86 let Ok(body) =
88 std::panic::catch_unwind(move || def.this().drop_glue_shim(ctx.hax_state()))
89 else {
90 let self_ty_name = if let TyKind::Adt(TypeDeclRef {
91 id: TypeId::Adt(type_id),
92 ..
93 }) = self_ty.kind()
94 && let Some(name) = self.translated.item_name(*type_id)
95 {
96 name.to_string_with_ctx(&self.into_fmt())
97 } else {
98 "crate::the::Type".to_string()
99 };
100 raise_error!(
101 self,
102 span,
103 "rustc panicked while retrieving drop glue. \
104 This is known to happen with `--precise-drops`; to silence this warning, \
105 pass `--opaque '{{impl core::marker::Destruct for {}}}'` to charon",
106 self_ty_name
107 )
108 };
109 body
110 };
111
112 Ok(self.translate_body(span, body, &def.source_text))
113 }
114
115 #[tracing::instrument(skip(self, item_meta, def))]
118 pub fn translate_drop_in_place_method(
119 mut self,
120 def_id: FunDeclId,
121 item_meta: ItemMeta,
122 def: &hax::FullDef<'tcx>,
123 impl_kind: Option<TraitImplSource>,
124 ) -> Result<FunDecl, Error> {
125 let span = item_meta.span;
126
127 let trait_pred = match def.kind() {
128 FullDefKind::Adt { destruct_impl, .. } | FullDefKind::Closure { destruct_impl, .. } => {
130 assert_eq!(impl_kind, Some(TraitImplSource::ImplicitDestruct));
131 &destruct_impl.trait_pred
132 }
133 FullDefKind::Trait { self_predicate, .. } => {
135 assert_eq!(impl_kind, None);
136 self_predicate
137 }
138 _ => unreachable!(),
139 };
140
141 let implemented_trait = self.translate_trait_predicate(span, trait_pred)?;
142 let item_id: AssocItemId = self
143 .translate_drop_in_place_method_id(&trait_pred.trait_ref.def_id, implemented_trait.id)?
144 .into();
145 let self_ty = implemented_trait
146 .self_ty(&self.t_ctx.translated)
147 .unwrap()
148 .clone();
149
150 let signature = self.drop_in_place_method_sig(self_ty.clone());
151 let src = match impl_kind {
152 Some(impl_kind) => {
153 let destruct_impl_id =
154 self.register_item(span, def.this(), TransItemSourceKind::TraitImpl(impl_kind));
155 let impl_ref = TraitImplRef {
156 id: destruct_impl_id,
157 generics: Box::new(self.the_only_binder().params.identity_args()),
158 };
159 ItemSource::TraitImpl {
160 impl_ref,
161 trait_ref: implemented_trait,
162 item_id,
163 reuses_default: false,
164 }
165 }
166 None => ItemSource::TraitDecl {
167 trait_ref: implemented_trait,
168 item_id,
169 has_default: false,
170 },
171 };
172
173 let body = if item_meta.opacity.with_private_contents().is_opaque() {
174 Body::Opaque
175 } else {
176 self.translate_drop_in_place_method_body(span, def, &self_ty)?
177 };
178
179 Ok(FunDecl {
180 def_id,
181 item_meta,
182 generics: self.into_generics(),
183 signature,
184 src,
185 is_global_initializer: None,
186 body,
187 })
188 }
189
190 pub fn drop_in_place_method_sig(&self, self_ty: Ty) -> FunSig {
192 let self_ptr = TyKind::RawPtr(self_ty, RefKind::Mut).into_ty();
193 FunSig {
194 is_unsafe: true,
195 inputs: [self_ptr].into(),
196 output: Ty::mk_unit(),
197 }
198 }
199
200 pub fn prepare_drop_in_place_method(
202 &mut self,
203 def: &hax::FullDef<'tcx>,
204 span: Span,
205 destruct_trait_def_id: &hax::DefId,
206 destruct_trait_id: TraitDeclId,
207 impl_kind: Option<TraitImplSource>,
208 ) -> Result<(TraitMethodId, Binder<FunDeclRef>), Error> {
209 let (fun_id, method_id) = self.translate_drop_in_place_method_ref(
210 span,
211 def.this(),
212 destruct_trait_def_id,
213 destruct_trait_id,
214 impl_kind,
215 )?;
216 let method_binder = {
217 let generics = self
218 .outermost_binder()
219 .params
220 .identity_args_at_depth(DeBruijnId::one());
221 Binder::new(
222 BinderKind::TraitMethod(destruct_trait_id, method_id),
223 GenericParams::empty(),
224 FunDeclRef {
225 id: fun_id,
226 generics: Box::new(generics),
227 },
228 )
229 };
230 Ok((method_id, method_binder))
231 }
232
233 #[tracing::instrument(skip(self, item_meta, def))]
234 pub fn translate_implicit_destruct_impl(
235 mut self,
236 impl_id: TraitImplId,
237 item_meta: ItemMeta,
238 def: &hax::FullDef<'tcx>,
239 ) -> Result<TraitImpl, Error> {
240 let span = item_meta.span;
241
242 let (FullDefKind::Adt { destruct_impl, .. } | FullDefKind::Closure { destruct_impl, .. }) =
243 def.kind()
244 else {
245 unreachable!("{:?}", def.def_id())
246 };
247 let mut timpl = self.translate_virtual_trait_impl(impl_id, item_meta, destruct_impl)?;
248
249 let destruct_trait_id = timpl.impl_trait.id;
251 let (method_id, method_binder) = self.prepare_drop_in_place_method(
252 def,
253 span,
254 &destruct_impl.trait_pred.trait_ref.def_id,
255 destruct_trait_id,
256 Some(TraitImplSource::ImplicitDestruct),
257 )?;
258 timpl.methods.set_slot_extend(method_id, method_binder);
259
260 Ok(timpl)
261 }
262}