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