charon_lib/transform/resugar/reconstruct_asserts.rs
1//! In the MIR AST, it seems `assert` are introduced to check preconditions
2//! (for the binops for example). The `assert!` introduced by the user
3//! introduce `if ... then { panic!(...) } else { ...}`.
4//! This pass introduces `assert` instead in order to make the code shorter.
5
6use crate::transform::TransformCtx;
7use crate::ullbc_ast::*;
8
9use crate::transform::ctx::UllbcPass;
10
11pub struct Transform;
12impl UllbcPass for Transform {
13 fn should_run(&self, options: &crate::options::TranslateOptions) -> bool {
14 options.reconstruct_asserts
15 }
16
17 fn transform_body(&self, _ctx: &mut TransformCtx, b: &mut ExprBody) {
18 // Start by computing the set of blocks which are actually panics.
19 // Remark: doing this in two steps because reading the blocks at random
20 // while doing in-place updates is not natural to do in Rust.
21 let panics = b.as_abort_map();
22
23 for block in b.body.iter_mut() {
24 match &block.terminator.kind {
25 TerminatorKind::Switch {
26 discr: _,
27 targets: SwitchTargets::If(bid0, bid1),
28 } => {
29 let (nbid, expected, abort) = if let Some(abort) = panics.get(bid0) {
30 (*bid1, false, abort)
31 } else if let Some(abort) = panics.get(bid1) {
32 (*bid0, true, abort)
33 } else {
34 continue;
35 };
36
37 let kind = std::mem::replace(
38 &mut block.terminator.kind,
39 TerminatorKind::Goto { target: nbid },
40 );
41 let (discr, _) = kind.as_switch().unwrap();
42 block.statements.push(Statement::new(
43 block.terminator.span,
44 StatementKind::Assert {
45 assert: Assert {
46 cond: discr.clone(),
47 expected,
48 check_kind: None,
49 },
50 on_failure: abort.clone(),
51 },
52 ));
53 }
54 _ => (),
55 }
56 }
57 }
58}