1use crate::hax::{self, UnderOwnerState};
45use itertools::Itertools;
46use std::mem;
47
48use super::translate_crate::TransItemSourceKind;
49use super::translate_ctx::*;
50use charon_lib::ullbc_ast::*;
51
52pub fn translate_closure_kind(kind: &hax::ClosureKind) -> ClosureKind {
53 match kind {
54 hax::ClosureKind::Fn => ClosureKind::Fn,
55 hax::ClosureKind::FnMut => ClosureKind::FnMut,
56 hax::ClosureKind::FnOnce => ClosureKind::FnOnce,
57 }
58}
59
60pub fn recognize_fn_trait_impl_proof<'a, 'tcx>(
63 trait_proof: &'a hax::TraitProof<'tcx>,
64) -> Option<(hax::Binder<&'a hax::Ty<'tcx>>, ClosureKind)> {
65 let hax::TraitProofKind::Builtin {
66 trait_data: hax::BuiltinTraitData::Other(lang_item),
67 ..
68 } = &trait_proof.kind
69 else {
70 return None;
71 };
72 let kind = match lang_item {
73 hax::SolverTraitLangItem::FnOnce => ClosureKind::FnOnce,
74 hax::SolverTraitLangItem::FnMut => ClosureKind::FnMut,
75 hax::SolverTraitLangItem::Fn => ClosureKind::Fn,
76 _ => return None,
77 };
78 let Some(hax::GenericArg::Type(self_ty)) =
79 trait_proof.pred.hax_skip_binder_ref().generic_args.first()
80 else {
81 unreachable!("no `Self` type arg on a `Fn*` trait ref")
82 };
83 Some((trait_proof.pred.rebind(self_ty), kind))
84}
85
86pub fn callable_virtual_impl<'a, 'tcx>(
88 s: &impl hax::BaseState<'tcx>,
89 def: &'a hax::FullDef<'tcx>,
90 target_kind: ClosureKind,
91) -> &'a hax::VirtualTraitImpl<'tcx> {
92 CallableFnImpls::from_def(s, def, target_kind)
93 .and_then(|impls| impls.vimpl)
94 .expect("expected a callable with a Fn* impl")
95}
96
97#[derive(Copy, Clone)]
98enum CallableKind {
99 Closure(ClosureKind),
100 FnDef,
101 FnPtr,
102}
103
104#[derive(Copy, Clone)]
105struct Callable<'tcx, 'a> {
106 kind: CallableKind,
107 item: &'a hax::ItemRef<'tcx>,
108 sig: &'a hax::PolyFnSig<'tcx>,
109}
110
111impl<'tcx, 'a> Callable<'tcx, 'a> {
112 fn for_closure(
113 s: &impl hax::BaseState<'tcx>,
114 closure: &'a hax::ClosureTy<'tcx>,
115 sig: &'a hax::PolyFnSig<'tcx>,
116 ) -> Self {
117 Self {
118 item: &closure.item,
119 kind: CallableKind::Closure(translate_closure_kind(&closure.kind(s))),
120 sig,
121 }
122 }
123
124 fn for_closure_def(def: &'a hax::FullDef<'tcx>) -> Self {
125 let hax::FullDefKind::Closure(closure) = def.kind() else {
126 unreachable!()
127 };
128 Self {
129 item: def.this(),
130 kind: CallableKind::Closure(translate_closure_kind(closure.kind())),
131 sig: closure.sig(),
132 }
133 }
134
135 fn kind(self) -> CallableKind {
136 self.kind
137 }
138
139 fn item(self) -> &'a hax::ItemRef<'tcx> {
140 self.item
141 }
142
143 fn sig(self) -> &'a hax::PolyFnSig<'tcx> {
144 self.sig
145 }
146}
147
148#[derive(Copy, Clone)]
149struct CallableFnImpls<'a, 'tcx> {
150 callable: Callable<'tcx, 'a>,
151 vimpl: Option<&'a hax::VirtualTraitImpl<'tcx>>,
153}
154
155impl<'a, 'tcx> CallableFnImpls<'a, 'tcx> {
156 fn from_def(
157 s: &impl hax::BaseState<'tcx>,
158 def: &'a hax::FullDef<'tcx>,
159 target_kind: ClosureKind,
160 ) -> Option<Self> {
161 let vimpl_from_impls = |impls: &'a hax::FnTraitImpls<'tcx>| -> Option<_> {
162 match target_kind {
163 ClosureKind::FnOnce => Some(impls.fn_once_impl.as_ref()),
164 ClosureKind::FnMut => impls.fn_mut_impl.as_deref(),
165 ClosureKind::Fn => impls.fn_impl.as_deref(),
166 }
167 };
168 let for_fn_def = |sig: &'a hax::PolyFnSig<'tcx>, impls: &'a hax::FnTraitImpls<'tcx>| {
169 Some(Self {
170 callable: Callable {
171 kind: CallableKind::FnDef,
172 item: def.this(),
173 sig,
174 },
175 vimpl: vimpl_from_impls(impls),
176 })
177 };
178 match def.kind() {
179 hax::FullDefKind::Closure(c) => Some(Self {
180 callable: Callable::for_closure_def(def),
181 vimpl: vimpl_from_impls(c.fn_trait_impls(s)),
182 }),
183 hax::FullDefKind::Fn(f) => for_fn_def(f.sig(), f.fn_trait_impls(s)?),
184 hax::FullDefKind::AssocFn(f) => for_fn_def(f.sig(), f.fn_trait_impls(s)?),
185 hax::FullDefKind::Ctor(f) => for_fn_def(f.sig(), f.fn_trait_impls(s)?),
186 hax::FullDefKind::FnPtr(f) => {
187 let impls = f.fn_trait_impls(s)?;
188 let sig = f.sig();
189 Some(Self {
190 callable: Callable {
191 kind: CallableKind::FnPtr,
192 item: def.this(),
193 sig,
194 },
195 vimpl: vimpl_from_impls(impls),
196 })
197 }
198 _ => None,
199 }
200 }
201}
202
203impl<'tcx> ItemTransCtx<'tcx, '_> {
208 fn translate_callable_bound_ref_with_late_bound(
211 &mut self,
212 span: Span,
213 callable: Callable<'tcx, '_>,
214 kind: TransItemSourceKind,
215 ) -> Result<RegionBinder<DeclRef<ItemId>>, Error> {
216 if !matches!(
217 kind,
218 TransItemSourceKind::TraitImpl(..) | TransItemSourceKind::ClosureAsFnCast
219 ) {
220 raise_error!(
221 self,
222 span,
223 "Called `translate_callable_bound_ref_with_late_bound` on a `{kind:?}`; \
224 use `translate_closure_ref_with_upvars` \
225 or `translate_callable_bound_ref_with_method_bound` instead"
226 )
227 }
228 let dref: DeclRef<ItemId> = self.translate_item(span, callable.item(), kind)?;
229 self.translate_region_binder(span, callable.sig(), |ctx, _| {
230 let mut dref = dref.move_under_binder();
231 for (a, b) in dref.generics.regions.iter_mut().rev().zip(
233 ctx.innermost_binder()
234 .params
235 .identity_args()
236 .regions
237 .into_iter()
238 .rev(),
239 ) {
240 *a = b;
241 }
242 Ok(dref)
243 })
244 }
245
246 fn translate_callable_bound_ref_with_method_bound(
250 &mut self,
251 span: Span,
252 item: &hax::ItemRef<'tcx>,
253 kind: TransItemSourceKind,
254 target_kind: ClosureKind,
255 ) -> Result<RegionBinder<DeclRef<ItemId>>, Error> {
256 if !matches!(kind, TransItemSourceKind::CallableMethod(..)) {
257 raise_error!(
258 self,
259 span,
260 "Called `translate_callable_bound_ref_with_method_bound` on a `{kind:?}`; \
261 use `translate_closure_ref_with_upvars` \
262 or `translate_callable_bound_ref_with_late_bound` instead"
263 )
264 }
265 let dref: DeclRef<ItemId> = self.translate_item(span, item, kind)?;
266 let mut dref = dref.move_under_binder();
267 let mut regions = IndexVec::new();
268 match target_kind {
269 ClosureKind::FnOnce => {}
270 ClosureKind::FnMut | ClosureKind::Fn => {
271 let rid =
272 regions.push_with(|index| RegionParam::new(index, None, Variance::Covariant));
273 *dref.generics.regions.iter_mut().last().unwrap() =
274 Region::Var(DeBruijnVar::new_at_zero(rid));
275 }
276 }
277 Ok(RegionBinder {
278 regions,
279 outlives: Vec::new(),
280 skip_binder: dref,
281 })
282 }
283
284 pub fn recognize_callable_impl_proof(
288 &self,
289 trait_proof: &hax::TraitProof<'tcx>,
290 ) -> Option<(hax::ItemRef<'tcx>, ClosureKind)> {
291 let hax::TraitProofKind::Builtin {
292 trait_data: hax::BuiltinTraitData::Other(lang_item),
293 ..
294 } = &trait_proof.kind
295 else {
296 return None;
297 };
298 let target_kind = match lang_item {
299 hax::SolverTraitLangItem::FnOnce => ClosureKind::FnOnce,
300 hax::SolverTraitLangItem::FnMut => ClosureKind::FnMut,
301 hax::SolverTraitLangItem::Fn => ClosureKind::Fn,
302 _ => return None,
303 };
304 let hax::GenericArg::Type(callable_ty) = trait_proof
306 .pred
307 .hax_skip_binder_ref()
308 .generic_args
309 .first()?
310 else {
311 return None;
312 };
313 let item = callable_ty.callable_item()?;
314 Some((item.erase(self.hax_state_with_id()), target_kind))
315 }
316
317 pub(crate) fn translate_callable_method_fn_ptr(
318 &mut self,
319 span: Span,
320 item: &hax::ItemRef<'tcx>,
321 ) -> Result<Option<RegionBinder<FnPtr>>, Error> {
322 if !self.monomorphize() {
323 return Ok(None);
324 }
325 let Some(in_trait) = &item.in_trait else {
326 return Ok(None);
327 };
328 let Some((callable, target_kind)) = self.recognize_callable_impl_proof(in_trait) else {
329 return Ok(None);
330 };
331 let kind = TransItemSourceKind::CallableMethod(target_kind);
332 let bound_ref = self.translate_callable_bound_ref_with_method_bound(
333 span,
334 &callable,
335 kind,
336 target_kind,
337 )?;
338 Ok(Some(bound_ref.map(|dref| {
339 let fn_ref: FunDeclRef = dref.try_into().unwrap();
340 FnPtr::new(FnPtrKind::Fun(fn_ref.id), fn_ref.generics)
341 })))
342 }
343}
344
345impl<'tcx> ItemTransCtx<'tcx, '_> {
346 pub fn translate_closure_type_ref(
348 &mut self,
349 span: Span,
350 closure: &hax::ItemRef<'tcx>,
351 ) -> Result<TypeDeclRef, Error> {
352 self.translate_type_decl_ref(span, closure)
353 }
354
355 pub fn translate_stateless_closure_as_fn_ref(
359 &mut self,
360 span: Span,
361 closure: &hax::ClosureTy<'tcx>,
362 ) -> Result<RegionBinder<FunDeclRef>, Error> {
363 let kind = TransItemSourceKind::ClosureAsFnCast;
364 let sig = closure.fn_sig(self.hax_state());
365 let callable = Callable::for_closure(self.hax_state(), closure, &sig);
366 let bound_dref = self.translate_callable_bound_ref_with_late_bound(span, callable, kind)?;
367 Ok(bound_dref.map(|dref| dref.try_into().unwrap()))
368 }
369
370 pub fn translate_closure_bound_impl_ref(
374 &mut self,
375 span: Span,
376 def: &hax::FullDef<'tcx>,
377 target_kind: ClosureKind,
378 ) -> Result<RegionBinder<TraitImplRef>, Error> {
379 let kind = TransItemSourceKind::TraitImpl(TransImplSource::Callable(target_kind));
380 let bound_dref = self.translate_callable_bound_ref_with_late_bound(
381 span,
382 Callable::for_closure_def(def),
383 kind,
384 )?;
385 Ok(bound_dref.map(|dref| dref.try_into().unwrap()))
386 }
387
388 pub fn translate_callable_impl_ref(
390 &mut self,
391 span: Span,
392 item: &hax::ItemRef<'tcx>,
393 target_kind: ClosureKind,
394 ) -> Result<TraitImplRef, Error> {
395 self.translate_item(
396 span,
397 item,
398 TransItemSourceKind::TraitImpl(TransImplSource::Callable(target_kind)),
399 )
400 }
401
402 pub fn translate_closure_info(
403 &mut self,
404 span: Span,
405 def: &hax::FullDef<'tcx>,
406 ) -> Result<ClosureInfo, Error> {
407 use ClosureKind::*;
408 let hax::FullDefKind::Closure(closure) = def.kind() else {
409 unreachable!()
410 };
411 let kind = translate_closure_kind(closure.kind());
412
413 let closure_body =
414 self.translate_item(span, def.this(), TransItemSourceKind::CallableMethod(kind))?;
415
416 let fn_once_impl = self.translate_closure_bound_impl_ref(span, def, FnOnce)?;
417 let fn_mut_impl = if matches!(kind, FnMut | Fn) {
418 Some(self.translate_closure_bound_impl_ref(span, def, FnMut)?)
419 } else {
420 None
421 };
422 let fn_impl = if matches!(kind, Fn) {
423 Some(self.translate_closure_bound_impl_ref(span, def, Fn)?)
424 } else {
425 None
426 };
427 let signature = self.translate_poly_fun_sig(span, closure.sig())?;
428 Ok(ClosureInfo {
429 kind,
430 closure_body,
431 fn_once_impl,
432 fn_mut_impl,
433 fn_impl,
434 signature,
435 })
436 }
437
438 fn get_callable_state_ty(
439 &mut self,
440 span: Span,
441 callable: Callable<'tcx, '_>,
442 ) -> Result<Ty, Error> {
443 Ok(match callable.kind() {
444 CallableKind::Closure(..) => {
445 let tref = self.translate_closure_type_ref(span, callable.item())?;
446 TyKind::Adt(tref).into_ty()
447 }
448 CallableKind::FnDef => {
449 let fn_ref =
450 self.translate_bound_fn_ptr(span, callable.item(), TransItemSourceKind::Fun)?;
451 TyKind::FnDef(fn_ref).into_ty()
452 }
453 CallableKind::FnPtr => {
454 TyKind::FnPtr(self.translate_poly_fun_sig(span, callable.sig())?).into_ty()
455 }
456 })
457 }
458
459 pub fn translate_closure_adt(
460 &mut self,
461 span: Span,
462 closure: &hax::Closure<'tcx>,
463 ) -> Result<TypeDeclKind, Error> {
464 let fields = closure
465 .upvar_tys()
466 .iter()
467 .enumerate()
468 .map(|(field_id, ty)| -> Result<_, Error> {
469 Ok(Field {
470 span,
471 attr_info: AttrInfo::dummy_private(),
472 name: format!("_{field_id}"),
473 is_positional: true,
474 ty: self.translate_ty(span, ty)?,
475 })
476 })
477 .try_collect()?;
478 Ok(TypeDeclKind::Struct(fields))
479 }
480
481 fn translate_callable_method_body(
482 &mut self,
483 span: Span,
484 def: &hax::FullDef<'tcx>,
485 target_kind: ClosureKind,
486 callable: Callable<'tcx, '_>,
487 signature: &FunSig,
488 ) -> Result<Body, Error> {
489 match callable.kind() {
490 CallableKind::Closure(source_kind) => self.translate_closure_method_body(
491 span,
492 def,
493 source_kind,
494 target_kind,
495 callable.item(),
496 signature,
497 ),
498 CallableKind::FnDef => {
499 self.translate_fn_def_method_body(span, callable.item(), signature)
500 }
501 CallableKind::FnPtr => {
502 self.translate_fn_ptr_method_body(span, callable.item(), signature)
503 }
504 }
505 }
506
507 fn translate_closure_method_body(
508 &mut self,
509 span: Span,
510 def: &hax::FullDef<'tcx>,
511 source_kind: ClosureKind,
512 target_kind: ClosureKind,
513 closure: &hax::ItemRef<'tcx>,
514 signature: &FunSig,
515 ) -> Result<Body, Error> {
516 use ClosureKind::*;
517 Ok(match (target_kind, source_kind) {
518 (Fn, Fn) | (FnMut, FnMut) | (FnOnce, FnOnce) => {
519 let mut body = self.translate_def_body(span, def);
521 let Body::Unstructured(inner_body) = &mut body else {
530 return Ok(body);
531 };
532
533 inner_body.dyn_visit_in_body_mut(|local: &mut LocalId| {
534 if local.index() >= 2 {
535 *local += 1;
536 }
537 });
538
539 let GExprBody {
540 locals,
541 body: blocks,
542 ..
543 } = inner_body;
544
545 let tupled_ty = &signature.inputs[1];
547
548 let closure_arg_count = locals.arg_count - 1;
550 let mut old_locals = mem::take(&mut locals.locals).into_iter();
551 locals.arg_count = 2;
552 locals.locals.push(old_locals.next().unwrap()); locals.locals.push(old_locals.next().unwrap()); let tupled_arg = locals.new_var(Some("tupled_args".to_string()), tupled_ty.clone());
555 locals.locals.extend(old_locals);
556
557 let untupled_args = locals
558 .locals
559 .iter()
560 .skip(3)
561 .take(closure_arg_count)
562 .map(|l| &l.ty)
563 .cloned();
564 let new_stts = untupled_args.enumerate().map(|(i, ty)| {
565 let nth_field = tupled_arg
566 .clone()
567 .project(ProjectionElem::Field(None, FieldId::new(i)), ty);
568 let local_id = LocalId::new(i + 3);
569 Statement::new(
570 span,
571 StatementKind::Assign(
572 locals.place_for_var(local_id),
573 Rvalue::Use(Operand::Move(nth_field), WithRetag::No),
574 ),
575 )
576 });
577 blocks[BlockId::ZERO].statements.splice(0..0, new_stts);
578
579 body
580 }
581 (FnOnce, Fn | FnMut) => {
591 let Some(body) = def.this.closure_once_shim(self.hax_state()) else {
593 panic!("missing shim for closure")
594 };
595 let mut body = self.translate_body(span, body, &def.source_text);
596 if let Some(body) = body.as_unstructured_mut() {
597 body.locals.locals[LocalId::new(1)].mutable = true;
599 }
600 body
601 }
602 (FnMut, Fn) => {
609 let fun_id: FunDeclId = self.register_item(
610 span,
611 def.this(),
612 TransItemSourceKind::CallableMethod(source_kind),
613 );
614 let impl_ref = self.translate_callable_impl_ref(span, closure, source_kind)?;
615 let fn_op = FnOperand::Regular(FnPtr::new(
618 fun_id.into(),
619 impl_ref.generics.concat(&GenericArgs {
620 regions: vec![self.translate_erased_region()].into(),
621 ..GenericArgs::empty()
622 }),
623 ));
624
625 let mut builder = BodyBuilder::new(span, 2);
626
627 let output = builder.new_var(None, signature.output.clone());
628 let state = builder.new_var(Some("state".to_string()), signature.inputs[0].clone());
629 let args = builder.new_var(Some("args".to_string()), signature.inputs[1].clone());
630 let deref_state = state.deref();
631 let reborrow_ty = TyKind::Ref(
632 self.translate_erased_region(),
633 deref_state.ty.clone(),
634 RefKind::Shared,
635 )
636 .into_ty();
637 let reborrow = builder.new_var(None, reborrow_ty);
638
639 builder.push_statement(StatementKind::Assign(
640 reborrow.clone(),
641 Rvalue::Ref {
642 place: deref_state,
643 kind: BorrowKind::Shared,
644 ptr_metadata: Operand::mk_const_unit(),
646 },
647 ));
648
649 builder.call(
650 output,
651 Call {
652 func: fn_op,
653 args: vec![Operand::Move(reborrow), Operand::Move(args)],
654 safety: CallSafety::Inherit,
655 },
656 );
657
658 Body::Unstructured(builder.build())
659 }
660 (Fn, FnOnce) | (Fn, FnMut) | (FnMut, FnOnce) => {
661 panic!(
662 "Can't make a closure body for a more restrictive kind \
663 than the closure kind"
664 )
665 }
666 })
667 }
668
669 fn translate_fn_def_method_body(
670 &mut self,
671 span: Span,
672 item: &hax::ItemRef<'tcx>,
673 signature: &FunSig,
674 ) -> Result<Body, Error> {
675 let late_bound_regions: RegionArgs = self
676 .innermost_binder()
677 .bound_region_vars
678 .iter()
679 .map(|rid| Region::Var(DeBruijnVar::new_at_zero(*rid)))
680 .collect();
681 let fn_ptr = self
682 .translate_bound_fn_ptr(span, item, TransItemSourceKind::Fun)?
683 .apply(late_bound_regions);
684 let fn_op = FnOperand::Regular(fn_ptr);
685
686 let mut builder = BodyBuilder::new(span, 2);
687
688 let output = builder.new_var(None, signature.output.clone());
689 let _state = builder.new_var(Some("state".to_string()), signature.inputs[0].clone());
690 let tupled_args_ty = &signature.inputs[1];
691 let tupled_args = builder.new_var(Some("args".to_string()), tupled_args_ty.clone());
692
693 let tuple_id = tupled_args_ty.as_adt().unwrap().id;
696 let _ = self.get_or_translate(ItemId::Type(tuple_id))?;
697 let arg_tys = tupled_args_ty.as_tuple_fields(&self.t_ctx.translated);
698
699 let args = arg_tys
700 .into_iter()
701 .enumerate()
702 .map(|(i, ty)| {
703 let nth_field = tupled_args
704 .clone()
705 .project(ProjectionElem::Field(None, FieldId::new(i)), ty);
706 Operand::Move(nth_field)
707 })
708 .collect();
709
710 builder.call(
711 output,
712 Call {
713 func: fn_op,
714 args,
715 safety: CallSafety::Inherit,
716 },
717 );
718
719 Ok(Body::Unstructured(builder.build()))
720 }
721
722 fn translate_fn_ptr_method_body(
723 &mut self,
724 span: Span,
725 item: &hax::ItemRef<'tcx>,
726 signature: &FunSig,
727 ) -> Result<Body, Error> {
728 let ty = item
729 .def_id
730 .type_of(&self.hax_state)
731 .instantiate(self.tcx, item.rustc_args(&self.hax_state));
732 let ty = hax::normalize(self.tcx, self.hax_state.typing_env(), ty);
733 let copy_proof =
734 hax::solve_copy(&self.hax_state, ty).expect("function pointers are always Copy");
735 let copy_proof = self
736 .translate_trait_proof(span, ©_proof)?
737 .no_bound_vars();
738 let mut builder = BodyBuilder::new(span, 2);
739 let output = builder.new_var(None, signature.output.clone());
740 let fn_ptr = builder.new_var(Some("fn_ptr".to_string()), signature.inputs[0].clone());
741 let tupled_args_ty = &signature.inputs[1];
742 let tupled_args = builder.new_var(Some("args".to_string()), tupled_args_ty.clone());
743
744 let fn_ptr = if matches!(fn_ptr.ty().kind(), TyKind::FnPtr(..)) {
747 fn_ptr
748 } else {
749 fn_ptr.deref()
750 };
751 let fn_ptr = Operand::Copy(fn_ptr, copy_proof);
752 let TyKind::FnPtr(fn_sig) = fn_ptr.ty().kind() else {
753 unreachable!()
754 };
755 let late_bound_regions: RegionArgs = self
756 .innermost_binder()
757 .bound_region_vars
758 .iter()
759 .map(|rid| Region::Var(DeBruijnVar::new_at_zero(*rid)))
760 .collect();
761 let arg_tys = fn_sig.clone().apply(late_bound_regions.clone()).inputs;
762 let args = arg_tys
763 .into_iter()
764 .enumerate()
765 .map(|(i, ty)| {
766 let field = tupled_args
767 .clone()
768 .project(ProjectionElem::Field(None, FieldId::new(i)), ty);
769 Operand::Move(field)
770 })
771 .collect();
772 builder.call(
773 output,
774 Call {
775 func: FnOperand::Dynamic(fn_ptr, late_bound_regions),
776 args,
777 safety: CallSafety::Inherit,
778 },
779 );
780 Ok(Body::Unstructured(builder.build()))
781 }
782
783 #[tracing::instrument(skip(self, item_meta))]
786 pub fn translate_closure_method(
787 mut self,
788 def_id: FunDeclId,
789 item_meta: ItemMeta,
790 def: &hax::FullDef<'tcx>,
791 target_kind: ClosureKind,
792 ) -> Result<FunDecl, Error> {
793 let span = item_meta.span;
794 let callable_impls = CallableFnImpls::from_def(self.hax_state(), def, target_kind).unwrap();
795 let callable = callable_impls.callable;
796
797 let vimpl = callable_impls.vimpl.unwrap();
799 let implemented_trait = self.translate_trait_predicate(span, &vimpl.trait_pred)?;
800 let method = &vimpl.methods[0];
801 let method_id = self.translate_trait_method_id(implemented_trait.id, &method.def_id)?;
802
803 let impl_ref = self.translate_callable_impl_ref(span, callable.item(), target_kind)?;
804 let src = FunSource::TraitImpl {
805 impl_ref,
806 trait_ref: implemented_trait.clone(),
807 item_id: method_id,
808 reuses_default: false,
809 };
810
811 let bound_sig = self.translate_poly_fun_sig(span, &method.sig)?;
813 let signature = bound_sig.apply(
815 self.the_only_binder()
816 .closure_call_method_region
817 .iter()
818 .map(|r| Region::Var(DeBruijnVar::new_at_zero(*r)))
819 .collect(),
820 );
821
822 let body = if item_meta.opacity.with_private_contents().is_opaque() {
823 Body::Opaque
824 } else {
825 self.translate_callable_method_body(span, def, target_kind, callable, &signature)?
826 };
827
828 Ok(FunDecl {
829 def_id,
830 item_meta,
831 generics: self.into_generics(),
832 signature: Box::new(signature),
833 src,
834 body,
835 })
836 }
837
838 #[tracing::instrument(skip(self, item_meta))]
839 pub fn translate_closure_trait_impl(
840 mut self,
841 def_id: TraitImplId,
842 item_meta: ItemMeta,
843 def: &hax::FullDef<'tcx>,
844 target_kind: ClosureKind,
845 ) -> Result<TraitImpl, Error> {
846 let span = item_meta.span;
847 let callable_impls = CallableFnImpls::from_def(self.hax_state(), def, target_kind).unwrap();
848 let callable = callable_impls.callable;
849
850 let vimpl = callable_impls.vimpl.unwrap();
852 let mut timpl = self.translate_virtual_trait_impl(
853 def_id,
854 item_meta,
855 callable.item(),
856 TransImplSource::Callable(target_kind),
857 vimpl,
858 )?;
859
860 if self.monomorphize() {
861 return Ok(timpl);
862 }
863
864 let trait_decl_id = timpl.impl_trait.id;
866 let trait_method_id =
867 self.translate_trait_method_id(trait_decl_id, &vimpl.methods[0].def_id)?;
868 let call_fn_binder = {
869 let kind = TransItemSourceKind::CallableMethod(target_kind);
870 let bound_method_ref: RegionBinder<DeclRef<ItemId>> = self
871 .translate_callable_bound_ref_with_method_bound(
872 span,
873 callable.item(),
874 kind,
875 target_kind,
876 )?;
877 let params = GenericParams {
878 regions: bound_method_ref.regions,
879 ..GenericParams::empty()
880 };
881 let fn_decl_ref: FunDeclRef = bound_method_ref.skip_binder.try_into().unwrap();
882 Binder::new(
883 BinderKind::TraitMethod(trait_decl_id, trait_method_id),
884 params,
885 fn_decl_ref,
886 )
887 };
888 timpl
889 .methods
890 .set_slot_extend(trait_method_id, call_fn_binder);
891
892 Ok(timpl)
893 }
894
895 #[tracing::instrument(skip(self, item_meta))]
898 pub fn translate_stateless_closure_as_fn(
899 mut self,
900 def_id: FunDeclId,
901 item_meta: ItemMeta,
902 def: &hax::FullDef<'tcx>,
903 ) -> Result<FunDecl, Error> {
904 let span = item_meta.span;
905 let hax::FullDefKind::Closure(closure) = &def.kind else {
906 unreachable!()
907 };
908
909 trace!("About to translate closure as fn:\n{:?}", def.def_id());
910
911 assert!(
912 closure.upvar_tys().is_empty(),
913 "Only stateless closures can be translated as functions"
914 );
915 let signature = self.translate_fun_sig(span, closure.sig().hax_skip_binder_ref())?;
917 let state_ty = self.get_callable_state_ty(span, Callable::for_closure_def(def))?;
918
919 let body = if item_meta.opacity.with_private_contents().is_opaque() {
920 Body::Opaque
921 } else {
922 let fun_id: FunDeclId = self.register_item(
930 span,
931 def.this(),
932 TransItemSourceKind::CallableMethod(ClosureKind::FnOnce),
933 );
934 let impl_ref =
935 self.translate_callable_impl_ref(span, def.this(), ClosureKind::FnOnce)?;
936 let fn_op = FnOperand::Regular(FnPtr::new(fun_id.into(), impl_ref.generics.clone()));
937
938 let mut builder = BodyBuilder::new(span, signature.inputs.len());
939
940 let output = builder.new_var(None, signature.output.clone());
941 let args: Vec<Place> = signature
942 .inputs
943 .iter()
944 .enumerate()
945 .map(|(i, ty)| builder.new_var(Some(format!("arg{}", i + 1)), ty.clone()))
946 .collect();
947 let args_tupled_ty =
948 self.translate_ty(span, &closure.sig().hax_skip_binder_ref().tupled_inputs)?;
949 let args_tupled = builder.new_var(Some("args".to_string()), args_tupled_ty.clone());
950 let state = builder.new_var(Some("state".to_string()), state_ty.clone());
951
952 builder.push_statement(StatementKind::Assign(
953 args_tupled.clone(),
954 Rvalue::Aggregate(
955 AggregateKind::Adt(args_tupled_ty.as_adt().unwrap().clone(), None, None),
956 args.into_iter().map(Operand::Move).collect(),
957 ),
958 ));
959
960 let state_ty_adt = state_ty.as_adt().unwrap();
961 builder.push_statement(StatementKind::Assign(
962 state.clone(),
963 Rvalue::Aggregate(AggregateKind::Adt(state_ty_adt.clone(), None, None), vec![]),
964 ));
965
966 builder.call(
967 output,
968 Call {
969 func: fn_op,
970 args: vec![Operand::Move(state), Operand::Move(args_tupled)],
971 safety: CallSafety::Inherit,
972 },
973 );
974
975 Body::Unstructured(builder.build())
976 };
977
978 Ok(FunDecl {
979 def_id,
980 item_meta,
981 generics: self.into_generics(),
982 signature: Box::new(signature),
983 src: FunSource::Normal,
984 body,
985 })
986 }
987}