charon_lib/transform/
remove_unit_locals.rs1use derive_generic_visitor::*;
2use std::collections::HashSet;
3
4use crate::transform::TransformCtx;
5use crate::ullbc_ast::*;
6
7use super::ctx::UllbcPass;
8
9pub struct Transform;
10impl UllbcPass for Transform {
11 fn transform_body(&self, _ctx: &mut TransformCtx, body: &mut ExprBody) {
12 body.visit_statements(|st| {
15 if let RawStatement::Assign(_, rvalue) = &mut st.content
16 && let Rvalue::Use(Operand::Move(from) | Operand::Copy(from)) = rvalue
17 && from.is_local()
18 && from.ty().is_unit()
19 {
20 *rvalue = Rvalue::unit_value()
21 }
22 });
23
24 #[derive(Visitor)]
26 struct UnitLocalsVisitor {
27 unused_unit_locals: HashSet<LocalId>,
28 }
29 impl VisitBody for UnitLocalsVisitor {
30 fn enter_place(&mut self, x: &Place) {
31 if let Some(var_id) = x.as_local() {
32 self.unused_unit_locals.remove(&var_id);
33 }
34 }
35 fn visit_ullbc_statement(
36 &mut self,
37 x: &ullbc_ast::Statement,
38 ) -> ControlFlow<Self::Break> {
39 match &x.content {
40 RawStatement::Assign(place, rvalue) => {
41 if place.is_local() && place.ty().is_unit() {
42 } else {
44 self.visit(place)?;
45 }
46 self.visit(rvalue)?;
47 }
48 _ => self.visit_inner(x)?,
49 }
50 Continue(())
51 }
52 }
53 let unused_unit_locals = (UnitLocalsVisitor {
54 unused_unit_locals: body
55 .locals
56 .non_argument_locals()
57 .filter(|(_, var)| var.ty.is_unit())
58 .map(|(id, _)| id)
59 .collect(),
60 })
61 .visit_by_val_infallible(&*body)
62 .unused_unit_locals;
63
64 body.visit_statements(|st| {
66 if let RawStatement::Assign(place, rvalue) = &st.content
67 && let Some(var_id) = place.as_local()
68 && unused_unit_locals.contains(&var_id)
69 && rvalue.is_aggregate()
70 {
71 st.content = RawStatement::Nop;
72 }
73 });
74 }
75}