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