1use itertools::Itertools;
7use std::collections::HashMap;
8use std::collections::VecDeque;
9use std::ops::Deref;
10use std::ops::DerefMut;
11use std::panic;
12use std::rc::Rc;
13
14use rustc_middle::mir;
15use rustc_middle::ty;
16
17use super::translate_crate::*;
18use super::translate_ctx::*;
19use charon_lib::ast::ullbc_ast::StatementKind;
20use charon_lib::ast::ullbc_ast_utils::BodyBuilder;
21use charon_lib::ast::*;
22use charon_lib::formatter::FmtCtx;
23use charon_lib::formatter::IntoFormatter;
24use charon_lib::ids::IndexMap;
25use charon_lib::pretty::FmtWithCtx;
26use charon_lib::ullbc_ast::*;
27
28pub(crate) struct BodyTransCtx<'tcx, 'tctx, 'ictx> {
30 pub i_ctx: &'ictx mut ItemTransCtx<'tcx, 'tctx>,
32 pub local_decls: &'ictx rustc_index::IndexVec<mir::Local, mir::LocalDecl<'tcx>>,
34
35 pub drop_kind: DropKind,
37 pub locals: Locals,
39 pub locals_map: HashMap<usize, LocalId>,
41 pub blocks: IndexMap<BlockId, BlockData>,
43 pub blocks_map: HashMap<mir::BasicBlock, BlockId>,
47 pub blocks_stack: VecDeque<mir::BasicBlock>,
51}
52
53impl<'tcx, 'tctx, 'ictx> BodyTransCtx<'tcx, 'tctx, 'ictx> {
54 pub(crate) fn new(
55 i_ctx: &'ictx mut ItemTransCtx<'tcx, 'tctx>,
56 body: &'ictx Rc<mir::Body<'tcx>>,
57 drop_kind: DropKind,
58 ) -> Self {
59 i_ctx.lifetime_freshener = Some(IndexMap::new());
60 BodyTransCtx {
61 i_ctx,
62 local_decls: &body.local_decls,
63 drop_kind,
64 locals: Default::default(),
65 locals_map: Default::default(),
66 blocks: Default::default(),
67 blocks_map: Default::default(),
68 blocks_stack: Default::default(),
69 }
70 }
71}
72
73impl<'tcx, 'tctx, 'ictx> Deref for BodyTransCtx<'tcx, 'tctx, 'ictx> {
74 type Target = ItemTransCtx<'tcx, 'tctx>;
75 fn deref(&self) -> &Self::Target {
76 self.i_ctx
77 }
78}
79impl<'tcx, 'tctx, 'ictx> DerefMut for BodyTransCtx<'tcx, 'tctx, 'ictx> {
80 fn deref_mut(&mut self) -> &mut Self::Target {
81 self.i_ctx
82 }
83}
84
85pub(crate) struct BlockTransCtx<'tcx, 'tctx, 'ictx, 'bctx> {
87 pub b_ctx: &'bctx mut BodyTransCtx<'tcx, 'tctx, 'ictx>,
89 pub statements: Vec<Statement>,
91}
92
93impl<'tcx, 'tctx, 'ictx, 'bctx> BlockTransCtx<'tcx, 'tctx, 'ictx, 'bctx> {
94 pub(crate) fn new(b_ctx: &'bctx mut BodyTransCtx<'tcx, 'tctx, 'ictx>) -> Self {
95 BlockTransCtx {
96 b_ctx,
97 statements: Vec::new(),
98 }
99 }
100}
101
102impl<'tcx, 'tctx, 'ictx, 'bctx> Deref for BlockTransCtx<'tcx, 'tctx, 'ictx, 'bctx> {
103 type Target = BodyTransCtx<'tcx, 'tctx, 'ictx>;
104 fn deref(&self) -> &Self::Target {
105 self.b_ctx
106 }
107}
108impl<'tcx, 'tctx, 'ictx, 'bctx> DerefMut for BlockTransCtx<'tcx, 'tctx, 'ictx, 'bctx> {
109 fn deref_mut(&mut self) -> &mut Self::Target {
110 self.b_ctx
111 }
112}
113
114pub fn translate_variant_id(id: hax::VariantIdx) -> VariantId {
115 VariantId::new(id.as_usize())
116}
117
118pub fn translate_field_id(id: hax::FieldIdx) -> FieldId {
119 FieldId::new(id.index())
120}
121
122fn translate_borrow_kind(borrow_kind: mir::BorrowKind) -> BorrowKind {
124 match borrow_kind {
125 mir::BorrowKind::Shared => BorrowKind::Shared,
126 mir::BorrowKind::Mut { kind } => match kind {
127 mir::MutBorrowKind::Default => BorrowKind::Mut,
128 mir::MutBorrowKind::TwoPhaseBorrow => BorrowKind::TwoPhaseMut,
129 mir::MutBorrowKind::ClosureCapture => BorrowKind::UniqueImmutable,
130 },
131 mir::BorrowKind::Fake(mir::FakeBorrowKind::Shallow) => BorrowKind::Shallow,
132 mir::BorrowKind::Fake(mir::FakeBorrowKind::Deep) => unimplemented!(),
134 }
135}
136
137impl<'tcx> ItemTransCtx<'tcx, '_> {
138 pub fn translate_def_body(&mut self, span: Span, def: &hax::FullDef) -> Body {
141 match self.translate_def_body_inner(span, def) {
142 Ok(body) => body,
143 Err(e) => Body::Error(e),
144 }
145 }
146
147 fn translate_def_body_inner(&mut self, span: Span, def: &hax::FullDef) -> Result<Body, Error> {
148 if let Some(body) = self.get_mir(def.this(), span)? {
150 Ok(self.translate_body(span, body, &def.source_text))
151 } else {
152 if let hax::FullDefKind::Const { value, .. }
153 | hax::FullDefKind::AssocConst { value, .. } = def.kind()
154 && let Some(value) = value
155 {
156 let c = self.translate_constant_expr(span, &value)?;
161 let mut bb = BodyBuilder::new(span, 0);
162 let ret = bb.new_var(None, c.ty.clone());
163 bb.push_statement(StatementKind::Assign(
164 ret,
165 Rvalue::Use(Operand::Const(Box::new(c))),
166 ));
167 Ok(Body::Unstructured(bb.build()))
168 } else {
169 Ok(Body::Missing)
170 }
171 }
172 }
173
174 pub fn translate_body(
177 &mut self,
178 span: Span,
179 body: mir::Body<'tcx>,
180 source_text: &Option<String>,
181 ) -> Body {
182 let drop_kind = match body.phase {
183 mir::MirPhase::Built | mir::MirPhase::Analysis(..) => DropKind::Conditional,
184 mir::MirPhase::Runtime(..) => DropKind::Precise,
185 };
186 let mut ctx = panic::AssertUnwindSafe(&mut *self);
187 let body = panic::AssertUnwindSafe(body);
188 let res = panic::catch_unwind(move || {
190 let body = Rc::new({ body }.0);
191 let ctx = BodyTransCtx::new(&mut *ctx, &body, drop_kind);
192 ctx.translate_body(&body, source_text)
193 });
194 match res {
195 Ok(Ok(body)) => body,
196 Ok(Err(e)) => Body::Error(e),
198 Err(_) => {
200 let e = register_error!(self, span, "Thread panicked when extracting body.");
201 Body::Error(e)
202 }
203 }
204 }
205}
206
207impl<'tcx> BodyTransCtx<'tcx, '_, '_> {
208 pub(crate) fn translate_local(&self, local: &mir::Local) -> Option<LocalId> {
209 self.locals_map.get(&local.index()).copied()
210 }
211
212 pub(crate) fn push_var(&mut self, rid: mir::Local, ty: Ty, name: Option<String>, span: Span) {
213 let local_id = self.locals.locals.push_with(|index| Local {
214 index,
215 name,
216 span,
217 ty,
218 });
219 self.locals_map.insert(rid.as_usize(), local_id);
220 }
221
222 fn translate_body_locals(&mut self, body: &mir::Body<'tcx>) -> Result<(), Error> {
224 for (index, var) in body.local_decls.iter_enumerated() {
226 let name: Option<String> = hax::name_of_local(index, &body.var_debug_info);
228
229 let span = self.translate_span(&var.source_info.span);
231 let ty = self.translate_rustc_ty(span, &var.ty)?;
232
233 self.push_var(index, ty, name, span);
235 }
236
237 Ok(())
238 }
239
240 fn translate_basic_block_id(&mut self, block_id: mir::BasicBlock) -> BlockId {
242 match self.blocks_map.get(&block_id) {
243 Some(id) => *id,
244 None => {
246 self.blocks_stack.push_back(block_id);
248 let id = self.blocks.reserve_slot();
249 self.blocks_map.insert(block_id, id);
251 id
252 }
253 }
254 }
255
256 fn translate_basic_block(
257 &mut self,
258 source_scopes: &rustc_index::IndexVec<mir::SourceScope, mir::SourceScopeData>,
259 block: &mir::BasicBlockData<'tcx>,
260 ) -> Result<BlockData, Error> {
261 let mut block_ctx = BlockTransCtx::new(self);
263 for statement in &block.statements {
264 trace!("statement: {:?}", statement);
265 block_ctx.translate_statement(source_scopes, statement)?;
266 }
267
268 let terminator = block.terminator.as_ref().unwrap();
270 let terminator = block_ctx.translate_terminator(source_scopes, terminator)?;
271
272 Ok(BlockData {
273 statements: block_ctx.statements,
274 terminator,
275 })
276 }
277
278 fn translate_body_comments(
280 &mut self,
281 source_text: &Option<String>,
282 charon_span: Span,
283 ) -> Vec<(usize, Vec<String>)> {
284 if let Some(body_text) = source_text {
285 let mut comments = body_text
286 .lines()
287 .rev()
289 .enumerate()
290 .map(|(i, line)| (charon_span.data.end.line - i, line))
292 .map(|(line_nbr, line)| (line_nbr, line.trim_start().strip_prefix("//")))
294 .peekable()
295 .batching(|iter| {
296 let (line_nbr, _first) = iter.next()?;
299 let mut comments = iter
301 .peeking_take_while(|(_, opt_comment)| opt_comment.is_some())
304 .map(|(_, opt_comment)| opt_comment.unwrap())
305 .map(|s| s.strip_prefix(" ").unwrap_or(s))
306 .map(str::to_owned)
307 .collect_vec();
308 comments.reverse();
309 Some((line_nbr, comments))
310 })
311 .filter(|(_, comments)| !comments.is_empty())
312 .collect_vec();
313 comments.reverse();
314 comments
315 } else {
316 Vec::new()
317 }
318 }
319
320 fn translate_body(
321 mut self,
322 mir_body: &mir::Body<'tcx>,
323 source_text: &Option<String>,
324 ) -> Result<Body, Error> {
325 let span = self.translate_span(&mir_body.span);
327
328 trace!("Translating the body locals");
330 self.locals.arg_count = mir_body.arg_count;
331 self.translate_body_locals(&mir_body)?;
332
333 trace!("Translating the expression body");
335
336 let id = self.translate_basic_block_id(rustc_index::Idx::new(mir::START_BLOCK.as_usize()));
338 assert!(id == START_BLOCK_ID);
339
340 while let Some(mir_block_id) = self.blocks_stack.pop_front() {
342 let mir_block = mir_body.basic_blocks.get(mir_block_id).unwrap();
343 let block_id = self.translate_basic_block_id(mir_block_id);
344 let block = self.translate_basic_block(&mir_body.source_scopes, mir_block)?;
345 self.blocks.set_slot(block_id, block);
346 }
347
348 let comments = self.translate_body_comments(source_text, span);
350 Ok(Body::Unstructured(ExprBody {
351 span,
352 locals: self.locals,
353 bound_body_regions: self.i_ctx.lifetime_freshener.take().unwrap().slot_count(),
354 body: self.blocks.make_contiguous(),
355 comments,
356 }))
357 }
358}
359
360impl<'tcx> BlockTransCtx<'tcx, '_, '_, '_> {
361 fn translate_binaryop_kind(&mut self, _span: Span, binop: mir::BinOp) -> Result<BinOp, Error> {
362 Ok(match binop {
363 mir::BinOp::BitXor => BinOp::BitXor,
364 mir::BinOp::BitAnd => BinOp::BitAnd,
365 mir::BinOp::BitOr => BinOp::BitOr,
366 mir::BinOp::Eq => BinOp::Eq,
367 mir::BinOp::Lt => BinOp::Lt,
368 mir::BinOp::Le => BinOp::Le,
369 mir::BinOp::Ne => BinOp::Ne,
370 mir::BinOp::Ge => BinOp::Ge,
371 mir::BinOp::Gt => BinOp::Gt,
372 mir::BinOp::Add => BinOp::Add(OverflowMode::Wrap),
373 mir::BinOp::AddUnchecked => BinOp::Add(OverflowMode::UB),
374 mir::BinOp::Sub => BinOp::Sub(OverflowMode::Wrap),
375 mir::BinOp::SubUnchecked => BinOp::Sub(OverflowMode::UB),
376 mir::BinOp::Mul => BinOp::Mul(OverflowMode::Wrap),
377 mir::BinOp::MulUnchecked => BinOp::Mul(OverflowMode::UB),
378 mir::BinOp::Div => BinOp::Div(OverflowMode::UB),
379 mir::BinOp::Rem => BinOp::Rem(OverflowMode::UB),
380 mir::BinOp::AddWithOverflow => BinOp::AddChecked,
381 mir::BinOp::SubWithOverflow => BinOp::SubChecked,
382 mir::BinOp::MulWithOverflow => BinOp::MulChecked,
383 mir::BinOp::Shl => BinOp::Shl(OverflowMode::Wrap),
384 mir::BinOp::ShlUnchecked => BinOp::Shl(OverflowMode::UB),
385 mir::BinOp::Shr => BinOp::Shr(OverflowMode::Wrap),
386 mir::BinOp::ShrUnchecked => BinOp::Shr(OverflowMode::UB),
387 mir::BinOp::Cmp => BinOp::Cmp,
388 mir::BinOp::Offset => BinOp::Offset,
389 })
390 }
391
392 fn translate_place(
393 &mut self,
394 span: Span,
395 mir_place: &mir::Place<'tcx>,
396 ) -> Result<Place, Error> {
397 use hax::{HasBase, SInto};
398 use rustc_middle::ty;
399
400 let tcx = self.hax_state.base().tcx;
401 let local_decls = self.local_decls;
402 let ptr_size = self.t_ctx.translated.target_information.target_pointer_size;
403
404 let mut place_ty: mir::PlaceTy = mir::Place::from(mir_place.local).ty(local_decls, tcx);
405 let var_id = self.translate_local(&mir_place.local).unwrap();
406 let mut place = self.locals.place_for_var(var_id);
407 for elem in mir_place.projection.as_slice() {
408 use mir::ProjectionElem::*;
409 if let TyKind::Error(msg) = place.ty().kind() {
410 return Err(Error {
411 span,
412 msg: msg.clone(),
413 });
414 }
415 let projected_place_ty = place_ty.projection_ty(tcx, *elem);
416 let next_place_ty = projected_place_ty.ty.sinto(&self.hax_state);
417 let next_place_ty = self.translate_ty(span, &next_place_ty)?;
418 let proj_elem = match elem {
419 Deref => ProjectionElem::Deref,
420 Field(index, _) => {
421 let TyKind::Adt(tref) = place.ty().kind() else {
422 raise_error!(
423 self,
424 span,
425 "found unexpected type in field projection: {}",
426 next_place_ty.with_ctx(&self.into_fmt())
427 )
428 };
429 let field_id = translate_field_id(*index);
430 match place_ty.ty.kind() {
431 ty::Adt(adt_def, _) => {
432 let variant = place_ty.variant_index;
433 let variant_id = variant.map(translate_variant_id);
434 let generics = &tref.generics;
435 match tref.id {
436 TypeId::Adt(type_id) => {
437 assert!(
438 ((adt_def.is_struct() || adt_def.is_union())
439 && variant.is_none())
440 || (adt_def.is_enum() && variant.is_some())
441 );
442 let field_proj = FieldProjKind::Adt(type_id, variant_id);
443 ProjectionElem::Field(field_proj, field_id)
444 }
445 TypeId::Tuple => {
446 assert!(generics.regions.is_empty());
447 assert!(variant.is_none());
448 assert!(generics.const_generics.is_empty());
449 let field_proj =
450 FieldProjKind::Tuple(generics.types.elem_count());
451 ProjectionElem::Field(field_proj, field_id)
452 }
453 TypeId::Builtin(BuiltinTy::Box) => {
454 assert!(generics.regions.is_empty());
456 assert!(generics.types.elem_count() == 2);
457 assert!(generics.const_generics.is_empty());
458 assert!(field_id == FieldId::ZERO);
459 ProjectionElem::Deref
461 }
462 _ => {
463 raise_error!(self, span, "Unexpected field projection")
464 }
465 }
466 }
467 ty::Tuple(_types) => {
468 let field_proj = FieldProjKind::Tuple(tref.generics.types.elem_count());
469 ProjectionElem::Field(field_proj, field_id)
470 }
471 ty::Closure(..) => {
474 let type_id = *tref.id.as_adt().unwrap();
475 let field_proj = FieldProjKind::Adt(type_id, None);
476 ProjectionElem::Field(field_proj, field_id)
477 }
478 _ => panic!(),
479 }
480 }
481 Index(local) => {
482 let var_id = self.translate_local(local).unwrap();
483 let local = self.locals.place_for_var(var_id);
484 let offset = Operand::Copy(local);
485 ProjectionElem::Index {
486 offset: Box::new(offset),
487 from_end: false,
488 }
489 }
490 &ConstantIndex {
491 offset, from_end, ..
492 } => {
493 let offset = Operand::Const(Box::new(
494 ScalarValue::mk_usize(ptr_size, offset).to_constant(),
495 ));
496 ProjectionElem::Index {
497 offset: Box::new(offset),
498 from_end,
499 }
500 }
501 &Subslice { from, to, from_end } => {
502 let from = Operand::Const(Box::new(
503 ScalarValue::mk_usize(ptr_size, from).to_constant(),
504 ));
505 let to =
506 Operand::Const(Box::new(ScalarValue::mk_usize(ptr_size, to).to_constant()));
507 ProjectionElem::Subslice {
508 from: Box::new(from),
509 to: Box::new(to),
510 from_end,
511 }
512 }
513 OpaqueCast(..) => {
514 raise_error!(self, span, "Unexpected ProjectionElem::OpaqueCast");
515 }
516 Downcast { .. } => {
517 place_ty = projected_place_ty;
520 continue;
521 }
522 UnwrapUnsafeBinder { .. } => {
523 raise_error!(self, span, "unsupported feature: unsafe binders");
524 }
525 };
526 place = place.project(proj_elem, next_place_ty);
527 place_ty = projected_place_ty;
528 }
529 Ok(place)
530 }
531
532 fn translate_operand(
534 &mut self,
535 span: Span,
536 operand: &mir::Operand<'tcx>,
537 ) -> Result<Operand, Error> {
538 Ok(match operand {
539 mir::Operand::Copy(place) => {
540 let p = self.translate_place(span, place)?;
541 Operand::Copy(p)
542 }
543 mir::Operand::Move(place) => {
544 let p = self.translate_place(span, place)?;
545 Operand::Move(p)
546 }
547 mir::Operand::Constant(const_op) => {
548 let const_op = self.catch_sinto(span, &const_op)?;
549 match &const_op.kind {
550 hax::ConstOperandKind::Value(constant) => {
551 let constant = self.translate_constant_expr(span, constant)?;
552 Operand::Const(Box::new(constant))
553 }
554 hax::ConstOperandKind::Promoted(item) => {
555 let global_ref = self.translate_global_decl_ref(span, item)?;
557 let constant = ConstantExpr {
558 kind: ConstantExprKind::Global(global_ref),
559 ty: self.translate_ty(span, &const_op.ty)?,
560 };
561 Operand::Const(Box::new(constant))
562 }
563 }
564 }
565 mir::Operand::RuntimeChecks(check) => {
566 let op = match check {
567 mir::RuntimeChecks::UbChecks => NullOp::UbChecks,
568 mir::RuntimeChecks::OverflowChecks => NullOp::OverflowChecks,
569 mir::RuntimeChecks::ContractChecks => NullOp::ContractChecks,
570 };
571 let local = self.locals.new_var(None, Ty::mk_bool());
572 self.statements.push(Statement {
573 span,
574 kind: StatementKind::StorageLive(local.as_local().unwrap()),
575 comments_before: vec![],
576 });
577 self.statements.push(Statement {
578 span,
579 kind: StatementKind::Assign(
580 local.clone(),
581 Rvalue::NullaryOp(op, Ty::mk_bool()),
582 ),
583 comments_before: vec![],
584 });
585 Operand::Move(local)
586 }
587 })
588 }
589
590 fn translate_mir_rvalue(
592 &mut self,
593 span: Span,
594 rvalue: &mir::Rvalue<'tcx>,
595 tgt_ty: &Ty,
596 ) -> Result<Rvalue, Error> {
597 match rvalue {
598 mir::Rvalue::Use(operand) => Ok(Rvalue::Use(self.translate_operand(span, operand)?)),
599 mir::Rvalue::CopyForDeref(place) => {
600 let place = self.translate_place(span, place)?;
603 Ok(Rvalue::Use(Operand::Copy(place)))
604 }
605 mir::Rvalue::Repeat(operand, cnst) => {
606 let c = self.translate_ty_constant_expr(span, cnst)?;
607 let op = self.translate_operand(span, operand)?;
608 let ty = op.ty().clone();
609 Ok(Rvalue::Repeat(op, ty, Box::new(c)))
611 }
612 mir::Rvalue::Ref(_region, borrow_kind, place) => {
613 let place = self.translate_place(span, place)?;
614 let borrow_kind = translate_borrow_kind(*borrow_kind);
615 Ok(Rvalue::Ref {
616 place,
617 kind: borrow_kind,
618 ptr_metadata: Operand::Const(Box::new(ConstantExpr {
620 kind: ConstantExprKind::Opaque("Missing metadata".to_string()),
621 ty: Ty::mk_unit(),
622 })),
623 })
624 }
625 mir::Rvalue::RawPtr(mtbl, place) => {
626 let mtbl = match mtbl {
627 mir::RawPtrKind::Mut => RefKind::Mut,
628 mir::RawPtrKind::Const => RefKind::Shared,
629 mir::RawPtrKind::FakeForPtrMetadata => RefKind::Shared,
630 };
631 let place = self.translate_place(span, place)?;
632 Ok(Rvalue::RawPtr {
633 place,
634 kind: mtbl,
635 ptr_metadata: Operand::Const(Box::new(ConstantExpr {
637 kind: ConstantExprKind::Opaque("Missing metadata".to_string()),
638 ty: Ty::mk_unit(),
639 })),
640 })
641 }
642 mir::Rvalue::Cast(cast_kind, mir_operand, rust_tgt_ty) => {
643 let op_ty = mir_operand.ty(self.local_decls, self.tcx);
644 let tgt_ty = self.translate_rustc_ty(span, rust_tgt_ty)?;
645
646 let mut operand = self.translate_operand(span, mir_operand)?;
648 let src_ty = operand.ty().clone();
649
650 let cast_kind = match cast_kind {
651 mir::CastKind::IntToInt
652 | mir::CastKind::IntToFloat
653 | mir::CastKind::FloatToInt
654 | mir::CastKind::FloatToFloat => {
655 let tgt_ty = *tgt_ty.kind().as_literal().unwrap();
656 let src_ty = *src_ty.kind().as_literal().unwrap();
657 CastKind::Scalar(src_ty, tgt_ty)
658 }
659 mir::CastKind::PtrToPtr
660 | mir::CastKind::PointerCoercion(
661 ty::adjustment::PointerCoercion::MutToConstPointer,
662 ..,
663 )
664 | mir::CastKind::PointerCoercion(
665 ty::adjustment::PointerCoercion::ArrayToPointer,
666 ..,
667 )
668 | mir::CastKind::FnPtrToPtr
669 | mir::CastKind::PointerExposeProvenance
670 | mir::CastKind::PointerWithExposedProvenance => {
671 CastKind::RawPtr(src_ty, tgt_ty)
672 }
673 mir::CastKind::PointerCoercion(
674 ty::adjustment::PointerCoercion::ClosureFnPointer(_),
675 ..,
676 ) => {
677 let hax_op_ty: hax::Ty = self.catch_sinto(span, &op_ty)?;
678 let hax::TyKind::Closure(closure, ..) = hax_op_ty.kind() else {
681 unreachable!("Non-closure type in PointerCoercion::ClosureFnPointer");
682 };
683 let fn_ref: RegionBinder<FunDeclRef> =
684 self.translate_stateless_closure_as_fn_ref(span, closure)?;
685 let fn_ptr_bound: RegionBinder<FnPtr> = fn_ref.map(FunDeclRef::into);
686 let fn_ptr: FnPtr = self.erase_region_binder(fn_ptr_bound.clone());
687 let src_ty = TyKind::FnDef(fn_ptr_bound).into_ty();
688 operand = Operand::Const(Box::new(ConstantExpr {
689 kind: ConstantExprKind::FnDef(fn_ptr),
690 ty: src_ty.clone(),
691 }));
692 CastKind::FnPtr(src_ty, tgt_ty)
693 }
694 mir::CastKind::PointerCoercion(
695 ty::adjustment::PointerCoercion::UnsafeFnPointer
696 | ty::adjustment::PointerCoercion::ReifyFnPointer(_),
697 ..,
698 ) => CastKind::FnPtr(src_ty, tgt_ty),
699 mir::CastKind::Transmute => CastKind::Transmute(src_ty, tgt_ty),
700 mir::CastKind::Subtype => CastKind::Transmute(src_ty, tgt_ty),
702 mir::CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize, ..) => {
703 let meta =
704 hax::compute_unsizing_metadata(&self.hax_state, op_ty, *rust_tgt_ty);
705 let meta = match &meta {
706 hax::UnsizingMetadata::Length(len) => {
707 let len = self.translate_constant_expr(span, len)?;
708 UnsizingMetadata::Length(Box::new(len))
709 }
710 hax::UnsizingMetadata::DirectVTable(impl_expr) => {
711 let tref = self.translate_trait_impl_expr(span, impl_expr)?;
712 let vtable =
713 self.translate_vtable_instance_const(span, impl_expr)?;
714 UnsizingMetadata::VTable(tref, vtable)
715 }
716 hax::UnsizingMetadata::NestedVTable(dyn_impl_expr) => {
717 let binder = self.translate_dyn_binder(
719 span,
720 dyn_impl_expr,
721 |ctx, _, impl_expr| {
722 ctx.translate_trait_impl_expr(span, impl_expr)
723 },
724 )?;
725
726 let mut target_tref = &binder.skip_binder;
729 let mut clause_path: Vec<(TraitDeclId, TraitClauseId)> = vec![];
730 while let TraitRefKind::ParentClause(tref, id) = &target_tref.kind {
731 clause_path.push((tref.trait_decl_ref.skip_binder.id, *id));
732 target_tref = tref;
733 }
734
735 let mut field_path = vec![];
736 for &(trait_id, clause_id) in &clause_path {
737 if let Ok(ItemRef::TraitDecl(tdecl)) =
738 self.get_or_translate(trait_id.into())
739 && let &vtable_decl_id =
740 tdecl.vtable.as_ref().unwrap().id.as_adt().unwrap()
741 && let Ok(ItemRef::Type(vtable_decl)) =
742 self.get_or_translate(vtable_decl_id.into())
743 {
744 let ItemSource::VTableTy { supertrait_map, .. } =
745 &vtable_decl.src
746 else {
747 unreachable!()
748 };
749 field_path.push(supertrait_map[clause_id].unwrap());
750 } else {
751 break;
752 }
753 }
754
755 if field_path.len() == clause_path.len() {
756 UnsizingMetadata::VTableUpcast(field_path)
757 } else {
758 UnsizingMetadata::Unknown
759 }
760 }
761 hax::UnsizingMetadata::Unknown => UnsizingMetadata::Unknown,
762 };
763 CastKind::Unsize(src_ty, tgt_ty.clone(), meta)
764 }
765 };
766 let unop = UnOp::Cast(cast_kind);
767 Ok(Rvalue::UnaryOp(unop, operand))
768 }
769 mir::Rvalue::BinaryOp(binop, (left, right)) => Ok(Rvalue::BinaryOp(
770 self.translate_binaryop_kind(span, *binop)?,
771 self.translate_operand(span, left)?,
772 self.translate_operand(span, right)?,
773 )),
774 mir::Rvalue::UnaryOp(unop, operand) => {
775 let operand = self.translate_operand(span, operand)?;
776 let unop = match unop {
777 mir::UnOp::Not => UnOp::Not,
778 mir::UnOp::Neg => UnOp::Neg(OverflowMode::Wrap),
779 mir::UnOp::PtrMetadata => match operand {
780 Operand::Copy(p) | Operand::Move(p) => {
781 return Ok(Rvalue::Use(Operand::Copy(
782 p.project(ProjectionElem::PtrMetadata, tgt_ty.clone()),
783 )));
784 }
785 Operand::Const(_) => {
786 panic!("unexpected metadata operand")
787 }
788 },
789 };
790 Ok(Rvalue::UnaryOp(unop, operand))
791 }
792 mir::Rvalue::Discriminant(place) => {
793 let place = self.translate_place(span, place)?;
794 if !place
796 .ty()
797 .kind()
798 .as_adt()
799 .is_some_and(|tref| tref.id.is_adt())
800 {
801 raise_error!(
802 self,
803 span,
804 "Unexpected scrutinee type for ReadDiscriminant: {}",
805 place.ty().with_ctx(&self.into_fmt())
806 )
807 }
808 Ok(Rvalue::Discriminant(place))
809 }
810 mir::Rvalue::Aggregate(aggregate_kind, operands) => {
811 let operands_t: Vec<Operand> = operands
826 .iter()
827 .map(|op| self.translate_operand(span, op))
828 .try_collect()?;
829 let ptr_size = self.t_ctx.translated.target_information.target_pointer_size;
830
831 match aggregate_kind {
832 mir::AggregateKind::Array(ty) => {
833 let t_ty = self.translate_rustc_ty(span, ty)?;
834 let c = ConstantExpr::mk_usize(
835 ScalarValue::from_uint(
836 ptr_size,
837 UIntTy::Usize,
838 operands_t.len() as u128,
839 )
840 .unwrap(),
841 );
842 Ok(Rvalue::Aggregate(
843 AggregateKind::Array(t_ty, Box::new(c)),
844 operands_t,
845 ))
846 }
847 mir::AggregateKind::Tuple => {
848 let tref = TypeDeclRef::new(TypeId::Tuple, GenericArgs::empty());
849 Ok(Rvalue::Aggregate(
850 AggregateKind::Adt(tref, None, None),
851 operands_t,
852 ))
853 }
854 mir::AggregateKind::Adt(def_id, variant_idx, generics, _, field_index) => {
855 use ty::AdtKind;
856 trace!("{:?}", rvalue);
857
858 let adt_kind = self.tcx.adt_def(def_id).adt_kind();
859 let item = hax::translate_item_ref(&self.hax_state, *def_id, generics);
860 let tref = self.translate_type_decl_ref(span, &item)?;
861 let variant_id = match adt_kind {
862 AdtKind::Struct | AdtKind::Union => None,
863 AdtKind::Enum => Some(translate_variant_id(*variant_idx)),
864 };
865 let field_id = match adt_kind {
866 AdtKind::Struct | AdtKind::Enum => None,
867 AdtKind::Union => Some(translate_field_id(field_index.unwrap())),
868 };
869
870 let akind = AggregateKind::Adt(tref, variant_id, field_id);
871 Ok(Rvalue::Aggregate(akind, operands_t))
872 }
873 mir::AggregateKind::Closure(def_id, generics) => {
874 let args = hax::ClosureArgs::sfrom(&self.hax_state, *def_id, generics);
875 let tref = self.translate_closure_type_ref(span, &args)?;
876 let akind = AggregateKind::Adt(tref, None, None);
877 Ok(Rvalue::Aggregate(akind, operands_t))
878 }
879 mir::AggregateKind::RawPtr(ty, mutability) => {
880 let t_ty = self.translate_rustc_ty(span, ty)?;
882 let mutability = if mutability.is_mut() {
883 RefKind::Mut
884 } else {
885 RefKind::Shared
886 };
887
888 let akind = AggregateKind::RawPtr(t_ty, mutability);
889
890 Ok(Rvalue::Aggregate(akind, operands_t))
891 }
892 mir::AggregateKind::Coroutine(..)
893 | mir::AggregateKind::CoroutineClosure(..) => {
894 raise_error!(self, span, "Coroutines are not supported");
895 }
896 }
897 }
898 mir::Rvalue::ShallowInitBox(op, ty) => {
899 let op = self.translate_operand(span, op)?;
900 let ty = self.translate_rustc_ty(span, ty)?;
901 Ok(Rvalue::ShallowInitBox(op, ty))
902 }
903 mir::Rvalue::ThreadLocalRef(_) => {
904 raise_error!(
905 self,
906 span,
907 "charon does not support thread local references"
908 );
909 }
910 mir::Rvalue::WrapUnsafeBinder { .. } => {
911 raise_error!(
912 self,
913 span,
914 "charon does not support unsafe lifetime binders"
915 );
916 }
917 }
918 }
919
920 fn translate_statement(
924 &mut self,
925 source_scopes: &rustc_index::IndexVec<mir::SourceScope, mir::SourceScopeData>,
926 statement: &mir::Statement<'tcx>,
927 ) -> Result<(), Error> {
928 trace!("About to translate statement (MIR) {:?}", statement);
929 let span = self.translate_span_from_source_info(source_scopes, &statement.source_info);
930
931 let t_statement: Option<StatementKind> = match &statement.kind {
932 mir::StatementKind::Assign((place, rvalue)) => {
933 let t_place = self.translate_place(span, place)?;
934 let t_rvalue = self.translate_mir_rvalue(span, rvalue, t_place.ty())?;
935 Some(StatementKind::Assign(t_place, t_rvalue))
936 }
937 mir::StatementKind::SetDiscriminant {
938 place,
939 variant_index,
940 } => {
941 let t_place = self.translate_place(span, place)?;
942 let variant_id = translate_variant_id(*variant_index);
943 Some(StatementKind::SetDiscriminant(t_place, variant_id))
944 }
945 mir::StatementKind::StorageLive(local) => {
946 let var_id = self.translate_local(local).unwrap();
947 Some(StatementKind::StorageLive(var_id))
948 }
949 mir::StatementKind::StorageDead(local) => {
950 let var_id = self.translate_local(local).unwrap();
951 Some(StatementKind::StorageDead(var_id))
952 }
953 mir::StatementKind::Intrinsic(mir::NonDivergingIntrinsic::Assume(op)) => {
955 let op = self.translate_operand(span, op)?;
956 Some(StatementKind::Assert {
957 assert: Assert {
958 cond: op,
959 expected: true,
960 check_kind: None,
961 },
962 on_failure: AbortKind::UndefinedBehavior,
963 })
964 }
965 mir::StatementKind::Intrinsic(mir::NonDivergingIntrinsic::CopyNonOverlapping(
966 mir::CopyNonOverlapping { src, dst, count },
967 )) => {
968 let src = self.translate_operand(span, src)?;
969 let dst = self.translate_operand(span, dst)?;
970 let count = self.translate_operand(span, count)?;
971 Some(StatementKind::CopyNonOverlapping(Box::new(
972 CopyNonOverlapping { src, dst, count },
973 )))
974 }
975 mir::StatementKind::PlaceMention(place) => {
976 let place = self.translate_place(span, place)?;
977 if place.is_local() {
980 None
981 } else {
982 Some(StatementKind::PlaceMention(place))
983 }
984 }
985 mir::StatementKind::Retag(_, _) => None,
987 mir::StatementKind::FakeRead(..) => None,
990 mir::StatementKind::AscribeUserType(..) => None,
994 mir::StatementKind::Coverage(_) => None,
996 mir::StatementKind::ConstEvalCounter => None,
999 mir::StatementKind::BackwardIncompatibleDropHint { .. } => None,
1001 mir::StatementKind::Nop => None,
1002 };
1003
1004 let Some(t_statement) = t_statement else {
1006 return Ok(());
1007 };
1008 let statement = Statement::new(span, t_statement);
1009 self.statements.push(statement);
1010 Ok(())
1011 }
1012
1013 fn translate_terminator(
1015 &mut self,
1016 source_scopes: &rustc_index::IndexVec<mir::SourceScope, mir::SourceScopeData>,
1017 terminator: &mir::Terminator<'tcx>,
1018 ) -> Result<Terminator, Error> {
1019 trace!("About to translate terminator (MIR) {:?}", terminator);
1020 let span = self.translate_span_from_source_info(source_scopes, &terminator.source_info);
1021
1022 use mir::TerminatorKind;
1024 let t_terminator: ullbc_ast::TerminatorKind = match &terminator.kind {
1025 TerminatorKind::Goto { target } => {
1026 let target = self.translate_basic_block_id(*target);
1027 ullbc_ast::TerminatorKind::Goto { target }
1028 }
1029 TerminatorKind::SwitchInt { discr, targets, .. } => {
1030 let discr = self.translate_operand(span, discr)?;
1031 let targets = self.translate_switch_targets(span, discr.ty(), targets)?;
1032 ullbc_ast::TerminatorKind::Switch { discr, targets }
1033 }
1034 TerminatorKind::UnwindResume => ullbc_ast::TerminatorKind::UnwindResume,
1035 TerminatorKind::UnwindTerminate { .. } => {
1036 ullbc_ast::TerminatorKind::Abort(AbortKind::UnwindTerminate)
1037 }
1038 TerminatorKind::Return => ullbc_ast::TerminatorKind::Return,
1039 TerminatorKind::Unreachable => {
1042 ullbc_ast::TerminatorKind::Abort(AbortKind::UndefinedBehavior)
1043 }
1044 TerminatorKind::Drop {
1045 place,
1046 target,
1047 unwind,
1048 ..
1049 } => self.translate_drop(span, place, target, unwind)?,
1050 TerminatorKind::Call {
1051 func,
1052 args,
1053 destination,
1054 target,
1055 unwind,
1056 fn_span: _,
1057 ..
1058 } => self.translate_function_call(span, func, args, destination, target, unwind)?,
1059 TerminatorKind::Assert {
1060 cond,
1061 expected,
1062 msg,
1063 target,
1064 unwind,
1065 } => {
1066 let on_unwind = self.translate_unwind_action(span, unwind);
1067 let kind = self.translate_assert_kind(span, msg)?;
1068 let assert = Assert {
1069 cond: self.translate_operand(span, cond)?,
1070 expected: *expected,
1071 check_kind: Some(kind),
1072 };
1073 let target = self.translate_basic_block_id(*target);
1074 ullbc_ast::TerminatorKind::Assert {
1075 assert,
1076 target,
1077 on_unwind,
1078 }
1079 }
1080 TerminatorKind::FalseEdge {
1081 real_target,
1082 imaginary_target: _,
1083 } => {
1084 let target = self.translate_basic_block_id(*real_target);
1089 ullbc_ast::TerminatorKind::Goto { target }
1090 }
1091 TerminatorKind::FalseUnwind {
1092 real_target,
1093 unwind: _,
1094 } => {
1095 let target = self.translate_basic_block_id(*real_target);
1097 ullbc_ast::TerminatorKind::Goto { target }
1098 }
1099 TerminatorKind::InlineAsm { .. } => {
1100 raise_error!(self, span, "Inline assembly is not supported");
1101 }
1102 TerminatorKind::CoroutineDrop
1103 | TerminatorKind::TailCall { .. }
1104 | TerminatorKind::Yield { .. } => {
1105 raise_error!(self, span, "Unsupported terminator: {:?}", terminator.kind);
1106 }
1107 };
1108
1109 Ok(Terminator::new(span, t_terminator))
1111 }
1112
1113 fn translate_switch_targets(
1115 &mut self,
1116 span: Span,
1117 switch_ty: &Ty,
1118 targets: &mir::SwitchTargets,
1119 ) -> Result<SwitchTargets, Error> {
1120 let otherwise = targets.otherwise();
1122 let targets = targets.iter().collect_vec();
1123 let switch_ty = *switch_ty.kind().as_literal().unwrap();
1124 match switch_ty {
1125 LiteralTy::Bool => {
1126 assert_eq!(targets.len(), 1);
1127 let (val, target) = targets.first().unwrap();
1128 assert_eq!(*val, 0);
1130 let if_block = self.translate_basic_block_id(otherwise);
1131 let then_block = self.translate_basic_block_id(*target);
1132 Ok(SwitchTargets::If(if_block, then_block))
1133 }
1134 LiteralTy::Char => {
1135 let targets: Vec<(Literal, BlockId)> = targets
1136 .iter()
1137 .copied()
1138 .map(|(v, tgt)| {
1139 let v = Literal::char_from_le_bytes(v);
1140 let tgt = self.translate_basic_block_id(tgt);
1141 (v, tgt)
1142 })
1143 .collect();
1144 let otherwise = self.translate_basic_block_id(otherwise);
1145 Ok(SwitchTargets::SwitchInt(
1146 LiteralTy::Char,
1147 targets,
1148 otherwise,
1149 ))
1150 }
1151 LiteralTy::Int(int_ty) => {
1152 let targets: Vec<(Literal, BlockId)> = targets
1153 .iter()
1154 .copied()
1155 .map(|(v, tgt)| {
1156 let v = Literal::Scalar(ScalarValue::from_le_bytes(
1157 IntegerTy::Signed(int_ty),
1158 v.to_le_bytes(),
1159 ));
1160 let tgt = self.translate_basic_block_id(tgt);
1161 (v, tgt)
1162 })
1163 .collect();
1164 let otherwise = self.translate_basic_block_id(otherwise);
1165 Ok(SwitchTargets::SwitchInt(switch_ty, targets, otherwise))
1166 }
1167 LiteralTy::UInt(uint_ty) => {
1168 let targets: Vec<(Literal, BlockId)> = targets
1169 .iter()
1170 .map(|(v, tgt)| {
1171 let v = Literal::Scalar(ScalarValue::from_le_bytes(
1172 IntegerTy::Unsigned(uint_ty),
1173 v.to_le_bytes(),
1174 ));
1175 let tgt = self.translate_basic_block_id(*tgt);
1176 (v, tgt)
1177 })
1178 .collect();
1179 let otherwise = self.translate_basic_block_id(otherwise);
1180 Ok(SwitchTargets::SwitchInt(
1181 LiteralTy::UInt(uint_ty),
1182 targets,
1183 otherwise,
1184 ))
1185 }
1186 _ => raise_error!(self, span, "Can't match on type {switch_ty}"),
1187 }
1188 }
1189
1190 #[allow(clippy::too_many_arguments)]
1195 fn translate_function_call(
1196 &mut self,
1197 span: Span,
1198 func: &mir::Operand<'tcx>,
1199 args: &[hax::Spanned<mir::Operand<'tcx>>],
1200 destination: &mir::Place<'tcx>,
1201 target: &Option<mir::BasicBlock>,
1202 unwind: &mir::UnwindAction,
1203 ) -> Result<TerminatorKind, Error> {
1204 let tcx = self.tcx;
1205 let op_ty = func.ty(self.local_decls, tcx);
1206 let lval = self.translate_place(span, destination)?;
1210 let on_unwind = self.translate_unwind_action(span, unwind);
1211 let fn_operand = match op_ty.kind() {
1213 ty::TyKind::FnDef(def_id, generics) => {
1214 let item = &hax::translate_item_ref(&self.hax_state, *def_id, *generics);
1217 trace!("func: {:?}", item.def_id);
1218 let fun_def = self.hax_def(item)?;
1219 let item_src =
1220 TransItemSource::from_item(item, TransItemSourceKind::Fun, self.monomorphize());
1221 let name = self.t_ctx.translate_name(&item_src)?;
1222 let panic_lang_items = &["panic", "panic_fmt", "begin_panic"];
1223 let panic_names = &[&["core", "panicking", "assert_failed"], EXPLICIT_PANIC_NAME];
1224
1225 if fun_def
1226 .lang_item
1227 .as_ref()
1228 .is_some_and(|lang_it| panic_lang_items.iter().contains(&lang_it.as_str()))
1229 || panic_names.iter().any(|panic| name.equals_ref_name(panic))
1230 {
1231 assert!(target.is_none());
1234 return Ok(TerminatorKind::Abort(AbortKind::Panic(Some(name))));
1237 } else {
1238 let fn_ptr = self.translate_fn_ptr(span, item, TransItemSourceKind::Fun)?;
1239 FnOperand::Regular(fn_ptr)
1240 }
1241 }
1242 _ => {
1243 let op = self.translate_operand(span, func)?;
1245 FnOperand::Dynamic(op)
1246 }
1247 };
1248 let args = self.translate_arguments(span, args)?;
1249 let call = Call {
1250 func: fn_operand,
1251 args,
1252 dest: lval,
1253 };
1254
1255 let target = match target {
1256 Some(target) => self.translate_basic_block_id(*target),
1257 None => {
1258 let abort =
1259 Terminator::new(span, TerminatorKind::Abort(AbortKind::UndefinedBehavior));
1260 self.blocks.push(abort.into_block())
1261 }
1262 };
1263
1264 Ok(TerminatorKind::Call {
1265 call,
1266 target,
1267 on_unwind,
1268 })
1269 }
1270
1271 #[allow(clippy::too_many_arguments)]
1273 fn translate_drop(
1274 &mut self,
1275 span: Span,
1276 place: &mir::Place<'tcx>,
1277 target: &mir::BasicBlock,
1278 unwind: &mir::UnwindAction,
1279 ) -> Result<TerminatorKind, Error> {
1280 let tref = {
1281 let place_ty = place.ty(self.local_decls, self.tcx).ty;
1282 let impl_expr = &hax::solve_destruct(&self.hax_state, place_ty);
1283 self.translate_trait_impl_expr(span, impl_expr)?
1284 };
1285 let place = self.translate_place(span, place)?;
1286 let target = self.translate_basic_block_id(*target);
1287 let on_unwind = self.translate_unwind_action(span, unwind);
1288
1289 Ok(TerminatorKind::Drop {
1290 kind: self.drop_kind,
1291 place,
1292 tref,
1293 target,
1294 on_unwind,
1295 })
1296 }
1297
1298 fn translate_unwind_action(&mut self, span: Span, unwind: &mir::UnwindAction) -> BlockId {
1300 let on_unwind = match unwind {
1301 mir::UnwindAction::Continue => {
1302 let unwind_continue = Terminator::new(span, TerminatorKind::UnwindResume);
1303 self.blocks.push(unwind_continue.into_block())
1304 }
1305 mir::UnwindAction::Unreachable => {
1306 let abort =
1307 Terminator::new(span, TerminatorKind::Abort(AbortKind::UndefinedBehavior));
1308 self.blocks.push(abort.into_block())
1309 }
1310 mir::UnwindAction::Terminate(..) => {
1311 let abort =
1312 Terminator::new(span, TerminatorKind::Abort(AbortKind::UnwindTerminate));
1313 self.blocks.push(abort.into_block())
1314 }
1315 mir::UnwindAction::Cleanup(bb) => self.translate_basic_block_id(*bb),
1316 };
1317 on_unwind
1318 }
1319
1320 fn translate_assert_kind(
1321 &mut self,
1322 span: Span,
1323 kind: &mir::AssertKind<mir::Operand<'tcx>>,
1324 ) -> Result<BuiltinAssertKind, Error> {
1325 match kind {
1326 mir::AssertKind::BoundsCheck { len, index } => {
1327 let len = self.translate_operand(span, len)?;
1328 let index = self.translate_operand(span, index)?;
1329 Ok(BuiltinAssertKind::BoundsCheck { len, index })
1330 }
1331 mir::AssertKind::Overflow(binop, left, right) => {
1332 let binop = self.translate_binaryop_kind(span, *binop)?;
1333 let left = self.translate_operand(span, left)?;
1334 let right = self.translate_operand(span, right)?;
1335 Ok(BuiltinAssertKind::Overflow(binop, left, right))
1336 }
1337 mir::AssertKind::OverflowNeg(operand) => {
1338 let operand = self.translate_operand(span, operand)?;
1339 Ok(BuiltinAssertKind::OverflowNeg(operand))
1340 }
1341 mir::AssertKind::DivisionByZero(operand) => {
1342 let operand = self.translate_operand(span, operand)?;
1343 Ok(BuiltinAssertKind::DivisionByZero(operand))
1344 }
1345 mir::AssertKind::RemainderByZero(operand) => {
1346 let operand = self.translate_operand(span, operand)?;
1347 Ok(BuiltinAssertKind::RemainderByZero(operand))
1348 }
1349 mir::AssertKind::MisalignedPointerDereference { required, found } => {
1350 let required = self.translate_operand(span, required)?;
1351 let found = self.translate_operand(span, found)?;
1352 Ok(BuiltinAssertKind::MisalignedPointerDereference { required, found })
1353 }
1354 mir::AssertKind::NullPointerDereference => {
1355 Ok(BuiltinAssertKind::NullPointerDereference)
1356 }
1357 mir::AssertKind::InvalidEnumConstruction(operand) => {
1358 let operand = self.translate_operand(span, operand)?;
1359 Ok(BuiltinAssertKind::InvalidEnumConstruction(operand))
1360 }
1361 mir::AssertKind::ResumedAfterDrop(..)
1362 | mir::AssertKind::ResumedAfterPanic(..)
1363 | mir::AssertKind::ResumedAfterReturn(..) => {
1364 raise_error!(self, span, "Coroutines are not supported");
1365 }
1366 }
1367 }
1368
1369 fn translate_arguments(
1372 &mut self,
1373 span: Span,
1374 args: &[hax::Spanned<mir::Operand<'tcx>>],
1375 ) -> Result<Vec<Operand>, Error> {
1376 let mut t_args: Vec<Operand> = Vec::new();
1377 for arg in args.iter().map(|x| &x.node) {
1378 let op = self.translate_operand(span, arg)?;
1380 t_args.push(op);
1381 }
1382 Ok(t_args)
1383 }
1384}
1385
1386impl<'a> IntoFormatter for &'a BodyTransCtx<'_, '_, '_> {
1387 type C = FmtCtx<'a>;
1388 fn into_fmt(self) -> Self::C {
1389 FmtCtx {
1390 locals: Some(&self.locals),
1391 ..self.i_ctx.into_fmt()
1392 }
1393 }
1394}