1use std::mem;
42
43use crate::translate::translate_bodies::BodyTransCtx;
44
45use super::translate_crate::TransItemSourceKind;
46use super::translate_ctx::*;
47use charon_lib::ast::*;
48use charon_lib::ids::Vector;
49use charon_lib::ullbc_ast::*;
50use itertools::Itertools;
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
60impl ItemTransCtx<'_, '_> {
61 pub fn translate_closure_info(
62 &mut self,
63 span: Span,
64 args: &hax::ClosureArgs,
65 ) -> Result<ClosureInfo, Error> {
66 use ClosureKind::*;
67 let kind = translate_closure_kind(&args.kind);
68
69 let fn_once_impl = self.translate_closure_bound_impl_ref(span, args, FnOnce)?;
70 let fn_mut_impl = if matches!(kind, FnMut | Fn) {
71 Some(self.translate_closure_bound_impl_ref(span, args, FnMut)?)
72 } else {
73 None
74 };
75 let fn_impl = if matches!(kind, Fn) {
76 Some(self.translate_closure_bound_impl_ref(span, args, Fn)?)
77 } else {
78 None
79 };
80 let signature = self.translate_fun_sig(span, &args.fn_sig)?;
81 Ok(ClosureInfo {
82 kind,
83 fn_once_impl,
84 fn_mut_impl,
85 fn_impl,
86 signature,
87 })
88 }
89
90 pub fn translate_closure_bound_type_ref(
94 &mut self,
95 span: Span,
96 closure: &hax::ClosureArgs,
97 ) -> Result<RegionBinder<TypeDeclRef>, Error> {
98 let upvar_binder = hax::Binder {
100 value: (),
101 bound_vars: closure
102 .upvar_tys
103 .iter()
104 .filter(|ty| {
105 matches!(
106 ty.kind(),
107 hax::TyKind::Ref(
108 hax::Region {
109 kind: hax::RegionKind::ReErased
110 },
111 ..
112 )
113 )
114 })
115 .map(|_| hax::BoundVariableKind::Region(hax::BoundRegionKind::Anon))
116 .collect(),
117 };
118 let tref = self.translate_type_decl_ref(span, &closure.item)?;
119 self.translate_region_binder(span, &upvar_binder, |ctx, _| {
120 let mut tref = tref.move_under_binder();
121 tref.generics.regions.extend(
122 ctx.innermost_binder()
123 .params
124 .identity_args()
125 .regions
126 .into_iter(),
127 );
128 Ok(tref)
129 })
130 }
131
132 pub fn translate_closure_type_ref(
134 &mut self,
135 span: Span,
136 closure: &hax::ClosureArgs,
137 ) -> Result<TypeDeclRef, Error> {
138 let bound_tref = self.translate_closure_bound_type_ref(span, closure)?;
139 let tref = if self.item_src.def_id() == &closure.item.def_id {
140 bound_tref.apply(
142 self.outermost_binder()
143 .by_ref_upvar_regions
144 .iter()
145 .map(|r| Region::Var(DeBruijnVar::bound(self.binding_levels.depth(), *r)))
146 .collect(),
147 )
148 } else {
149 bound_tref.erase()
151 };
152 Ok(tref)
153 }
154
155 pub fn translate_stateless_closure_as_fn_ref(
158 &mut self,
159 span: Span,
160 closure: &hax::ClosureArgs,
161 ) -> Result<RegionBinder<FunDeclRef>, Error> {
162 let id = self.register_item(span, &closure.item, TransItemSourceKind::ClosureAsFnCast);
163 let TypeDeclRef { generics, .. } = self.translate_closure_type_ref(span, closure)?;
164 self.translate_region_binder(span, &closure.fn_sig, |ctx, _| {
165 let mut generics = generics.move_under_binder();
166 generics.regions.extend(
167 ctx.innermost_binder()
168 .params
169 .identity_args()
170 .regions
171 .into_iter(),
172 );
173 Ok(FunDeclRef { id, generics })
174 })
175 }
176
177 pub fn translate_closure_bound_impl_ref(
181 &mut self,
182 span: Span,
183 closure: &hax::ClosureArgs,
184 target_kind: ClosureKind,
185 ) -> Result<RegionBinder<TraitImplRef>, Error> {
186 let impl_id = self.register_item(
187 span,
188 &closure.item,
189 TransItemSourceKind::TraitImpl(TraitImplSource::Closure(target_kind)),
190 );
191 let adt_ref = self.translate_closure_type_ref(span, closure)?;
192 let impl_ref = TraitImplRef {
193 id: impl_id,
194 generics: adt_ref.generics,
195 };
196 self.translate_region_binder(span, &closure.fn_sig, |ctx, _| {
197 let mut impl_ref = impl_ref.move_under_binder();
198 impl_ref.generics.regions.extend(
199 ctx.innermost_binder()
200 .params
201 .identity_args()
202 .regions
203 .into_iter(),
204 );
205 Ok(impl_ref)
206 })
207 }
208
209 pub fn translate_closure_impl_ref(
211 &mut self,
212 span: Span,
213 closure: &hax::ClosureArgs,
214 target_kind: ClosureKind,
215 ) -> Result<TraitImplRef, Error> {
216 let bound_impl_ref = self.translate_closure_bound_impl_ref(span, closure, target_kind)?;
217 let impl_ref = if self.item_src.def_id() == &closure.item.def_id {
218 bound_impl_ref.apply(
220 self.outermost_binder()
221 .bound_region_vars
222 .iter()
223 .map(|r| Region::Var(DeBruijnVar::bound(self.binding_levels.depth(), *r)))
224 .collect(),
225 )
226 } else {
227 bound_impl_ref.erase()
228 };
229 Ok(impl_ref)
230 }
231
232 pub fn get_closure_state_ty(
233 &mut self,
234 span: Span,
235 args: &hax::ClosureArgs,
236 ) -> Result<Ty, Error> {
237 let tref = self.translate_closure_type_ref(span, args)?;
238 Ok(TyKind::Adt(tref).into_ty())
239 }
240
241 pub fn translate_closure_adt(
242 &mut self,
243 _trans_id: TypeDeclId,
244 span: Span,
245 args: &hax::ClosureArgs,
246 ) -> Result<TypeDeclKind, Error> {
247 let mut by_ref_upvar_regions = self
248 .the_only_binder()
249 .by_ref_upvar_regions
250 .clone()
251 .into_iter();
252 let fields: Vector<FieldId, Field> = args
253 .upvar_tys
254 .iter()
255 .map(|ty| -> Result<Field, Error> {
256 let mut ty = self.translate_ty(span, ty)?;
257 if let TyKind::Ref(Region::Erased, deref_ty, kind) = ty.kind() {
259 let region_id = by_ref_upvar_regions.next().unwrap();
260 ty = TyKind::Ref(
261 Region::Var(DeBruijnVar::new_at_zero(region_id)),
262 deref_ty.clone(),
263 *kind,
264 )
265 .into_ty();
266 }
267 Ok(Field {
268 span,
269 attr_info: AttrInfo {
270 attributes: vec![],
271 inline: None,
272 rename: None,
273 public: false,
274 },
275 name: None,
276 ty,
277 })
278 })
279 .try_collect()?;
280 Ok(TypeDeclKind::Struct(fields))
281 }
282
283 fn translate_closure_method_sig(
286 &mut self,
287 def: &hax::FullDef,
288 span: Span,
289 args: &hax::ClosureArgs,
290 target_kind: ClosureKind,
291 ) -> Result<FunSig, Error> {
292 let signature = &args.fn_sig;
293 trace!(
294 "signature of closure {:?}:\n{:?}",
295 def.def_id(),
296 signature.value,
297 );
298
299 let is_unsafe = match signature.value.safety {
300 hax::Safety::Unsafe => true,
301 hax::Safety::Safe => false,
302 };
303
304 let state_ty = self.get_closure_state_ty(span, args)?;
305
306 let state_ty = match target_kind {
308 ClosureKind::FnOnce => state_ty,
309 ClosureKind::Fn | ClosureKind::FnMut => {
310 let rid = self
311 .innermost_generics_mut()
312 .regions
313 .push_with(|index| RegionVar { index, name: None });
314 let r = Region::Var(DeBruijnVar::new_at_zero(rid));
315 let mutability = if target_kind == ClosureKind::Fn {
316 RefKind::Shared
317 } else {
318 RefKind::Mut
319 };
320 TyKind::Ref(r, state_ty, mutability).into_ty()
321 }
322 };
323
324 let input_tys: Vec<Ty> = signature
326 .value
327 .inputs
328 .iter()
329 .map(|ty| self.translate_ty(span, ty))
330 .try_collect()?;
331 let inputs = vec![state_ty, Ty::mk_tuple(input_tys)];
333 let output = self.translate_ty(span, &signature.value.output)?;
334
335 Ok(FunSig {
336 generics: self.the_only_binder().params.clone(),
337 is_unsafe,
338 inputs,
339 output,
340 })
341 }
342
343 fn translate_closure_method_body(
344 mut self,
345 span: Span,
346 def: &hax::FullDef,
347 target_kind: ClosureKind,
348 args: &hax::ClosureArgs,
349 signature: &FunSig,
350 ) -> Result<Result<Body, Opaque>, Error> {
351 use ClosureKind::*;
352 let closure_kind = translate_closure_kind(&args.kind);
353 let mk_stt = |content| Statement::new(span, content);
354 let mk_block = |statements, terminator| -> BlockData {
355 BlockData {
356 statements,
357 terminator: Terminator::new(span, terminator),
358 }
359 };
360
361 Ok(match (target_kind, closure_kind) {
362 (Fn, Fn) | (FnMut, FnMut) | (FnOnce, FnOnce) => {
363 let mut bt_ctx = BodyTransCtx::new(&mut self);
365 match bt_ctx.translate_def_body(span, def) {
366 Ok(Ok(mut body)) => {
367 let GExprBody {
376 locals,
377 body: blocks,
378 ..
379 } = body.as_unstructured_mut().unwrap();
380
381 blocks.dyn_visit_mut(|local: &mut LocalId| {
382 let idx = local.index();
383 if idx >= 2 {
384 *local = LocalId::new(idx + 1)
385 }
386 });
387
388 let mut old_locals = mem::take(&mut locals.locals).into_iter();
389 locals.arg_count = 2;
390 locals.locals.push(old_locals.next().unwrap()); locals.locals.push(old_locals.next().unwrap()); let tupled_arg = locals
393 .new_var(Some("tupled_args".to_string()), signature.inputs[1].clone());
394 locals.locals.extend(old_locals.map(|mut l| {
395 l.index += 1;
396 l
397 }));
398
399 let untupled_args = signature.inputs[1].as_tuple().unwrap();
400 let closure_arg_count = untupled_args.elem_count();
401 let new_stts = untupled_args.iter().cloned().enumerate().map(|(i, ty)| {
402 let nth_field = tupled_arg.clone().project(
403 ProjectionElem::Field(
404 FieldProjKind::Tuple(closure_arg_count),
405 FieldId::new(i),
406 ),
407 ty,
408 );
409 mk_stt(StatementKind::Assign(
410 locals.place_for_var(LocalId::new(i + 3)),
411 Rvalue::Use(Operand::Move(nth_field)),
412 ))
413 });
414 blocks[BlockId::ZERO].statements.splice(0..0, new_stts);
415
416 Ok(body)
417 }
418 Ok(Err(Opaque)) => Err(Opaque),
419 Err(_) => Err(Opaque),
420 }
421 }
422 (FnOnce, Fn | FnMut) => {
432 let hax::FullDefKind::Closure {
434 once_shim: Some(body),
435 ..
436 } = &def.kind
437 else {
438 panic!("missing shim for closure")
439 };
440 let mut bt_ctx = BodyTransCtx::new(&mut self);
441 match bt_ctx.translate_body(span, body, &def.source_text) {
442 Ok(Ok(body)) => Ok(body),
443 Ok(Err(Opaque)) => Err(Opaque),
444 Err(_) => Err(Opaque),
445 }
446 }
447 (FnMut, Fn) => {
454 let fun_id: FunDeclId = self.register_item(
455 span,
456 def.this(),
457 TransItemSourceKind::ClosureMethod(closure_kind),
458 );
459 let impl_ref = self.translate_closure_impl_ref(span, args, closure_kind)?;
460 let fn_op = FnOperand::Regular(FnPtr {
463 func: Box::new(fun_id.into()),
464 generics: Box::new(impl_ref.generics.concat(&GenericArgs {
465 regions: vec![Region::Erased].into(),
466 ..GenericArgs::empty()
467 })),
468 });
469
470 let mut locals = Locals {
471 arg_count: 2,
472 locals: Vector::new(),
473 };
474 let mut statements = vec![];
475 let mut blocks = Vector::default();
476
477 let output = locals.new_var(None, signature.output.clone());
478 let state = locals.new_var(Some("state".to_string()), signature.inputs[0].clone());
479 let args = locals.new_var(Some("args".to_string()), signature.inputs[1].clone());
480 let deref_state = state.deref();
481 let reborrow_ty =
482 TyKind::Ref(Region::Erased, deref_state.ty.clone(), RefKind::Shared).into_ty();
483 let reborrow = locals.new_var(None, reborrow_ty);
484
485 statements.push(mk_stt(StatementKind::Assign(
486 reborrow.clone(),
487 Rvalue::Ref(deref_state, BorrowKind::Shared),
488 )));
489
490 let start_block = blocks.reserve_slot();
491 let ret_block = blocks.push(mk_block(vec![], TerminatorKind::Return));
492 let unwind_block = blocks.push(mk_block(vec![], TerminatorKind::UnwindResume));
493 let call = TerminatorKind::Call {
494 target: ret_block,
495 call: Call {
496 func: fn_op,
497 args: vec![Operand::Move(reborrow), Operand::Move(args)],
498 dest: output,
499 },
500 on_unwind: unwind_block,
501 };
502 blocks.set_slot(start_block, mk_block(statements, call));
503
504 let body: ExprBody = GExprBody {
505 span,
506 locals,
507 comments: vec![],
508 body: blocks,
509 };
510 Ok(Body::Unstructured(body))
511 }
512 (Fn, FnOnce) | (Fn, FnMut) | (FnMut, FnOnce) => {
513 panic!(
514 "Can't make a closure body for a more restrictive kind \
515 than the closure kind"
516 )
517 }
518 })
519 }
520
521 #[tracing::instrument(skip(self, item_meta))]
524 pub fn translate_closure_method(
525 mut self,
526 def_id: FunDeclId,
527 item_meta: ItemMeta,
528 def: &hax::FullDef,
529 target_kind: ClosureKind,
530 ) -> Result<FunDecl, Error> {
531 let span = item_meta.span;
532 let hax::FullDefKind::Closure {
533 args,
534 fn_once_impl,
535 fn_mut_impl,
536 fn_impl,
537 ..
538 } = &def.kind
539 else {
540 unreachable!()
541 };
542
543 trace!("About to translate closure:\n{:?}", def.def_id());
544
545 self.translate_def_generics(span, def)?;
546 assert!(self.innermost_binder_mut().bound_region_vars.is_empty(),);
548 self.innermost_binder_mut()
549 .push_params_from_binder(args.fn_sig.rebind(()))?;
550
551 let vimpl = match target_kind {
553 ClosureKind::FnOnce => fn_once_impl,
554 ClosureKind::FnMut => fn_mut_impl.as_ref().unwrap(),
555 ClosureKind::Fn => fn_impl.as_ref().unwrap(),
556 };
557 let implemented_trait = self.translate_trait_predicate(span, &vimpl.trait_pred)?;
558
559 let impl_ref = self.translate_closure_impl_ref(span, args, target_kind)?;
560 let kind = ItemKind::TraitImpl {
561 impl_ref,
562 trait_ref: implemented_trait,
563 item_name: TraitItemName(target_kind.method_name().to_owned()),
564 reuses_default: false,
565 };
566
567 let signature = self.translate_closure_method_sig(def, span, args, target_kind)?;
569
570 let body = if item_meta.opacity.with_private_contents().is_opaque() {
571 Err(Opaque)
572 } else {
573 self.translate_closure_method_body(span, def, target_kind, args, &signature)?
574 };
575
576 Ok(FunDecl {
577 def_id,
578 item_meta,
579 signature,
580 kind,
581 is_global_initializer: None,
582 body,
583 })
584 }
585
586 #[tracing::instrument(skip(self, item_meta))]
587 pub fn translate_closure_trait_impl(
588 mut self,
589 def_id: TraitImplId,
590 item_meta: ItemMeta,
591 def: &hax::FullDef,
592 target_kind: ClosureKind,
593 ) -> Result<TraitImpl, Error> {
594 let span = item_meta.span;
595 let hax::FullDefKind::Closure {
596 args,
597 fn_once_impl,
598 fn_mut_impl,
599 fn_impl,
600 ..
601 } = &def.kind
602 else {
603 unreachable!()
604 };
605
606 self.translate_def_generics(span, def)?;
607 assert!(self.innermost_binder_mut().bound_region_vars.is_empty());
609 self.innermost_binder_mut()
610 .push_params_from_binder(args.fn_sig.rebind(()))?;
611
612 let vimpl = match target_kind {
614 ClosureKind::FnOnce => fn_once_impl,
615 ClosureKind::FnMut => fn_mut_impl.as_ref().unwrap(),
616 ClosureKind::Fn => fn_impl.as_ref().unwrap(),
617 };
618 let mut timpl = self.translate_virtual_trait_impl(def_id, item_meta, vimpl)?;
619
620 let call_fn_id = self.register_item(
622 span,
623 def.this(),
624 TransItemSourceKind::ClosureMethod(target_kind),
625 );
626 let call_fn_name = TraitItemName(target_kind.method_name().to_string());
627 let call_fn_binder = {
628 let mut method_params = GenericParams::empty();
629 match target_kind {
630 ClosureKind::FnOnce => {}
631 ClosureKind::FnMut | ClosureKind::Fn => {
632 method_params
633 .regions
634 .push_with(|index| RegionVar { index, name: None });
635 }
636 };
637
638 let generics = self
639 .outermost_binder()
640 .params
641 .identity_args_at_depth(DeBruijnId::one())
642 .concat(&method_params.identity_args_at_depth(DeBruijnId::zero()));
643 Binder::new(
644 BinderKind::TraitMethod(timpl.impl_trait.id, call_fn_name.clone()),
645 method_params,
646 FunDeclRef {
647 id: call_fn_id,
648 generics: Box::new(generics),
649 },
650 )
651 };
652 timpl.methods.push((call_fn_name, call_fn_binder));
653
654 Ok(timpl)
655 }
656
657 #[tracing::instrument(skip(self, item_meta))]
660 pub fn translate_stateless_closure_as_fn(
661 mut self,
662 def_id: FunDeclId,
663 item_meta: ItemMeta,
664 def: &hax::FullDef,
665 ) -> Result<FunDecl, Error> {
666 let span = item_meta.span;
667 let hax::FullDefKind::Closure { args: closure, .. } = &def.kind else {
668 unreachable!()
669 };
670
671 trace!("About to translate closure as fn:\n{:?}", def.def_id());
672
673 assert!(
674 closure.upvar_tys.is_empty(),
675 "Only stateless closures can be translated as functions"
676 );
677
678 self.translate_def_generics(span, def)?;
679 assert!(self.innermost_binder_mut().bound_region_vars.is_empty(),);
681 self.innermost_binder_mut()
682 .push_params_from_binder(closure.fn_sig.rebind(()))?;
683
684 let mut signature =
686 self.translate_closure_method_sig(def, span, closure, ClosureKind::FnOnce)?;
687 let state_ty = signature.inputs.remove(0);
688 let args_tuple_ty = signature.inputs.remove(0);
689 signature.inputs = args_tuple_ty.as_tuple().unwrap().iter().cloned().collect();
690
691 let body = if item_meta.opacity.with_private_contents().is_opaque() {
692 Err(Opaque)
693 } else {
694 let mk_stt = |content| Statement::new(span, content);
702 let mk_block = |statements, terminator| -> BlockData {
703 BlockData {
704 statements,
705 terminator: Terminator::new(span, terminator),
706 }
707 };
708 let fun_id: FunDeclId = self.register_item(
709 span,
710 def.this(),
711 TransItemSourceKind::ClosureMethod(ClosureKind::FnOnce),
712 );
713 let impl_ref = self.translate_closure_impl_ref(span, closure, ClosureKind::FnOnce)?;
714 let fn_op = FnOperand::Regular(FnPtr {
715 func: Box::new(fun_id.into()),
716 generics: impl_ref.generics.clone(),
717 });
718
719 let mut locals = Locals {
720 arg_count: signature.inputs.len(),
721 locals: Vector::new(),
722 };
723 let mut statements = vec![];
724 let mut blocks = Vector::default();
725
726 let output = locals.new_var(None, signature.output.clone());
727 let args: Vec<Place> = signature
728 .inputs
729 .iter()
730 .enumerate()
731 .map(|(i, ty)| locals.new_var(Some(format!("arg{}", i + 1)), ty.clone()))
732 .collect();
733 let args_tupled = locals.new_var(Some("args".to_string()), args_tuple_ty.clone());
734 let state = locals.new_var(Some("state".to_string()), state_ty.clone());
735
736 statements.push(mk_stt(StatementKind::Assign(
737 args_tupled.clone(),
738 Rvalue::Aggregate(
739 AggregateKind::Adt(args_tuple_ty.as_adt().unwrap().clone(), None, None),
740 args.into_iter().map(Operand::Move).collect(),
741 ),
742 )));
743
744 let state_ty_adt = state_ty.as_adt().unwrap();
745 statements.push(mk_stt(StatementKind::Assign(
746 state.clone(),
747 Rvalue::Aggregate(AggregateKind::Adt(state_ty_adt.clone(), None, None), vec![]),
748 )));
749
750 let start_block = blocks.reserve_slot();
751 let ret_block = blocks.push(mk_block(vec![], TerminatorKind::Return));
752 let unwind_block = blocks.push(mk_block(vec![], TerminatorKind::UnwindResume));
753 let call = TerminatorKind::Call {
754 target: ret_block,
755 call: Call {
756 func: fn_op,
757 args: vec![Operand::Move(state), Operand::Move(args_tupled)],
758 dest: output,
759 },
760 on_unwind: unwind_block,
761 };
762 blocks.set_slot(start_block, mk_block(statements, call));
763
764 let body: ExprBody = GExprBody {
765 span,
766 locals,
767 comments: vec![],
768 body: blocks,
769 };
770 Ok(Body::Unstructured(body))
771 };
772
773 Ok(FunDecl {
774 def_id,
775 item_meta,
776 signature,
777 kind: ItemKind::TopLevel,
778 is_global_initializer: None,
779 body,
780 })
781 }
782}