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
115pub fn translate_variant_id(id: hax::VariantIdx) -> VariantId {
116 VariantId::new(id.as_usize())
117}
118
119pub fn translate_field_id(id: hax::FieldIdx) -> FieldId {
120 FieldId::new(id.index())
121}
122
123fn translate_borrow_kind(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
138impl<'tcx> ItemTransCtx<'tcx, '_> {
139 pub fn translate_def_body(&mut self, span: Span, def: &hax::FullDef) -> Body {
142 match self.translate_def_body_inner(span, def) {
143 Ok(body) => body,
144 Err(e) => Body::Error(e),
145 }
146 }
147
148 fn translate_def_body_inner(&mut self, span: Span, def: &hax::FullDef) -> Result<Body, Error> {
149 if let Some(body) = self.get_mir(def.this(), span)? {
151 Ok(self.translate_body(span, body, &def.source_text))
152 } else {
153 if let hax::FullDefKind::Const { value, .. }
154 | hax::FullDefKind::AssocConst { value, .. } = def.kind()
155 && let Some(value) = value
156 {
157 let c = self.translate_constant_expr(span, value)?;
162 let mut bb = BodyBuilder::new(span, 0);
163 let ret = bb.new_var(None, c.ty.clone());
164 bb.push_statement(StatementKind::Assign(
165 ret,
166 Rvalue::Use(Operand::Const(Box::new(c))),
167 ));
168 Ok(Body::Unstructured(bb.build()))
169 } else {
170 Ok(Body::Missing)
171 }
172 }
173 }
174
175 pub fn translate_body(
178 &mut self,
179 span: Span,
180 body: mir::Body<'tcx>,
181 source_text: &Option<String>,
182 ) -> Body {
183 let drop_kind = match body.phase {
184 mir::MirPhase::Built | mir::MirPhase::Analysis(..) => DropKind::Conditional,
185 mir::MirPhase::Runtime(..) => DropKind::Precise,
186 };
187 let mut ctx = panic::AssertUnwindSafe(&mut *self);
188 let body = panic::AssertUnwindSafe(body);
189 let res = panic::catch_unwind(move || {
191 let body = Rc::new({ body }.0);
192 let ctx = BodyTransCtx::new(*ctx, &body, drop_kind);
193 ctx.translate_body(&body, source_text)
194 });
195 match res {
196 Ok(Ok(body)) => body,
197 Ok(Err(e)) => Body::Error(e),
199 Err(_) => {
201 let e = register_error!(self, span, "Thread panicked when extracting body.");
202 Body::Error(e)
203 }
204 }
205 }
206}
207
208impl<'tcx> BodyTransCtx<'tcx, '_, '_> {
209 pub(crate) fn translate_local(&self, local: &mir::Local) -> Option<LocalId> {
210 self.locals_map.get(&local.index()).copied()
211 }
212
213 pub(crate) fn push_var(&mut self, rid: mir::Local, ty: Ty, name: Option<String>, span: Span) {
214 let local_id = self.locals.locals.push_with(|index| Local {
215 index,
216 name,
217 span,
218 ty,
219 });
220 self.locals_map.insert(rid.as_usize(), local_id);
221 }
222
223 fn translate_body_locals(&mut self, body: &mir::Body<'tcx>) -> Result<(), Error> {
225 for (index, var) in body.local_decls.iter_enumerated() {
227 let name: Option<String> = hax::name_of_local(index, &body.var_debug_info);
229
230 let span = self.translate_span(&var.source_info.span);
232 let ty = self.translate_rustc_ty(span, &var.ty)?;
233
234 self.push_var(index, ty, name, span);
236 }
237
238 Ok(())
239 }
240
241 fn translate_basic_block_id(&mut self, block_id: mir::BasicBlock) -> BlockId {
243 match self.blocks_map.get(&block_id) {
244 Some(id) => *id,
245 None => {
247 self.blocks_stack.push_back(block_id);
249 let id = self.blocks.reserve_slot();
250 self.blocks_map.insert(block_id, id);
252 id
253 }
254 }
255 }
256
257 fn translate_basic_block(
258 &mut self,
259 source_scopes: &rustc_index::IndexVec<mir::SourceScope, mir::SourceScopeData>,
260 block: &mir::BasicBlockData<'tcx>,
261 ) -> Result<BlockData, Error> {
262 let mut block_ctx = BlockTransCtx::new(self);
264 for statement in &block.statements {
265 trace!("statement: {:?}", statement);
266 block_ctx.translate_statement(source_scopes, statement)?;
267 }
268
269 let terminator = block.terminator.as_ref().unwrap();
271 let terminator = block_ctx.translate_terminator(source_scopes, terminator)?;
272
273 Ok(BlockData {
274 statements: block_ctx.statements,
275 terminator,
276 })
277 }
278
279 fn translate_body_comments(
281 &mut self,
282 source_text: &Option<String>,
283 charon_span: Span,
284 ) -> Vec<(usize, Vec<String>)> {
285 if let Some(body_text) = source_text {
286 let mut comments = body_text
287 .lines()
288 .rev()
290 .enumerate()
291 .filter_map(|(i, line)| Some((charon_span.data.end.line.checked_sub(i)?, line)))
293 .map(|(line_nbr, line)| (line_nbr, line.trim_start().strip_prefix("//")))
295 .peekable()
296 .batching(|iter| {
297 let (line_nbr, _first) = iter.next()?;
300 let mut comments = iter
302 .peeking_take_while(|(_, opt_comment)| opt_comment.is_some())
305 .map(|(_, opt_comment)| opt_comment.unwrap())
306 .map(|s| s.strip_prefix(" ").unwrap_or(s))
307 .map(str::to_owned)
308 .collect_vec();
309 comments.reverse();
310 Some((line_nbr, comments))
311 })
312 .filter(|(_, comments)| !comments.is_empty())
313 .collect_vec();
314 comments.reverse();
315 comments
316 } else {
317 Vec::new()
318 }
319 }
320
321 fn translate_body(
322 mut self,
323 mir_body: &mir::Body<'tcx>,
324 source_text: &Option<String>,
325 ) -> Result<Body, Error> {
326 let span = self.translate_span(&mir_body.span);
328
329 trace!("Translating the body locals");
331 self.locals.arg_count = mir_body.arg_count;
332 self.translate_body_locals(mir_body)?;
333
334 trace!("Translating the expression body");
336
337 let id = self.translate_basic_block_id(rustc_index::Idx::new(mir::START_BLOCK.as_usize()));
339 assert!(id == START_BLOCK_ID);
340
341 while let Some(mir_block_id) = self.blocks_stack.pop_front() {
343 let mir_block = mir_body.basic_blocks.get(mir_block_id).unwrap();
344 let block_id = self.translate_basic_block_id(mir_block_id);
345 let block = self.translate_basic_block(&mir_body.source_scopes, mir_block)?;
346 self.blocks.set_slot(block_id, block);
347 }
348
349 let comments = self.translate_body_comments(source_text, span);
351 Ok(Body::Unstructured(ExprBody {
352 span,
353 locals: self.locals,
354 bound_body_regions: self.i_ctx.lifetime_freshener.take().unwrap().slot_count(),
355 body: self.blocks.make_contiguous(),
356 comments,
357 }))
358 }
359}
360
361impl<'tcx> BlockTransCtx<'tcx, '_, '_, '_> {
362 fn translate_binaryop_kind(&mut self, _span: Span, binop: mir::BinOp) -> Result<BinOp, Error> {
363 Ok(match binop {
364 mir::BinOp::BitXor => BinOp::BitXor,
365 mir::BinOp::BitAnd => BinOp::BitAnd,
366 mir::BinOp::BitOr => BinOp::BitOr,
367 mir::BinOp::Eq => BinOp::Eq,
368 mir::BinOp::Lt => BinOp::Lt,
369 mir::BinOp::Le => BinOp::Le,
370 mir::BinOp::Ne => BinOp::Ne,
371 mir::BinOp::Ge => BinOp::Ge,
372 mir::BinOp::Gt => BinOp::Gt,
373 mir::BinOp::Add => BinOp::Add(OverflowMode::Wrap),
374 mir::BinOp::AddUnchecked => BinOp::Add(OverflowMode::UB),
375 mir::BinOp::Sub => BinOp::Sub(OverflowMode::Wrap),
376 mir::BinOp::SubUnchecked => BinOp::Sub(OverflowMode::UB),
377 mir::BinOp::Mul => BinOp::Mul(OverflowMode::Wrap),
378 mir::BinOp::MulUnchecked => BinOp::Mul(OverflowMode::UB),
379 mir::BinOp::Div => BinOp::Div(OverflowMode::UB),
380 mir::BinOp::Rem => BinOp::Rem(OverflowMode::UB),
381 mir::BinOp::AddWithOverflow => BinOp::AddChecked,
382 mir::BinOp::SubWithOverflow => BinOp::SubChecked,
383 mir::BinOp::MulWithOverflow => BinOp::MulChecked,
384 mir::BinOp::Shl => BinOp::Shl(OverflowMode::Wrap),
385 mir::BinOp::ShlUnchecked => BinOp::Shl(OverflowMode::UB),
386 mir::BinOp::Shr => BinOp::Shr(OverflowMode::Wrap),
387 mir::BinOp::ShrUnchecked => BinOp::Shr(OverflowMode::UB),
388 mir::BinOp::Cmp => BinOp::Cmp,
389 mir::BinOp::Offset => BinOp::Offset,
390 })
391 }
392
393 fn translate_place(
394 &mut self,
395 span: Span,
396 mir_place: &mir::Place<'tcx>,
397 ) -> Result<Place, Error> {
398 use crate::hax::{HasBase, SInto};
399 use rustc_middle::ty;
400
401 let tcx = self.hax_state.base().tcx;
402 let local_decls = self.local_decls;
403 let ptr_size = self.translated.the_target_information().target_pointer_size;
404
405 let mut place_ty: mir::PlaceTy = mir::Place::from(mir_place.local).ty(local_decls, tcx);
406 let var_id = self.translate_local(&mir_place.local).unwrap();
407 let mut place = self.locals.place_for_var(var_id);
408 for elem in mir_place.projection.as_slice() {
409 use mir::ProjectionElem::*;
410 if let TyKind::Error(msg) = place.ty().kind() {
411 return Err(Error {
412 span,
413 msg: msg.clone(),
414 });
415 }
416 let projected_place_ty = place_ty.projection_ty(tcx, *elem);
417 let next_place_ty = projected_place_ty.ty.sinto(&self.hax_state);
418 let next_place_ty = self.translate_ty(span, &next_place_ty)?;
419 let proj_elem = match elem {
420 Deref => ProjectionElem::Deref,
421 Field(index, _) => {
422 let TyKind::Adt(tref) = place.ty().kind() else {
423 raise_error!(
424 self,
425 span,
426 "found unexpected type in field projection: {}",
427 next_place_ty.with_ctx(&self.into_fmt())
428 )
429 };
430 let field_id = translate_field_id(*index);
431 match place_ty.ty.kind() {
432 ty::Adt(adt_def, _) => {
433 let variant = place_ty.variant_index;
434 let variant_id = variant.map(translate_variant_id);
435 let generics = &tref.generics;
436 match tref.id {
437 TypeId::Adt(type_id) => {
438 assert!(
439 ((adt_def.is_struct() || adt_def.is_union())
440 && variant.is_none())
441 || (adt_def.is_enum() && variant.is_some())
442 );
443 let field_proj = FieldProjKind::Adt(type_id, variant_id);
444 ProjectionElem::Field(field_proj, field_id)
445 }
446 TypeId::Tuple => {
447 assert!(generics.regions.is_empty());
448 assert!(variant.is_none());
449 assert!(generics.const_generics.is_empty());
450 let field_proj = FieldProjKind::Tuple(generics.types.len());
451 ProjectionElem::Field(field_proj, field_id)
452 }
453 TypeId::Builtin(BuiltinTy::Box) => {
454 assert!(generics.regions.is_empty());
456 assert!(generics.types.len() == 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.len());
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.translated.the_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 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 }
1318
1319 fn translate_assert_kind(
1320 &mut self,
1321 span: Span,
1322 kind: &mir::AssertKind<mir::Operand<'tcx>>,
1323 ) -> Result<BuiltinAssertKind, Error> {
1324 match kind {
1325 mir::AssertKind::BoundsCheck { len, index } => {
1326 let len = self.translate_operand(span, len)?;
1327 let index = self.translate_operand(span, index)?;
1328 Ok(BuiltinAssertKind::BoundsCheck { len, index })
1329 }
1330 mir::AssertKind::Overflow(binop, left, right) => {
1331 let binop = self.translate_binaryop_kind(span, *binop)?;
1332 let left = self.translate_operand(span, left)?;
1333 let right = self.translate_operand(span, right)?;
1334 Ok(BuiltinAssertKind::Overflow(binop, left, right))
1335 }
1336 mir::AssertKind::OverflowNeg(operand) => {
1337 let operand = self.translate_operand(span, operand)?;
1338 Ok(BuiltinAssertKind::OverflowNeg(operand))
1339 }
1340 mir::AssertKind::DivisionByZero(operand) => {
1341 let operand = self.translate_operand(span, operand)?;
1342 Ok(BuiltinAssertKind::DivisionByZero(operand))
1343 }
1344 mir::AssertKind::RemainderByZero(operand) => {
1345 let operand = self.translate_operand(span, operand)?;
1346 Ok(BuiltinAssertKind::RemainderByZero(operand))
1347 }
1348 mir::AssertKind::MisalignedPointerDereference { required, found } => {
1349 let required = self.translate_operand(span, required)?;
1350 let found = self.translate_operand(span, found)?;
1351 Ok(BuiltinAssertKind::MisalignedPointerDereference { required, found })
1352 }
1353 mir::AssertKind::NullPointerDereference => {
1354 Ok(BuiltinAssertKind::NullPointerDereference)
1355 }
1356 mir::AssertKind::InvalidEnumConstruction(operand) => {
1357 let operand = self.translate_operand(span, operand)?;
1358 Ok(BuiltinAssertKind::InvalidEnumConstruction(operand))
1359 }
1360 mir::AssertKind::ResumedAfterDrop(..)
1361 | mir::AssertKind::ResumedAfterPanic(..)
1362 | mir::AssertKind::ResumedAfterReturn(..) => {
1363 raise_error!(self, span, "Coroutines are not supported");
1364 }
1365 }
1366 }
1367
1368 fn translate_arguments(
1371 &mut self,
1372 span: Span,
1373 args: &[hax::Spanned<mir::Operand<'tcx>>],
1374 ) -> Result<Vec<Operand>, Error> {
1375 let mut t_args: Vec<Operand> = Vec::new();
1376 for arg in args.iter().map(|x| &x.node) {
1377 let op = self.translate_operand(span, arg)?;
1379 t_args.push(op);
1380 }
1381 Ok(t_args)
1382 }
1383}
1384
1385impl<'a> IntoFormatter for &'a BodyTransCtx<'_, '_, '_> {
1386 type C = FmtCtx<'a>;
1387 fn into_fmt(self) -> Self::C {
1388 FmtCtx {
1389 locals: Some(&self.locals),
1390 ..self.i_ctx.into_fmt()
1391 }
1392 }
1393}