1use itertools::Itertools;
7use rustc_attr_ir::LangItem;
8use rustc_hash::FxHashMap as HashMap;
9use std::collections::VecDeque;
10use std::mem;
11use std::ops::Deref;
12use std::ops::DerefMut;
13use std::panic;
14use std::rc::Rc;
15
16use crate::hax;
17use rustc_middle::mir;
18use rustc_middle::ty;
19use rustc_span::{Symbol, sym};
20
21use super::translate_crate::*;
22use super::translate_ctx::*;
23use charon_lib::formatter::{FmtCtx, IntoFormatter, compute_local_names};
24use charon_lib::name_matcher::NamePattern;
25use charon_lib::options::TranslateOptions;
26use charon_lib::pretty::FmtWithCtx;
27use charon_lib::transform::ctx::BodyTransformCtx;
28use charon_lib::ullbc_ast::*;
29
30pub(crate) struct BodyTransCtx<'tcx, 'tctx, 'ictx> {
32 pub i_ctx: &'ictx mut ItemTransCtx<'tcx, 'tctx>,
34 pub local_decls: &'ictx rustc_index::IndexVec<mir::Local, mir::LocalDecl<'tcx>>,
36 pub user_type_annotations: ty::CanonicalUserTypeAnnotations<'tcx>,
38
39 pub drop_kind: DropKind,
41 pub locals: Locals,
43 pub locals_map: HashMap<usize, LocalId>,
45 pub blocks: IndexMap<BlockId, BlockData>,
47 pub blocks_map: HashMap<mir::BasicBlock, BlockId>,
51 pub blocks_stack: VecDeque<mir::BasicBlock>,
55}
56
57impl<'tcx, 'tctx, 'ictx> BodyTransCtx<'tcx, 'tctx, 'ictx> {
58 pub(crate) fn new(
59 i_ctx: &'ictx mut ItemTransCtx<'tcx, 'tctx>,
60 body: &'ictx Rc<mir::Body<'tcx>>,
61 drop_kind: DropKind,
62 ) -> Self {
63 i_ctx.lifetime_freshener = (!i_ctx.options.erase_body_lifetimes).then(IndexMap::new);
64 let mut user_type_annotations = body.user_type_annotations.clone();
65 if let RustcItem::Mono(item) = &i_ctx.item_src.item {
66 let item = item.clone();
69 let args = item.rustc_args(i_ctx.hax_state_with_id());
70 for annotation in &mut user_type_annotations {
71 annotation.user_ty.value = hax::substitute(
72 i_ctx.tcx,
73 hax::UnderOwnerState::typing_env(&i_ctx.hax_state),
74 Some(args),
75 annotation.user_ty.value,
76 );
77 }
78 }
79 BodyTransCtx {
80 i_ctx,
81 local_decls: &body.local_decls,
82 user_type_annotations,
83 drop_kind,
84 locals: Default::default(),
85 locals_map: Default::default(),
86 blocks: Default::default(),
87 blocks_map: Default::default(),
88 blocks_stack: Default::default(),
89 }
90 }
91}
92
93impl<'tcx, 'tctx, 'ictx> Deref for BodyTransCtx<'tcx, 'tctx, 'ictx> {
94 type Target = ItemTransCtx<'tcx, 'tctx>;
95 fn deref(&self) -> &Self::Target {
96 self.i_ctx
97 }
98}
99impl<'tcx, 'tctx, 'ictx> DerefMut for BodyTransCtx<'tcx, 'tctx, 'ictx> {
100 fn deref_mut(&mut self) -> &mut Self::Target {
101 self.i_ctx
102 }
103}
104
105pub(crate) struct BlockTransCtx<'tcx, 'tctx, 'ictx, 'bctx> {
107 pub b_ctx: &'bctx mut BodyTransCtx<'tcx, 'tctx, 'ictx>,
109 pub current_block: BlockId,
111 pub is_cleanup: bool,
113 pub span: Span,
115 pub statements: Vec<Statement>,
117}
118
119impl<'tcx, 'tctx, 'ictx, 'bctx> BlockTransCtx<'tcx, 'tctx, 'ictx, 'bctx> {
120 pub(crate) fn new(
121 b_ctx: &'bctx mut BodyTransCtx<'tcx, 'tctx, 'ictx>,
122 current_block: BlockId,
123 is_cleanup: bool,
124 ) -> Self {
125 BlockTransCtx {
126 b_ctx,
127 current_block,
128 is_cleanup,
129 span: Span::dummy(),
130 statements: Vec::new(),
131 }
132 }
133
134 fn finish_current_block(self, terminator: Terminator) {
135 let block = BlockData {
136 statements: self.statements,
137 terminator,
138 is_cleanup: self.is_cleanup,
139 };
140 self.b_ctx.blocks.set_slot(self.current_block, block);
141 }
142
143 fn push_nounwind_call(&mut self, span: Span, call: Call) {
145 let target = self.blocks.reserve_slot();
146 let on_unwind = self
147 .blocks
148 .push(Terminator::new(span, TerminatorKind::UndefinedBehavior).into_block(true));
149 let block = BlockData {
150 statements: mem::take(&mut self.statements),
151 terminator: Terminator::new(
152 span,
153 TerminatorKind::Call {
154 call,
155 target,
156 on_unwind,
157 },
158 ),
159 is_cleanup: self.is_cleanup,
160 };
161 let current_block = mem::replace(&mut self.current_block, target);
162 self.blocks.set_slot(current_block, block);
163 }
164}
165
166impl<'tcx, 'tctx, 'ictx, 'bctx> Deref for BlockTransCtx<'tcx, 'tctx, 'ictx, 'bctx> {
167 type Target = BodyTransCtx<'tcx, 'tctx, 'ictx>;
168 fn deref(&self) -> &Self::Target {
169 self.b_ctx
170 }
171}
172impl<'tcx, 'tctx, 'ictx, 'bctx> DerefMut for BlockTransCtx<'tcx, 'tctx, 'ictx, 'bctx> {
173 fn deref_mut(&mut self) -> &mut Self::Target {
174 self.b_ctx
175 }
176}
177
178impl<'tcx> TranslateCtx<'tcx> {
179 pub fn translate_variant_id(&self, id: hax::VariantIdx) -> VariantId {
180 VariantId::new(id.as_usize())
181 }
182
183 pub fn translate_field_id(&self, id: hax::FieldIdx) -> FieldId {
184 FieldId::new(id.index())
185 }
186
187 fn translate_borrow_kind(&self, borrow_kind: mir::BorrowKind) -> BorrowKind {
188 match borrow_kind {
189 mir::BorrowKind::Shared => BorrowKind::Shared,
190 mir::BorrowKind::Mut { kind } => match kind {
191 mir::MutBorrowKind::Default => BorrowKind::Mut,
192 mir::MutBorrowKind::TwoPhaseBorrow => BorrowKind::TwoPhaseMut,
193 mir::MutBorrowKind::ClosureCapture => BorrowKind::UniqueImmutable,
194 },
195 mir::BorrowKind::Fake(mir::FakeBorrowKind::Shallow) => BorrowKind::Shallow,
196 mir::BorrowKind::Fake(mir::FakeBorrowKind::Deep) => unimplemented!(),
198 }
199 }
200}
201
202impl<'tcx> ItemTransCtx<'tcx, '_> {
203 pub fn translate_def_body(&mut self, span: Span, def: &hax::FullDef<'tcx>) -> Body {
206 match self.translate_def_body_inner(span, def) {
207 Ok(body) => body,
208 Err(e) => Body::Error(e),
209 }
210 }
211
212 fn translate_def_body_inner(
213 &mut self,
214 span: Span,
215 def: &hax::FullDef<'tcx>,
216 ) -> Result<Body, Error> {
217 if let Some(body) = self.get_mir(def.this(), span)? {
219 Ok(self.translate_body(span, body, &def.source_text))
220 } else if let Some(value) = self.evaluate_const_def(def) {
221 let c = self.translate_constant_expr(span, &value)?;
225 let mut bb = BodyBuilder::new(span, 0);
226 let ret = bb.new_var(None, c.ty().clone());
227 bb.push_statement(StatementKind::Assign(
228 ret,
229 Rvalue::Use(Operand::Const(c), WithRetag::No),
230 ));
231 Ok(Body::Unstructured(bb.build()))
232 } else {
233 Ok(Body::Missing)
234 }
235 }
236
237 pub fn translate_body(
240 &mut self,
241 span: Span,
242 body: mir::Body<'tcx>,
243 source_text: &Option<String>,
244 ) -> Body {
245 let _guard = charon_lib::timing::scope("translate-body");
246 let drop_kind = match body.phase {
247 mir::MirPhase::Built | mir::MirPhase::Analysis(..) => DropKind::Conditional,
248 mir::MirPhase::Runtime(..) => DropKind::Precise,
249 };
250 let mut ctx = panic::AssertUnwindSafe(&mut *self);
251 let body = panic::AssertUnwindSafe(body);
252 let res = panic::catch_unwind(move || {
254 let body = Rc::new({ body }.0);
255 let ctx = BodyTransCtx::new(*ctx, &body, drop_kind);
256 ctx.translate_body(&body, source_text)
257 });
258 match res {
259 Ok(Ok(body)) => body,
260 Ok(Err(e)) => Body::Error(e),
262 Err(_) => {
264 let e = register_error!(self, span, "Thread panicked when extracting body.");
265 Body::Error(e)
266 }
267 }
268 }
269
270 pub(crate) fn translate_unsizing_metadata(
271 &mut self,
272 span: Span,
273 meta: &hax::UnsizingMetadata,
274 ) -> Result<UnsizingMetadata, Error> {
275 Ok(match meta {
276 hax::UnsizingMetadata::Length(len) => {
277 let len = self.translate_constant_expr(span, len)?;
278 UnsizingMetadata::Length(len)
279 }
280 hax::UnsizingMetadata::DirectVTable(trait_proof) => {
281 let tref = self.translate_trait_proof(span, trait_proof)?;
282 let vtable = self.translate_vtable_instance_const(span, trait_proof)?;
283 UnsizingMetadata::VTable(tref, vtable)
284 }
285 hax::UnsizingMetadata::NestedVTable(dyn_trait_proof) => {
286 let binder =
288 self.translate_dyn_binder(span, dyn_trait_proof, |ctx, _, trait_proof| {
289 ctx.translate_trait_proof(span, trait_proof)
290 })?;
291
292 let mut target_tref = &binder.skip_binder;
295 let mut clause_path: Vec<(TraitDeclId, TraitClauseId)> = vec![];
296 while let TraitRefKind::ParentClause(tref, id) = &target_tref.kind {
297 clause_path.push((tref.trait_decl_ref.skip_binder.id, *id));
298 target_tref = tref;
299 }
300
301 let mut field_path = vec![];
302 for &(trait_id, clause_id) in &clause_path {
303 if let Ok(ItemRef::TraitDecl(tdecl)) = self.get_or_translate(trait_id.into())
304 && let vtable_decl_id = tdecl.vtable.as_ref().unwrap().id
305 && let Ok(ItemRef::Type(vtable_decl)) =
306 self.get_or_translate(vtable_decl_id.into())
307 {
308 let TypeSource::VTable { supertrait_map, .. } = &vtable_decl.src else {
309 unreachable!()
310 };
311 field_path.push(supertrait_map[clause_id].unwrap());
312 } else {
313 break;
314 }
315 }
316
317 if field_path.len() == clause_path.len() {
318 UnsizingMetadata::VTableUpcast(field_path)
319 } else {
320 UnsizingMetadata::Unknown
321 }
322 }
323 hax::UnsizingMetadata::Unknown => UnsizingMetadata::Unknown,
324 })
325 }
326
327 pub(crate) fn build_ctor_body(
329 &mut self,
330 span: Span,
331 def: &hax::FullDef<'tcx>,
332 ) -> Result<Body, Error> {
333 let hax::FullDefKind::Ctor(ctor) = def.kind() else {
334 unreachable!()
335 };
336 let tref = self.translate_type_decl_ref(
337 span,
338 &def.this().with_def_id(self.hax_state(), ctor.adt_def_id()),
339 )?;
340 let output_ty = self.translate_ty(span, ctor.output_ty())?;
341
342 let mut builder = BodyBuilder::new(span, ctor.fields().len());
343 let return_place = builder.new_var(None, output_ty);
344 let args: Vec<_> = ctor
345 .fields()
346 .iter()
347 .map(|field| -> Result<Operand, Error> {
348 let ty = self.translate_ty(span, &field.ty)?;
349 let place = builder.new_var(None, ty);
350 Ok(Operand::Move(place))
351 })
352 .try_collect()?;
353 let variant = match ctor.ctor_of() {
354 hax::CtorOf::Struct => None,
355 hax::CtorOf::Variant => Some(self.translate_variant_id(ctor.variant_id())),
356 };
357 builder.push_statement(StatementKind::Assign(
358 return_place,
359 Rvalue::Aggregate(AggregateKind::Adt(tref, variant, None), args),
360 ));
361 Ok(Body::Unstructured(builder.build()))
362 }
363
364 pub(crate) fn build_box_assume_init_into_vec_unsafe(
367 &mut self,
368 span: Span,
369 def: &hax::FullDef<'tcx>,
370 ) -> Result<Body, Error> {
371 let tcx = self.tcx;
379 let hax::FullDefKind::Fn(f) = def.kind() else {
380 unreachable!()
381 };
382 let hax_sig = f.sig().hax_skip_binder_ref();
383 let sig = self.translate_fun_sig(span, hax_sig)?;
384
385 let (array_rust_ty, alloc_rust_ty) = {
387 let input_box_rust_args = {
388 let hax::TyKind::Adt(input_box_item) = hax_sig.inputs[0].kind() else {
389 raise_error!(self, span, "expected a boxed input in the hax signature");
390 };
391 input_box_item.rustc_args(self.hax_state_with_id())
392 };
393 let maybe_uninit_array_rust_ty = input_box_rust_args[0].as_type().unwrap();
394 let alloc_rust_ty = input_box_rust_args[1].as_type().unwrap();
395 let ty::Adt(_, maybe_uninit_rust_args) = maybe_uninit_array_rust_ty.kind() else {
396 raise_error!(
397 self,
398 span,
399 "expected `MaybeUninit<[T; N]>` in the hax signature"
400 );
401 };
402 let Some(array_rust_ty) = maybe_uninit_rust_args[0].as_type() else {
403 raise_error!(
404 self,
405 span,
406 "expected the first `MaybeUninit` parameter to be a type"
407 );
408 };
409 (array_rust_ty, alloc_rust_ty)
410 };
411 let elem_rust_ty = array_rust_ty.builtin_index().unwrap();
413 let slice_rust_ty = ty::Ty::new_slice(tcx, elem_rust_ty);
415 let box_array_rust_ty = ty::Ty::new_box(tcx, array_rust_ty);
417 let box_array_ty = self.translate_rustc_ty(span, &box_array_rust_ty)?;
418 let box_slice_rust_ty = ty::Ty::new_box(tcx, slice_rust_ty);
420 let box_slice_ty = self.translate_rustc_ty(span, &box_slice_rust_ty)?;
421
422 if !self.monomorphize() {
423 let path = NamePattern::parse(names::BOX_NEW).unwrap();
425 let box_new_def_id = self.resolve_single_path(span, &path)?;
426 let box_new_args = tcx.mk_args(&[array_rust_ty.into()]);
427 let box_new_item =
428 hax::ItemRef::translate(self.hax_state_with_id(), box_new_def_id, box_new_args);
429 let _ = self.translate_fn_ptr(span, &box_new_item, TransItemSourceKind::Fun)?;
430
431 let path = NamePattern::parse(names::BOX_WRITE).unwrap();
432 let box_write_def_id = self.resolve_single_path(span, &path)?;
433 let box_write_args = tcx.mk_args(&[array_rust_ty.into(), alloc_rust_ty.into()]);
434 let box_write_item =
435 hax::ItemRef::translate(self.hax_state_with_id(), box_write_def_id, box_write_args);
436 let _ = self.translate_fn_ptr(span, &box_write_item, TransItemSourceKind::Fun)?;
437 }
438
439 let body = {
440 let mut builder = BodyBuilder::new(span, sig.inputs.len());
441 let return_place = builder.new_var(Some("ret".to_string()), sig.output.clone());
442 let input = builder.new_var(Some("b".to_string()), sig.inputs[0].clone());
443 let initialized_box = builder.new_var(Some("x".to_string()), box_array_ty.clone());
444 let box_slice = builder.new_var(Some("y".to_string()), box_slice_ty.clone());
445
446 builder.call({
447 let assume_init_fn = {
448 let path = NamePattern::parse("alloc::boxed::Box::assume_init").unwrap();
449 let assume_init_def_id = self
450 .resolve_path(span, &path, true)?
451 .into_iter()
452 .filter(|&def_id| {
454 let sig = self.tcx.fn_sig(def_id);
455 !sig.skip_binder().inputs().skip_binder()[0]
456 .expect_boxed_ty()
457 .is_slice()
458 })
459 .exactly_one()
460 .unwrap();
461 let assume_init_args =
462 tcx.mk_args(&[array_rust_ty.into(), alloc_rust_ty.into()]);
463 let assume_init_item = hax::ItemRef::translate(
464 self.hax_state_with_id(),
465 assume_init_def_id,
466 assume_init_args,
467 );
468 self.translate_fn_ptr(span, &assume_init_item, TransItemSourceKind::Fun)?
469 };
470 Call {
471 func: FnOperand::Regular(assume_init_fn),
472 args: vec![Operand::Move(input)],
473 dest: initialized_box.clone(),
474 safety: CallSafety::Inherit,
475 }
476 });
477
478 builder.push_statement({
479 let meta = hax::compute_unsizing_metadata(
480 &self.hax_state,
481 box_array_rust_ty,
482 box_slice_rust_ty,
483 );
484 let meta = self.translate_unsizing_metadata(span, &meta)?;
485 StatementKind::Assign(
486 box_slice.clone(),
487 Rvalue::UnaryOp(
488 UnOp::Cast(CastKind::Unsize(box_array_ty, box_slice_ty, meta)),
489 Operand::Move(initialized_box),
490 ),
491 )
492 });
493
494 builder.call({
495 let into_vec_fn = {
496 let path = NamePattern::parse("slice::into_vec").unwrap();
497 let into_vec_def_id = self.resolve_single_path(span, &path)?;
498 let into_vec_args = tcx.mk_args(&[elem_rust_ty.into(), alloc_rust_ty.into()]);
499 let into_vec_item = hax::ItemRef::translate(
500 self.hax_state_with_id(),
501 into_vec_def_id,
502 into_vec_args,
503 );
504 self.translate_fn_ptr(span, &into_vec_item, TransItemSourceKind::Fun)?
505 };
506 Call {
507 func: FnOperand::Regular(into_vec_fn),
508 args: vec![Operand::Move(box_slice)],
509 dest: return_place,
510 safety: CallSafety::Inherit,
511 }
512 });
513 builder.build()
514 };
515
516 Ok(Body::Unstructured(body))
517 }
518
519 pub(crate) fn build_type_id_body(
521 &mut self,
522 span: Span,
523 def: &hax::FullDef<'tcx>,
524 signature: &FunSig,
525 ) -> Result<Body, Error> {
526 let generics = self.translate_generic_args(span, &def.this().generic_args, &[])?;
527 let type_id_ty = generics.types[0].clone();
528
529 let mut builder = BodyBuilder::new(span, signature.inputs.len());
530 let return_place = builder.new_var(Some("ret".to_string()), signature.output.clone());
531 let type_id = ConstantExpr::new(
532 ConstantExprKind::TypeId(type_id_ty),
533 signature.output.clone(),
534 );
535 builder.push_statement(StatementKind::Assign(
536 return_place,
537 Rvalue::Use(Operand::Const(type_id), WithRetag::No),
538 ));
539 Ok(Body::Unstructured(builder.build()))
540 }
541
542 pub(crate) fn build_drop_glue_body(
544 &mut self,
545 span: Span,
546 def: &hax::FullDef<'tcx>,
547 signature: &FunSig,
548 ) -> Result<Body, Error> {
549 let hax::FullDefKind::Fn(_) = def.kind() else {
550 unreachable!()
551 };
552 let def_id = def.def_id().as_real_def_id().unwrap();
553 let rustc_args = def.this().rustc_args(self.hax_state_with_id());
554 let rustc_sig = self.tcx.fn_sig(def_id).instantiate(self.tcx, rustc_args);
555 let input_ty = rustc_sig.skip_binder().inputs()[0];
557 let pointee_ty = input_ty
558 .builtin_deref(true)
559 .expect("`drop_glue` argument is not a pointer");
560 let fn_ptr = self.translate_drop_glue_method_call(span, pointee_ty)?;
561
562 let mut builder = BodyBuilder::new(span, signature.inputs.len());
563 let _return_place = builder.new_var(Some("ret".to_string()), signature.output.clone());
564 let input = builder.new_var(None, signature.inputs[0].clone());
565 builder.insert_drop(input.deref(), fn_ptr);
566 Ok(Body::Unstructured(builder.build()))
567 }
568}
569
570impl<'tcx> BodyTransCtx<'tcx, '_, '_> {
571 pub(crate) fn translate_local(&self, local: &mir::Local) -> Option<LocalId> {
572 self.locals_map.get(&local.index()).copied()
573 }
574
575 pub(crate) fn push_var(&mut self, rid: mir::Local, ty: Ty, name: Option<String>, span: Span) {
576 let local_id = self.locals.locals.push_with(|index| Local {
577 index,
578 name,
579 span,
580 ty,
581 drop_flag_for: None,
582 });
583 self.locals_map.insert(rid.as_usize(), local_id);
584 }
585
586 fn translate_body_locals(&mut self, body: &mir::Body<'tcx>) -> Result<(), Error> {
588 for (index, var) in body.local_decls.iter_enumerated() {
590 let name: Option<String> = hax::name_of_local(index, &body.var_debug_info);
592
593 let span = self.translate_span(&var.source_info.span);
595 let ty = self.translate_rustc_ty(span, &var.ty)?;
596
597 self.push_var(index, ty, name, span);
599 }
600
601 Ok(())
602 }
603
604 fn translate_basic_block_id(&mut self, block_id: mir::BasicBlock) -> BlockId {
606 match self.blocks_map.get(&block_id) {
607 Some(id) => *id,
608 None => {
610 self.blocks_stack.push_back(block_id);
612 let id = self.blocks.reserve_slot();
613 self.blocks_map.insert(block_id, id);
615 id
616 }
617 }
618 }
619
620 fn translate_basic_block(
621 &mut self,
622 block_id: BlockId,
623 source_scopes: &rustc_index::IndexVec<mir::SourceScope, mir::SourceScopeData>,
624 block: &mir::BasicBlockData<'tcx>,
625 ) -> Result<(), Error> {
626 let mut block_ctx = BlockTransCtx::new(self, block_id, block.is_cleanup);
628 for statement in &block.statements {
629 trace!("statement: {:?}", statement);
630 block_ctx.translate_statement(source_scopes, statement)?;
631 }
632
633 let terminator = block.terminator.as_ref().unwrap();
635 block_ctx.translate_terminator(source_scopes, terminator)?;
636
637 Ok(())
638 }
639
640 fn translate_body_comments(
642 &mut self,
643 source_text: &Option<String>,
644 charon_span: Span,
645 ) -> Vec<(u32, Vec<String>)> {
646 if let Some(body_text) = source_text {
647 let mut comments = body_text
648 .lines()
649 .rev()
651 .enumerate()
652 .filter_map(|(i, line)| {
654 Some(((charon_span.data().end.line).checked_sub(i as u32)?, line))
655 })
656 .map(|(line_nbr, line)| (line_nbr, line.trim_start().strip_prefix("//")))
658 .peekable()
659 .batching(|iter| {
660 let (line_nbr, _first) = iter.next()?;
663 let mut comments = iter
665 .peeking_take_while(|(_, opt_comment)| opt_comment.is_some())
668 .map(|(_, opt_comment)| opt_comment.unwrap())
669 .map(|s| s.strip_prefix(" ").unwrap_or(s))
670 .map(str::to_owned)
671 .collect_vec();
672 comments.reverse();
673 Some((line_nbr, comments))
674 })
675 .filter(|(_, comments)| !comments.is_empty())
676 .collect_vec();
677 comments.reverse();
678 comments
679 } else {
680 Vec::new()
681 }
682 }
683
684 fn translate_body(
685 mut self,
686 mir_body: &mir::Body<'tcx>,
687 source_text: &Option<String>,
688 ) -> Result<Body, Error> {
689 let span = self.translate_span(&mir_body.span);
691
692 trace!("Translating the body locals");
694 self.locals.arg_count = mir_body.arg_count;
695 self.translate_body_locals(mir_body)?;
696
697 trace!("Translating the expression body");
699
700 let id = self.translate_basic_block_id(rustc_index::Idx::new(mir::START_BLOCK.as_usize()));
702 assert!(id == START_BLOCK_ID);
703
704 while let Some(mir_block_id) = self.blocks_stack.pop_front() {
706 let mir_block = mir_body.basic_blocks.get(mir_block_id).unwrap();
707 let block_id = self.translate_basic_block_id(mir_block_id);
708 self.translate_basic_block(block_id, &mir_body.source_scopes, mir_block)?;
709 }
710
711 let comments = self.translate_body_comments(source_text, span);
713 Ok(Body::Unstructured(ExprBody {
714 span,
715 locals: self.locals,
716 bound_body_regions: self
717 .i_ctx
718 .lifetime_freshener
719 .take()
720 .map_or(0, |v| v.slot_count()),
721 body: self.blocks.make_contiguous(),
722 comments,
723 }))
724 }
725}
726
727impl BodyTransformCtx for BlockTransCtx<'_, '_, '_, '_> {
728 fn get_crate(&self) -> &TranslatedCrate {
729 &self.translated
730 }
731
732 fn get_options(&self) -> &TranslateOptions {
733 &self.options
734 }
735
736 fn get_params(&self) -> &GenericParams {
737 self.outermost_generics()
738 }
739
740 fn get_locals_mut(&mut self) -> &mut Locals {
741 &mut self.locals
742 }
743
744 fn insert_storage_live_stmt(&mut self, local: LocalId) {
745 self.statements
746 .push(Statement::new(self.span, StatementKind::StorageLive(local)));
747 }
748
749 fn insert_storage_dead_stmt(&mut self, local: LocalId) {
750 self.statements
751 .push(Statement::new(self.span, StatementKind::StorageDead(local)));
752 }
753
754 fn insert_assn_stmt(&mut self, place: Place, rvalue: Rvalue) {
755 self.statements.push(Statement::new(
756 self.span,
757 StatementKind::Assign(place, rvalue),
758 ));
759 }
760}
761
762impl<'tcx> BlockTransCtx<'tcx, '_, '_, '_> {
763 fn missing_ptr_metadata() -> Operand {
764 Operand::Const(ConstantExpr::new(
765 ConstantExprKind::Opaque("Missing metadata".to_string()),
766 Ty::mk_unit(),
767 ))
768 }
769
770 fn try_reconstruct_array_repeat(
773 &mut self,
774 span: Span,
775 array_ty: &hax::Ty,
776 fields: impl ExactSizeIterator<Item = ConstantExpr>,
777 ) -> Result<Option<Rvalue>, Error> {
778 if fields.len() >= 2
779 && let Ok(field) = fields.dedup().exactly_one()
780 {
781 let hax::TyKind::Array(item_ref) = array_ty.kind() else {
782 panic!("expected an array type")
783 };
784 let translated_array_ty = self.translate_ty(span, array_ty)?;
785 let TyKind::Array(elem_ty, len, _) = translated_array_ty.kind() else {
786 unreachable!()
787 };
788 let rust_elem_ty = item_ref.rustc_args(&self.hax_state).type_at(0);
789 let Some(copy_proof) = hax::solve_copy(&self.hax_state, rust_elem_ty) else {
790 return Ok(None);
791 };
792 let ty_is_copy = self.translate_trait_proof(span, ©_proof)?;
793 Ok(Some(Rvalue::Repeat(
794 Operand::Const(field),
795 elem_ty.clone(),
796 len.clone(),
797 Some(ty_is_copy),
798 )))
799 } else {
800 Ok(None)
801 }
802 }
803
804 fn apply_user_type_projection(
805 &mut self,
806 span: Span,
807 mut ty: Ty,
808 projections: &[mir::ProjectionElem<(), ()>],
809 ) -> Result<Ty, Error> {
810 let mut downcast = None;
811 for projection in projections {
812 let projection = match projection {
813 mir::ProjectionElem::Deref => ProjectionElem::Deref,
814 mir::ProjectionElem::PhantomDeref => {
815 raise_error!(
816 self,
817 span,
818 "unsupported phantom dereference in user type projection"
819 );
820 }
821 mir::ProjectionElem::Field(field, ()) => {
822 let field = self.translate_field_id(*field);
823 let TyKind::Adt(type_ref) = ty.kind() else {
824 raise_error!(self, span, "field projection on unexpected type");
825 };
826 match type_ref.as_builtin() {
827 None => ProjectionElem::Field(downcast.take(), field),
828 Some(BuiltinAdt::Tuple) => ProjectionElem::Field(None, field),
829 Some(BuiltinAdt::Box) if field == FieldId::ZERO => ProjectionElem::Deref,
830 _ => raise_error!(self, span, "field projection on unexpected type"),
831 }
832 }
833 mir::ProjectionElem::Index(()) => ProjectionElem::Index {
834 offset: Box::new(Operand::mk_const_unit()),
835 from_end: false,
836 },
837 mir::ProjectionElem::ConstantIndex { from_end, .. } => ProjectionElem::Index {
838 offset: Box::new(Operand::mk_const_unit()),
839 from_end: *from_end,
840 },
841 mir::ProjectionElem::Subslice { from_end, .. } => ProjectionElem::Subslice {
842 from: Box::new(Operand::mk_const_unit()),
843 to: Box::new(Operand::mk_const_unit()),
844 from_end: *from_end,
845 },
846 mir::ProjectionElem::Downcast(_, variant) => {
847 downcast = Some(self.translate_variant_id(*variant));
848 continue;
849 }
850 mir::ProjectionElem::OpaqueCast(()) => {
851 raise_error!(self, span, "unexpected opaque cast in user type projection");
852 }
853 mir::ProjectionElem::UnwrapUnsafeBinder(()) => {
854 raise_error!(
855 self,
856 span,
857 "unsupported unsafe binder in user type projection"
858 );
859 }
860 };
861 let Some(next_ty) = projection.project_type(&self.translated, &ty) else {
862 raise_error!(self, span, "invalid user type projection");
863 };
864 ty = next_ty;
865 }
866 Ok(ty)
867 }
868
869 fn translate_user_type_projection(
870 &mut self,
871 span: Span,
872 user_ty: &mir::UserTypeProjection,
873 ) -> Result<(Ty, Vec<BorrowckStatement>), Error> {
874 use rustc_infer::infer::canonical::CanonicalExt;
875
876 let annotation = self.user_type_annotations[user_ty.base].clone();
877 let canonical = *annotation.user_ty;
878
879 let mut facts = Vec::new();
880 if !canonical.value.bounds.is_empty() {
881 let user_ty_before_inference = match canonical.value.kind {
882 ty::UserTypeKind::Ty(ty) => ty,
883 ty::UserTypeKind::TypeOf(def_id, user_args)
884 if user_args.args.len() == self.tcx.generics_of(def_id).count() =>
885 {
886 self.tcx
887 .type_of(def_id)
888 .instantiate(self.tcx, user_args.args)
889 .skip_normalization()
890 }
891 ty::UserTypeKind::TypeOf(..) => annotation.inferred_ty,
894 };
895
896 let Some(var_values) = hax::rustc::match_canonical_var_values(
900 self.tcx,
901 canonical.var_kinds,
902 user_ty_before_inference,
903 annotation.inferred_ty,
904 ) else {
905 raise_error!(
906 self,
907 span,
908 "could not match a user type annotation with its inferred type"
909 )
910 };
911 let instantiated_user_ty = canonical.instantiate(self.tcx, &var_values);
912
913 for clause in instantiated_user_ty.bounds {
914 if let Some(trait_predicate) = clause.as_trait_clause() {
915 if trait_predicate.skip_binder().polarity != ty::ClausePolarity::Positive {
916 raise_error!(self, span, "negative trait bound in a user type annotation")
917 }
918 let proof = hax::solve_trait(
919 &self.hax_state,
920 trait_predicate.map_bound(|predicate| predicate.trait_ref),
921 );
922 facts.push(BorrowckStatement::PredicateHolds(
923 self.translate_trait_proof(span, &proof)?,
924 ));
925 } else if let Some(outlives) = clause.as_type_outlives_clause() {
926 let Some(ty::OutlivesClause(outlived_ty, region)) = outlives.no_bound_vars()
927 else {
928 raise_error!(self, span, "higher-ranked outlives user type bound")
929 };
930 let outlived_ty = self.translate_rustc_ty(span, &outlived_ty)?;
931 let region = self.catch_sinto(span, ®ion)?;
932 let region = self.translate_region(span, ®ion)?;
933 facts.push(BorrowckStatement::SetOutlives(outlived_ty, region));
934 }
935 }
936 }
937
938 let ty = self.translate_rustc_ty(span, &annotation.inferred_ty)?;
941 let ty = self.apply_user_type_projection(span, ty, &user_ty.projs)?;
942
943 Ok((ty, facts))
944 }
945
946 fn translate_thread_local_ref(
947 &mut self,
948 span: Span,
949 def_id: rustc_hir::def_id::DefId,
950 ) -> Result<Rvalue, Error> {
951 let args = ty::GenericArgs::empty();
952 let item = hax::translate_item_ref(&self.hax_state, def_id, args);
953 let global_ref = self.translate_global_decl_ref(span, &item)?;
954
955 let ptr_ty = self.tcx.thread_local_ptr_ty(def_id);
956 let ty = ptr_ty.builtin_deref(true).unwrap();
957 let ty = self.translate_rustc_ty(span, &ty)?;
958 let place = Place::new_global(global_ref, ty);
959 match ptr_ty.kind() {
960 ty::TyKind::Ref(_, _, mutability) => {
961 let kind = if mutability.is_mut() {
962 BorrowKind::Mut
963 } else {
964 BorrowKind::Shared
965 };
966 Ok(Rvalue::Ref {
967 place,
968 kind,
969 ptr_metadata: Self::missing_ptr_metadata(),
971 })
972 }
973 ty::TyKind::RawPtr(_, mutability) => {
974 let kind = if mutability.is_mut() {
975 RefKind::Mut
976 } else {
977 RefKind::Shared
978 };
979 Ok(Rvalue::RawPtr {
980 place,
981 kind,
982 ptr_metadata: Self::missing_ptr_metadata(),
984 })
985 }
986 _ => raise_error!(
987 self,
988 span,
989 "unexpected type for thread-local reference: {ptr_ty:?}"
990 ),
991 }
992 }
993
994 fn translate_binaryop_kind(&mut self, _span: Span, binop: mir::BinOp) -> Result<BinOp, Error> {
995 Ok(match binop {
996 mir::BinOp::BitXor => BinOp::BitXor,
997 mir::BinOp::BitAnd => BinOp::BitAnd,
998 mir::BinOp::BitOr => BinOp::BitOr,
999 mir::BinOp::Eq => BinOp::Eq,
1000 mir::BinOp::Lt => BinOp::Lt,
1001 mir::BinOp::Le => BinOp::Le,
1002 mir::BinOp::Ne => BinOp::Ne,
1003 mir::BinOp::Ge => BinOp::Ge,
1004 mir::BinOp::Gt => BinOp::Gt,
1005 mir::BinOp::Add => BinOp::Add(OverflowMode::Wrap),
1006 mir::BinOp::AddUnchecked => BinOp::Add(OverflowMode::UB),
1007 mir::BinOp::Sub => BinOp::Sub(OverflowMode::Wrap),
1008 mir::BinOp::SubUnchecked => BinOp::Sub(OverflowMode::UB),
1009 mir::BinOp::Mul => BinOp::Mul(OverflowMode::Wrap),
1010 mir::BinOp::MulUnchecked => BinOp::Mul(OverflowMode::UB),
1011 mir::BinOp::Div => BinOp::Div(OverflowMode::UB),
1012 mir::BinOp::Rem => BinOp::Rem(OverflowMode::UB),
1013 mir::BinOp::AddWithOverflow => BinOp::AddChecked,
1014 mir::BinOp::SubWithOverflow => BinOp::SubChecked,
1015 mir::BinOp::MulWithOverflow => BinOp::MulChecked,
1016 mir::BinOp::Shl => BinOp::Shl(OverflowMode::Wrap),
1017 mir::BinOp::ShlUnchecked => BinOp::Shl(OverflowMode::UB),
1018 mir::BinOp::Shr => BinOp::Shr(OverflowMode::Wrap),
1019 mir::BinOp::ShrUnchecked => BinOp::Shr(OverflowMode::UB),
1020 mir::BinOp::Cmp => BinOp::Cmp,
1021 mir::BinOp::Offset => BinOp::Offset,
1022 })
1023 }
1024
1025 fn translate_place(
1026 &mut self,
1027 span: Span,
1028 mir_place: &mir::Place<'tcx>,
1029 ) -> Result<Place, Error> {
1030 use crate::hax::{HasBase, SInto};
1031 use rustc_middle::ty;
1032
1033 let tcx = self.hax_state.base().tcx;
1034 let local_decls = self.local_decls;
1035 let mut place_ty: mir::PlaceTy = mir::Place::from(mir_place.local).ty(local_decls, tcx);
1036 let var_id = self.translate_local(&mir_place.local).unwrap();
1037 let mut place = self.locals.place_for_var(var_id);
1038 for elem in mir_place.projection.as_slice() {
1039 use mir::ProjectionElem::*;
1040 if let TyKind::Error(msg) = place.ty().kind() {
1041 return Err(Error {
1042 span,
1043 msg: msg.clone(),
1044 });
1045 }
1046 let projected_place_ty = place_ty.projection_ty(tcx, *elem);
1047 let next_place_ty = projected_place_ty.ty.sinto(&self.hax_state);
1048 let next_place_ty = self.translate_ty(span, &next_place_ty)?;
1049 let proj_elem = match elem {
1050 Deref => ProjectionElem::Deref,
1051 PhantomDeref => {
1052 raise_error!(self, span, "unsupported phantom dereference in MIR place");
1053 }
1054 Field(index, _) => {
1055 let TyKind::Adt(tref) = place.ty().kind() else {
1056 raise_error!(
1057 self,
1058 span,
1059 "found unexpected type in field projection: {}",
1060 next_place_ty.with_ctx(&self.into_fmt())
1061 )
1062 };
1063 let field_id = self.translate_field_id(*index);
1064 match place_ty.ty.kind() {
1065 ty::Adt(adt_def, _) => {
1066 let variant = place_ty.variant_index;
1067 let variant_id = variant.map(|id| self.translate_variant_id(id));
1068 let generics = &tref.generics;
1069 match tref.as_builtin() {
1070 None => {
1071 assert!(
1072 ((adt_def.is_struct() || adt_def.is_union())
1073 && variant.is_none())
1074 || (adt_def.is_enum() && variant.is_some())
1075 );
1076 ProjectionElem::Field(variant_id, field_id)
1077 }
1078 Some(BuiltinAdt::Tuple) => {
1079 assert!(generics.regions.is_empty());
1080 assert!(variant.is_none());
1081 assert!(generics.const_generics.is_empty());
1082 ProjectionElem::Field(None, field_id)
1083 }
1084 Some(BuiltinAdt::Box)
1085 if self.t_ctx.options.treat_box_as_builtin =>
1086 {
1087 assert!(generics.regions.is_empty());
1089 assert!(generics.types.len() == 2);
1090 assert!(generics.const_generics.is_empty());
1091 if field_id == FieldId::ZERO {
1092 ProjectionElem::Deref
1094 } else {
1095 raise_error!(
1096 self,
1097 span,
1098 "trying to access the allocator field from Box, \
1099 but it is being treated as a builtin (without allocator)"
1100 )
1101 }
1102 }
1103 Some(BuiltinAdt::Box) => ProjectionElem::Field(None, field_id),
1104 Some(_) => {
1105 raise_error!(self, span, "Unexpected field projection")
1106 }
1107 }
1108 }
1109 ty::Tuple(_types) => ProjectionElem::Field(None, field_id),
1110 ty::Closure(..) => ProjectionElem::Field(None, field_id),
1113 _ => panic!(),
1114 }
1115 }
1116 Index(local) => {
1117 let var_id = self.translate_local(local).unwrap();
1118 let local = self.locals.place_for_var(var_id);
1119 let offset = Operand::Copy(local);
1120 ProjectionElem::Index {
1121 offset: Box::new(offset),
1122 from_end: false,
1123 }
1124 }
1125 &ConstantIndex {
1126 offset, from_end, ..
1127 } => {
1128 let offset =
1129 Operand::Const(IntegerValue::mk_usize(offset as u128).to_constant());
1130 ProjectionElem::Index {
1131 offset: Box::new(offset),
1132 from_end,
1133 }
1134 }
1135 &Subslice { from, to, from_end } => {
1136 let from = Operand::Const(IntegerValue::mk_usize(from as u128).to_constant());
1137 let to = Operand::Const(IntegerValue::mk_usize(to as u128).to_constant());
1138 ProjectionElem::Subslice {
1139 from: Box::new(from),
1140 to: Box::new(to),
1141 from_end,
1142 }
1143 }
1144 OpaqueCast(..) => {
1145 raise_error!(self, span, "Unexpected ProjectionElem::OpaqueCast");
1146 }
1147 Downcast { .. } => {
1148 place_ty = projected_place_ty;
1151 continue;
1152 }
1153 UnwrapUnsafeBinder { .. } => {
1154 raise_error!(self, span, "unsupported feature: unsafe binders");
1155 }
1156 };
1157 place = place.project(proj_elem, next_place_ty);
1158 place_ty = projected_place_ty;
1159 }
1160 Ok(place)
1161 }
1162
1163 fn translate_operand(
1165 &mut self,
1166 span: Span,
1167 operand: &mir::Operand<'tcx>,
1168 ) -> Result<Operand, Error> {
1169 Ok(match operand {
1170 mir::Operand::Copy(place) => {
1171 let p = self.translate_place(span, place)?;
1172 Operand::Copy(p)
1173 }
1174 mir::Operand::Move(place) => {
1175 let p = self.translate_place(span, place)?;
1176 Operand::Move(p)
1177 }
1178 mir::Operand::Constant(const_op) => {
1179 let const_op = self.catch_sinto(span, &const_op)?;
1180 match &const_op.kind {
1181 hax::ConstOperandKind::Value(constant) => {
1182 let constant = self.translate_constant_expr(span, constant)?;
1183 if let ConstantExprKind::Array(fields) = constant.kind()
1185 && matches!(const_op.ty.kind(), hax::TyKind::Array(_))
1186 && let Some(repeat) = self.try_reconstruct_array_repeat(
1187 span,
1188 &const_op.ty,
1189 fields.iter().cloned(),
1190 )?
1191 {
1192 let local = self.fresh_var(None, constant.ty().clone());
1193 self.insert_assn_stmt(local.clone(), repeat);
1194 return Ok(Operand::Move(local));
1195 }
1196 Operand::Const(constant)
1197 }
1198 hax::ConstOperandKind::Promoted(item) => {
1199 let global_ref = self.translate_global_decl_ref(span, item)?;
1201 let constant = ConstantExpr::new(
1202 ConstantExprKind::Global(global_ref),
1203 self.translate_ty(span, &const_op.ty)?,
1204 );
1205 Operand::Const(constant)
1206 }
1207 }
1208 }
1209 mir::Operand::RuntimeChecks(check) => {
1210 let op = match check {
1211 mir::RuntimeChecks::UbChecks => NullOp::UbChecks,
1212 mir::RuntimeChecks::OverflowChecks => NullOp::OverflowChecks,
1213 mir::RuntimeChecks::ContractChecks => NullOp::ContractChecks,
1214 };
1215 let local = self.fresh_var(None, Ty::mk_bool());
1216 self.insert_assn_stmt(local.clone(), Rvalue::NullaryOp(op));
1217 Operand::Move(local)
1218 }
1219 })
1220 }
1221
1222 fn translate_mir_rvalue(
1224 &mut self,
1225 span: Span,
1226 rvalue: &mir::Rvalue<'tcx>,
1227 tgt_ty: &Ty,
1228 ) -> Result<Rvalue, Error> {
1229 match rvalue {
1230 mir::Rvalue::Use(operand, retag) => {
1231 let retag = match retag {
1232 mir::WithRetag::Yes => WithRetag::Yes,
1233 mir::WithRetag::No => WithRetag::No,
1234 };
1235 Ok(Rvalue::Use(self.translate_operand(span, operand)?, retag))
1236 }
1237 mir::Rvalue::CopyForDeref(place) => {
1238 let place = self.translate_place(span, place)?;
1241 Ok(Rvalue::Use(Operand::Copy(place), WithRetag::No))
1242 }
1243 mir::Rvalue::Repeat(operand, cnst) => {
1244 let ty_is_copy = {
1245 let rust_ty = operand.ty(self.local_decls, self.tcx);
1246 hax::solve_copy(&self.hax_state, rust_ty)
1247 .map(|proof| self.translate_trait_proof(span, &proof))
1248 .transpose()?
1249 };
1250 let c = self.translate_ty_constant_expr(span, cnst)?;
1251 let op = self.translate_operand(span, operand)?;
1252 let ty = op.ty().clone();
1253 Ok(Rvalue::Repeat(op, ty, c, ty_is_copy))
1255 }
1256 mir::Rvalue::Ref(_region, borrow_kind, place) => {
1257 let place = self.translate_place(span, place)?;
1258 let borrow_kind = self.translate_borrow_kind(*borrow_kind);
1259 Ok(Rvalue::Ref {
1260 place,
1261 kind: borrow_kind,
1262 ptr_metadata: Self::missing_ptr_metadata(),
1264 })
1265 }
1266 mir::Rvalue::RawPtr(mtbl, place) => {
1267 let mtbl = match mtbl {
1268 mir::RawPtrKind::Mut => RefKind::Mut,
1269 mir::RawPtrKind::Const => RefKind::Shared,
1270 mir::RawPtrKind::FakeForPtrMetadata => RefKind::Shared,
1271 };
1272 let place = self.translate_place(span, place)?;
1273 Ok(Rvalue::RawPtr {
1274 place,
1275 kind: mtbl,
1276 ptr_metadata: Self::missing_ptr_metadata(),
1278 })
1279 }
1280 mir::Rvalue::Cast(cast_kind, mir_operand, rust_tgt_ty) => {
1281 let op_ty = mir_operand.ty(self.local_decls, self.tcx);
1282 let tgt_ty = self.translate_rustc_ty(span, rust_tgt_ty)?;
1283
1284 let mut operand = self.translate_operand(span, mir_operand)?;
1286 let src_ty = operand.ty().clone();
1287
1288 let cast_kind = match cast_kind {
1289 mir::CastKind::IntToInt
1290 | mir::CastKind::IntToFloat
1291 | mir::CastKind::FloatToInt
1292 | mir::CastKind::FloatToFloat => {
1293 let tgt_ty = *tgt_ty.kind().as_scalar().unwrap();
1294 let src_ty = *src_ty.kind().as_scalar().unwrap();
1295 CastKind::Scalar(src_ty, tgt_ty)
1296 }
1297 mir::CastKind::PtrToPtr
1298 | mir::CastKind::PointerCoercion(
1299 ty::adjustment::PointerCoercion::MutToConstPointer,
1300 ..,
1301 )
1302 | mir::CastKind::PointerCoercion(
1303 ty::adjustment::PointerCoercion::ArrayToPointer,
1304 ..,
1305 )
1306 | mir::CastKind::FnPtrToPtr => CastKind::RawPtr(src_ty, tgt_ty),
1307
1308 mir::CastKind::PointerExposeProvenance => {
1309 CastKind::PtrExposeProvenance(src_ty, *tgt_ty.kind().as_scalar().unwrap())
1310 }
1311 mir::CastKind::PointerWithExposedProvenance => {
1312 CastKind::PtrWithExposedProvenance(
1313 *src_ty.kind().as_scalar().unwrap(),
1314 tgt_ty,
1315 )
1316 }
1317 mir::CastKind::PointerCoercion(
1318 ty::adjustment::PointerCoercion::ClosureFnPointer(_),
1319 ..,
1320 ) => {
1321 let hax_op_ty: hax::Ty = self.catch_sinto(span, &op_ty)?;
1322 let hax::TyKind::Closure(closure, ..) = hax_op_ty.kind() else {
1325 unreachable!("Non-closure type in PointerCoercion::ClosureFnPointer");
1326 };
1327 let fn_ref: RegionBinder<FunDeclRef> =
1328 self.translate_stateless_closure_as_fn_ref(span, closure)?;
1329 let fn_ptr_bound: RegionBinder<FnPtr> = fn_ref.map(FunDeclRef::into);
1330 let fn_ptr: FnPtr = self.erase_region_binder(fn_ptr_bound.clone());
1331 let src_ty = TyKind::FnDef(fn_ptr_bound).into_ty();
1332 operand = Operand::Const(ConstantExpr::new(
1333 ConstantExprKind::FnDef(fn_ptr),
1334 src_ty.clone(),
1335 ));
1336 CastKind::FnPtr(src_ty, tgt_ty)
1337 }
1338 mir::CastKind::PointerCoercion(
1339 ty::adjustment::PointerCoercion::UnsafeFnPointer
1340 | ty::adjustment::PointerCoercion::ReifyFnPointer(_),
1341 ..,
1342 ) => CastKind::FnPtr(src_ty, tgt_ty),
1343 mir::CastKind::Transmute | mir::CastKind::BoxDerefTransmute => {
1344 CastKind::Transmute(src_ty, tgt_ty)
1345 }
1346 mir::CastKind::Subtype => CastKind::Transmute(src_ty, tgt_ty),
1348 mir::CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize, ..) => {
1349 let meta =
1350 hax::compute_unsizing_metadata(&self.hax_state, op_ty, *rust_tgt_ty);
1351 let meta = self.translate_unsizing_metadata(span, &meta)?;
1352 CastKind::Unsize(src_ty, tgt_ty.clone(), meta)
1353 }
1354 };
1355 let unop = UnOp::Cast(cast_kind);
1356 Ok(Rvalue::UnaryOp(unop, operand))
1357 }
1358 mir::Rvalue::BinaryOp(binop, (left, right)) => Ok(Rvalue::BinaryOp(
1359 self.translate_binaryop_kind(span, *binop)?,
1360 self.translate_operand(span, left)?,
1361 self.translate_operand(span, right)?,
1362 )),
1363 mir::Rvalue::UnaryOp(unop, operand) => {
1364 let operand = self.translate_operand(span, operand)?;
1365 let unop = match unop {
1366 mir::UnOp::Not => UnOp::Not,
1367 mir::UnOp::Neg => UnOp::Neg(OverflowMode::Wrap),
1368 mir::UnOp::PtrMetadata => match operand {
1369 Operand::Copy(p) | Operand::Move(p) => {
1370 return Ok(Rvalue::Use(
1371 Operand::Copy(
1372 p.project(ProjectionElem::PtrMetadata, tgt_ty.clone()),
1373 ),
1374 WithRetag::No,
1375 ));
1376 }
1377 Operand::Const(_) => {
1378 panic!("unexpected metadata operand")
1379 }
1380 },
1381 };
1382 Ok(Rvalue::UnaryOp(unop, operand))
1383 }
1384 mir::Rvalue::Discriminant(place) => {
1385 let place = self.translate_place(span, place)?;
1386 Ok(Rvalue::Discriminant(place))
1387 }
1388 mir::Rvalue::Aggregate(aggregate_kind, operands) => {
1389 let operands_t: Vec<Operand> = operands
1404 .iter()
1405 .map(|op| self.translate_operand(span, op))
1406 .try_collect()?;
1407 match aggregate_kind {
1408 mir::AggregateKind::Array(ty) => {
1409 let t_ty = self.translate_rustc_ty(span, ty)?;
1410 if operands_t.iter().all(Operand::is_const) {
1411 let rust_array_ty =
1412 ty::Ty::new_array(self.tcx, *ty, operands_t.len() as u64);
1413 let hax_array_ty = self.catch_sinto(span, &rust_array_ty)?;
1414 let fields = operands_t
1415 .iter()
1416 .map(|operand| operand.as_const().unwrap())
1417 .cloned();
1418 if let Some(repeat) =
1419 self.try_reconstruct_array_repeat(span, &hax_array_ty, fields)?
1420 {
1421 return Ok(repeat);
1422 }
1423 }
1424 let c = ConstantExpr::mk_usize(operands_t.len() as u128);
1425 let TyKind::Array(_, _, ty_is_sized) = tgt_ty.kind() else {
1426 raise_error!(self, span, "array aggregate has non-array type")
1427 };
1428 Ok(Rvalue::Aggregate(
1429 AggregateKind::Array(t_ty, c, ty_is_sized.clone()),
1430 operands_t,
1431 ))
1432 }
1433 mir::AggregateKind::Tuple => {
1434 let tys = operands.iter().map(|op| op.ty(self.local_decls, self.tcx));
1435 let ty = ty::Ty::new_tup_from_iter(self.tcx, tys);
1436 let ty = self.translate_rustc_ty(span, &ty)?;
1437 let tref = ty.as_adt().unwrap().clone();
1438 Ok(Rvalue::Aggregate(
1439 AggregateKind::Adt(tref, None, None),
1440 operands_t,
1441 ))
1442 }
1443 mir::AggregateKind::Adt(def_id, variant_idx, generics, _, field_index) => {
1444 use ty::AdtKind;
1445 trace!("{:?}", rvalue);
1446
1447 let adt_kind = self.tcx.adt_def(*def_id).adt_kind();
1448 let item = hax::translate_item_ref(&self.hax_state, *def_id, generics);
1449 let tref = self.translate_type_decl_ref(span, &item)?;
1450 let variant_id = match adt_kind {
1451 AdtKind::Struct | AdtKind::Union => None,
1452 AdtKind::Enum => Some(self.translate_variant_id(*variant_idx)),
1453 };
1454 let field_id = match adt_kind {
1455 AdtKind::Struct | AdtKind::Enum => None,
1456 AdtKind::Union => Some(self.translate_field_id(field_index.unwrap())),
1457 };
1458
1459 let akind = AggregateKind::Adt(tref, variant_id, field_id);
1460 Ok(Rvalue::Aggregate(akind, operands_t))
1461 }
1462 mir::AggregateKind::Closure(def_id, generics) => {
1463 let args = hax::ClosureArgs::sfrom(&self.hax_state, *def_id, generics);
1464 let tref = self.translate_closure_type_ref(span, &args)?;
1465 let akind = AggregateKind::Adt(tref, None, None);
1466 Ok(Rvalue::Aggregate(akind, operands_t))
1467 }
1468 mir::AggregateKind::RawPtr(ty, mutability) => {
1469 let t_ty = self.translate_rustc_ty(span, ty)?;
1470 let mutability = if mutability.is_mut() {
1471 RefKind::Mut
1472 } else {
1473 RefKind::Shared
1474 };
1475
1476 let akind = AggregateKind::RawPtr(t_ty, mutability);
1477
1478 Ok(Rvalue::Aggregate(akind, operands_t))
1479 }
1480 mir::AggregateKind::Coroutine(..)
1481 | mir::AggregateKind::CoroutineClosure(..) => {
1482 raise_error!(self, span, "Coroutines are not supported");
1483 }
1484 }
1485 }
1486 mir::Rvalue::ThreadLocalRef(def_id) => self.translate_thread_local_ref(span, *def_id),
1487 mir::Rvalue::WrapUnsafeBinder { .. } => {
1488 raise_error!(
1489 self,
1490 span,
1491 "charon does not support unsafe lifetime binders"
1492 );
1493 }
1494 mir::Rvalue::Reborrow(..) => {
1495 raise_error!(
1496 self,
1497 span,
1498 "charon does not support reborrow rvalues (for Reborrow traits)"
1499 );
1500 }
1501 }
1502 }
1503
1504 fn translate_statement(
1506 &mut self,
1507 source_scopes: &rustc_index::IndexVec<mir::SourceScope, mir::SourceScopeData>,
1508 statement: &mir::Statement<'tcx>,
1509 ) -> Result<(), Error> {
1510 trace!("About to translate statement (MIR) {:?}", statement);
1511 let span = self.translate_span_from_source_info(source_scopes, &statement.source_info);
1512
1513 self.span = span;
1514 let kind: Option<StatementKind> = match &statement.kind {
1515 mir::StatementKind::Assign((place, rvalue)) => {
1516 let t_place = self.translate_place(span, place)?;
1517 let t_rvalue = self.translate_mir_rvalue(span, rvalue, t_place.ty())?;
1518 Some(StatementKind::Assign(t_place, t_rvalue))
1519 }
1520 mir::StatementKind::SetDiscriminant {
1521 place,
1522 variant_index,
1523 } => {
1524 let t_place = self.translate_place(span, place)?;
1525 let variant_id = self.translate_variant_id(*variant_index);
1526 Some(StatementKind::SetDiscriminant(t_place, variant_id))
1527 }
1528 mir::StatementKind::StorageLive(local) => {
1529 let var_id = self.translate_local(local).unwrap();
1530 Some(StatementKind::StorageLive(var_id))
1531 }
1532 mir::StatementKind::StorageDead(local) => {
1533 let var_id = self.translate_local(local).unwrap();
1534 Some(StatementKind::StorageDead(var_id))
1535 }
1536 mir::StatementKind::Intrinsic(mir::NonDivergingIntrinsic::Assume(op)) => {
1537 let op = self.translate_operand(span, op)?;
1538 self.translate_intrinsic_call(
1539 span,
1540 sym::assume,
1541 ty::GenericArgs::empty(),
1542 vec![op],
1543 )?;
1544 None
1545 }
1546 mir::StatementKind::Intrinsic(mir::NonDivergingIntrinsic::CopyNonOverlapping(
1547 mir::CopyNonOverlapping { src, dst, count },
1548 )) => {
1549 let pointee_ty = src
1550 .ty(self.local_decls, self.tcx)
1551 .builtin_deref(true)
1552 .unwrap();
1553 let generic_args = self.tcx.mk_args(&[pointee_ty.into()]);
1554 let src = self.translate_operand(span, src)?;
1555 let dst = self.translate_operand(span, dst)?;
1556 let count = self.translate_operand(span, count)?;
1557 self.translate_intrinsic_call(
1558 span,
1559 sym::copy_nonoverlapping,
1560 generic_args,
1561 vec![src, dst, count],
1562 )?;
1563 None
1564 }
1565 mir::StatementKind::PlaceMention(place) => {
1566 let place = self.translate_place(span, place)?;
1567 if place.is_local() {
1570 None
1571 } else {
1572 Some(StatementKind::PlaceMention(place))
1573 }
1574 }
1575 mir::StatementKind::FakeRead((_, place)) => {
1576 let place = self.translate_place(span, place)?;
1577 Some(StatementKind::Borrowck(BorrowckStatement::FakeRead(place)))
1578 }
1579 mir::StatementKind::AscribeUserType((place, user_ty), variance) => {
1580 let variance = match variance {
1581 ty::Variance::Covariant => Variance::Covariant,
1582 ty::Variance::Invariant => Variance::Invariant,
1583 ty::Variance::Contravariant => Variance::Contravariant,
1584 ty::Variance::Bivariant => return Ok(()),
1586 };
1587 let place = self.translate_place(span, place)?;
1588 let (ty, facts) = self.translate_user_type_projection(span, user_ty)?;
1589 self.statements.push(Statement::new(
1590 span,
1591 StatementKind::Borrowck(BorrowckStatement::SetType {
1592 place,
1593 ty,
1594 variance,
1595 }),
1596 ));
1597 self.statements.extend(
1598 facts
1599 .into_iter()
1600 .map(|fact| Statement::new(span, StatementKind::Borrowck(fact))),
1601 );
1602 None
1603 }
1604 mir::StatementKind::Coverage(_) => None,
1606 mir::StatementKind::ConstEvalCounter => None,
1609 mir::StatementKind::BackwardIncompatibleDropHint { .. } => None,
1611 mir::StatementKind::Nop => None,
1612 };
1613
1614 let Some(kind) = kind else {
1615 return Ok(());
1616 };
1617 self.statements.push(Statement::new(span, kind));
1618 Ok(())
1619 }
1620
1621 fn translate_intrinsic_call(
1623 &mut self,
1624 span: Span,
1625 name: Symbol,
1626 generic_args: ty::GenericArgsRef<'tcx>,
1627 args: Vec<Operand>,
1628 ) -> Result<(), Error> {
1629 let path = NamePattern::parse(&format!("core::intrinsics::{name}")).unwrap();
1631 let def_id = self.resolve_single_path(span, &path)?;
1632 assert!(self.tcx.is_intrinsic(def_id, name));
1633 let item = hax::ItemRef::translate(self.hax_state_with_id(), def_id, generic_args);
1634 let func =
1635 FnOperand::Regular(self.translate_fn_ptr(span, &item, TransItemSourceKind::Fun)?);
1636 let dest = self.locals.new_var(None, Ty::mk_unit());
1637 self.push_nounwind_call(
1638 span,
1639 Call {
1640 func,
1641 args,
1642 dest,
1643 safety: CallSafety::Inherit,
1644 },
1645 );
1646 Ok(())
1647 }
1648
1649 fn translate_terminator(
1651 mut self,
1652 source_scopes: &rustc_index::IndexVec<mir::SourceScope, mir::SourceScopeData>,
1653 terminator: &mir::Terminator<'tcx>,
1654 ) -> Result<(), Error> {
1655 trace!("About to translate terminator (MIR) {:?}", terminator);
1656 let span = self.translate_span_from_source_info(source_scopes, &terminator.source_info);
1657
1658 self.span = span;
1660 use mir::TerminatorKind;
1661 let kind: ullbc_ast::TerminatorKind = match &terminator.kind {
1662 TerminatorKind::Goto { target } => {
1663 let target = self.translate_basic_block_id(*target);
1664 ullbc_ast::TerminatorKind::Goto { target }
1665 }
1666 TerminatorKind::SwitchInt { discr, targets, .. } => {
1667 let discr = self.translate_operand(span, discr)?;
1668 let (data, branches) = self.translate_switch_targets(span, discr, targets)?;
1669 ullbc_ast::TerminatorKind::Switch { data, branches }
1670 }
1671 TerminatorKind::UnwindResume => ullbc_ast::TerminatorKind::UnwindResume,
1672 TerminatorKind::UnwindTerminate { .. } => ullbc_ast::TerminatorKind::UnwindTerminate,
1673 TerminatorKind::Return => ullbc_ast::TerminatorKind::Return,
1674 TerminatorKind::Unreachable => ullbc_ast::TerminatorKind::UndefinedBehavior,
1677 TerminatorKind::Drop {
1678 place,
1679 target,
1680 unwind,
1681 ..
1682 } => self.translate_drop(span, place, target, unwind)?,
1683 TerminatorKind::Call {
1684 func,
1685 args,
1686 destination,
1687 target,
1688 unwind,
1689 ..
1690 } => self.translate_function_call(span, func, args, destination, target, unwind)?,
1691 TerminatorKind::Assert {
1692 cond,
1693 expected,
1694 msg,
1695 target,
1696 unwind,
1697 } => {
1698 let on_unwind = self.translate_unwind_action(span, unwind);
1699 let kind = self.translate_assert_kind(span, msg)?;
1700 let assert = Assert {
1701 cond: self.translate_operand(span, cond)?,
1702 expected: *expected,
1703 check_kind: Some(kind),
1704 };
1705 let target = self.translate_basic_block_id(*target);
1706 ullbc_ast::TerminatorKind::Assert {
1707 assert,
1708 target,
1709 on_unwind,
1710 }
1711 }
1712 TerminatorKind::FalseEdge {
1713 real_target,
1714 imaginary_target: _,
1715 } => {
1716 let target = self.translate_basic_block_id(*real_target);
1721 ullbc_ast::TerminatorKind::Goto { target }
1722 }
1723 TerminatorKind::FalseUnwind {
1724 real_target,
1725 unwind: _,
1726 } => {
1727 let target = self.translate_basic_block_id(*real_target);
1729 ullbc_ast::TerminatorKind::Goto { target }
1730 }
1731 TerminatorKind::InlineAsm {
1732 asm_macro,
1733 template,
1734 targets,
1735 unwind,
1736 ..
1737 } => {
1738 let asm = rustc_ast::ast::InlineAsmTemplatePiece::to_string(template);
1739 let targets = targets
1740 .iter()
1741 .map(|target| self.translate_basic_block_id(*target))
1742 .collect();
1743 let on_unwind = self.translate_unwind_action(span, unwind);
1744 let kind = match asm_macro {
1745 mir::InlineAsmMacro::Asm => AsmKind::Asm,
1746 mir::InlineAsmMacro::NakedAsm => AsmKind::NakedAsm,
1747 };
1748 ullbc_ast::TerminatorKind::InlineAsm {
1749 asm,
1750 kind,
1751 targets,
1752 on_unwind,
1753 }
1754 }
1755 TerminatorKind::CoroutineDrop
1756 | TerminatorKind::TailCall { .. }
1757 | TerminatorKind::Yield { .. } => {
1758 raise_error!(self, span, "Unsupported terminator: {:?}", terminator.kind);
1759 }
1760 };
1761
1762 self.finish_current_block(Terminator::new(span, kind));
1763 Ok(())
1764 }
1765
1766 fn translate_switch_targets(
1768 &mut self,
1769 span: Span,
1770 discr: Operand,
1771 targets: &mir::SwitchTargets,
1772 ) -> Result<(SwitchData, IndexVec<BranchId, BlockId>), Error> {
1773 let otherwise = targets.otherwise();
1775 let switch_ty = discr.ty();
1776 let switch_scalar_ty = *switch_ty.as_scalar().unwrap();
1777 let mut branch_targets: IndexVec<BranchId, BlockId> = IndexVec::new();
1778 let mut target_to_branch: SeqHashMap<BlockId, BranchId> = SeqHashMap::new();
1779 let mut switch_branches = Vec::with_capacity(targets.iter().count());
1780
1781 let bool_fallback = (switch_scalar_ty == ScalarTy::Bool).then(|| {
1783 let target = self.translate_basic_block_id(otherwise);
1784 *target_to_branch
1785 .entry(target)
1786 .or_insert_with(|| branch_targets.push(target))
1787 });
1788
1789 for (bits, target) in targets.iter() {
1790 let Some(kind) = ConstantExprKind::from_bits(&switch_scalar_ty, bits) else {
1791 raise_error!(self, span, "Can't match on type {switch_scalar_ty}")
1792 };
1793 let target = self.translate_basic_block_id(target);
1794 let branch_id = *target_to_branch
1795 .entry(target)
1796 .or_insert_with(|| branch_targets.push(target));
1797 let value = ConstantExpr::new(kind, switch_ty.clone());
1798 switch_branches.push((value, branch_id));
1799 }
1800
1801 let fallback = bool_fallback.unwrap_or_else(|| {
1802 let target = self.translate_basic_block_id(otherwise);
1803 *target_to_branch
1804 .entry(target)
1805 .or_insert_with(|| branch_targets.push(target))
1806 });
1807 let data = SwitchData {
1808 scrutinee: SwitchScrutinee::Value(discr),
1809 branches: switch_branches,
1810 fallback: Some(fallback),
1811 };
1812 Ok((data, branch_targets))
1813 }
1814
1815 #[allow(clippy::too_many_arguments)]
1820 fn translate_function_call(
1821 &mut self,
1822 span: Span,
1823 func: &mir::Operand<'tcx>,
1824 args: &[hax::Spanned<mir::Operand<'tcx>>],
1825 destination: &mir::Place<'tcx>,
1826 target: &Option<mir::BasicBlock>,
1827 unwind: &mir::UnwindAction,
1828 ) -> Result<TerminatorKind, Error> {
1829 let tcx = self.tcx;
1830 let op_ty = func.ty(self.local_decls, tcx);
1831 let lval = self.translate_place(span, destination)?;
1835 let on_unwind = self.translate_unwind_action(span, unwind);
1836 let fn_operand = match op_ty.kind() {
1838 ty::TyKind::FnDef(def_id, generics) => {
1839 let generics = hax::erase_free_regions(tcx, generics.skip_binder());
1844 let item = &hax::translate_item_ref(&self.hax_state, *def_id, generics);
1845 trace!("func: {:?}", item.def_id);
1846 let fn_ptr = self.translate_fn_ptr(span, item, TransItemSourceKind::Fun)?;
1847 FnOperand::Regular(fn_ptr)
1848 }
1849 _ => {
1850 let op = self.translate_operand(span, func)?;
1852 FnOperand::Dynamic(op)
1853 }
1854 };
1855 let args = self.translate_arguments(span, args)?;
1856
1857 let safety = match op_ty.kind() {
1858 ty::TyKind::FnDef(def_id, generics) => 'safety_fndef: {
1859 let sig_is_unsafe = tcx.fn_sig(*def_id).skip_binder().safety().is_unsafe();
1860
1861 let attrs = tcx.codegen_fn_attrs(*def_id);
1866 let caller = self.item_src.def_id().as_real_or_promoted();
1867 let caller_features = caller
1868 .map(|caller| tcx.typeck_root_def_id(caller))
1869 .filter(|caller| tcx.def_kind(*caller).has_codegen_attrs())
1870 .map_or(&[][..], |caller| {
1871 &tcx.codegen_fn_attrs(caller).target_features[..]
1872 });
1873 let has_feature =
1874 tcx.is_target_feature_call_safe(&attrs.target_features, caller_features);
1875 if sig_is_unsafe && attrs.safe_target_features && has_feature {
1876 break 'safety_fndef CallSafety::Safe;
1877 } else if !has_feature {
1878 break 'safety_fndef CallSafety::Unsafe;
1879 }
1880
1881 if let Some(trait_id) = tcx.trait_of_assoc(*def_id)
1883 && tcx.is_lang_item(trait_id, LangItem::Drop)
1884 {
1885 break 'safety_fndef CallSafety::Unsafe;
1886 }
1887
1888 let mono_dyn_call = self.monomorphize()
1891 && tcx.trait_of_assoc(*def_id).is_some()
1892 && generics.skip_binder().type_at(0).is_trait();
1893 if mono_dyn_call {
1894 break 'safety_fndef if sig_is_unsafe {
1895 CallSafety::Unsafe
1896 } else {
1897 CallSafety::Safe
1898 };
1899 }
1900
1901 CallSafety::Inherit
1902 }
1903 _ => CallSafety::Inherit,
1904 };
1905
1906 let call = Call {
1907 func: fn_operand,
1908 args,
1909 dest: lval,
1910 safety,
1911 };
1912
1913 let target = match target {
1914 Some(target) => self.translate_basic_block_id(*target),
1915 None => {
1916 let abort = Terminator::new(span, TerminatorKind::UndefinedBehavior);
1917 let is_cleanup = self.is_cleanup;
1918 self.blocks.push(abort.into_block(is_cleanup))
1919 }
1920 };
1921
1922 Ok(TerminatorKind::Call {
1923 call,
1924 target,
1925 on_unwind,
1926 })
1927 }
1928
1929 #[allow(clippy::too_many_arguments)]
1931 fn translate_drop(
1932 &mut self,
1933 span: Span,
1934 place: &mir::Place<'tcx>,
1935 target: &mir::BasicBlock,
1936 unwind: &mir::UnwindAction,
1937 ) -> Result<TerminatorKind, Error> {
1938 let place_ty = place.ty(self.local_decls, self.tcx).ty;
1939 let fn_ptr = self.translate_drop_glue_method_call(span, place_ty)?;
1940 let place = self.translate_place(span, place)?;
1941 let target = self.translate_basic_block_id(*target);
1942 let on_unwind = self.translate_unwind_action(span, unwind);
1943
1944 Ok(TerminatorKind::Drop {
1945 kind: self.drop_kind,
1946 place,
1947 fn_ptr,
1948 target,
1949 on_unwind,
1950 })
1951 }
1952
1953 fn translate_unwind_action(&mut self, span: Span, unwind: &mir::UnwindAction) -> BlockId {
1955 match unwind {
1956 mir::UnwindAction::Continue => {
1957 let unwind_continue = Terminator::new(span, TerminatorKind::UnwindResume);
1958 self.blocks.push(unwind_continue.into_block(true))
1959 }
1960 mir::UnwindAction::Unreachable => {
1961 let abort = Terminator::new(span, TerminatorKind::UndefinedBehavior);
1962 self.blocks.push(abort.into_block(true))
1963 }
1964 mir::UnwindAction::Terminate(..) => {
1965 let abort = Terminator::new(span, TerminatorKind::UnwindTerminate);
1966 self.blocks.push(abort.into_block(true))
1967 }
1968 mir::UnwindAction::Cleanup(bb) => self.translate_basic_block_id(*bb),
1969 }
1970 }
1971
1972 fn translate_assert_kind(
1973 &mut self,
1974 span: Span,
1975 kind: &mir::AssertKind<mir::Operand<'tcx>>,
1976 ) -> Result<BuiltinAssertKind, Error> {
1977 match kind {
1978 mir::AssertKind::BoundsCheck { len, index } => {
1979 let len = self.translate_operand(span, len)?;
1980 let index = self.translate_operand(span, index)?;
1981 Ok(BuiltinAssertKind::BoundsCheck { len, index })
1982 }
1983 mir::AssertKind::Overflow(binop, left, right) => {
1984 let binop = self.translate_binaryop_kind(span, *binop)?;
1985 let left = self.translate_operand(span, left)?;
1986 let right = self.translate_operand(span, right)?;
1987 Ok(BuiltinAssertKind::Overflow(binop, left, right))
1988 }
1989 mir::AssertKind::OverflowNeg(operand) => {
1990 let operand = self.translate_operand(span, operand)?;
1991 Ok(BuiltinAssertKind::OverflowNeg(operand))
1992 }
1993 mir::AssertKind::DivisionByZero(operand) => {
1994 let operand = self.translate_operand(span, operand)?;
1995 Ok(BuiltinAssertKind::DivisionByZero(operand))
1996 }
1997 mir::AssertKind::RemainderByZero(operand) => {
1998 let operand = self.translate_operand(span, operand)?;
1999 Ok(BuiltinAssertKind::RemainderByZero(operand))
2000 }
2001 mir::AssertKind::MisalignedPointerDereference { required, found } => {
2002 let required = self.translate_operand(span, required)?;
2003 let found = self.translate_operand(span, found)?;
2004 Ok(BuiltinAssertKind::MisalignedPointerDereference { required, found })
2005 }
2006 mir::AssertKind::NullPointerDereference => {
2007 Ok(BuiltinAssertKind::NullPointerDereference)
2008 }
2009 mir::AssertKind::NullReferenceConstructed => {
2010 Ok(BuiltinAssertKind::NullReferenceCreated)
2011 }
2012 mir::AssertKind::InvalidEnumConstruction(operand) => {
2013 let operand = self.translate_operand(span, operand)?;
2014 Ok(BuiltinAssertKind::InvalidEnumConstruction(operand))
2015 }
2016 mir::AssertKind::ResumedAfterDrop(..)
2017 | mir::AssertKind::ResumedAfterPanic(..)
2018 | mir::AssertKind::ResumedAfterReturn(..) => {
2019 raise_error!(self, span, "Coroutines are not supported");
2020 }
2021 }
2022 }
2023
2024 fn translate_arguments(
2027 &mut self,
2028 span: Span,
2029 args: &[hax::Spanned<mir::Operand<'tcx>>],
2030 ) -> Result<Vec<Operand>, Error> {
2031 let mut t_args: Vec<Operand> = Vec::new();
2032 for arg in args.iter().map(|x| &x.node) {
2033 let op = self.translate_operand(span, arg)?;
2035 t_args.push(op);
2036 }
2037 Ok(t_args)
2038 }
2039}
2040
2041impl<'a> IntoFormatter for &'a BodyTransCtx<'_, '_, '_> {
2042 type C = FmtCtx<'a>;
2043 fn into_fmt(self) -> Self::C {
2044 FmtCtx {
2045 local_names: Some(compute_local_names(&self.locals)),
2046 ..self.i_ctx.into_fmt()
2047 }
2048 }
2049}