leo_passes/
remove_unreachable.rs1use crate::{CompilerState, Pass};
18
19use leo_ast::*;
20use leo_errors::Result;
21
22pub struct RemoveUnreachableOutput {
23 pub changed: bool,
25}
26
27pub struct RemoveUnreachable;
29
30impl Pass for RemoveUnreachable {
31 type Input = ();
32 type Output = RemoveUnreachableOutput;
33
34 const NAME: &str = "RemoveUnreachable";
35
36 fn do_pass(_input: Self::Input, state: &mut crate::CompilerState) -> Result<Self::Output> {
37 let ast = std::mem::take(&mut state.ast);
38 let mut visitor = RemoveUnreachableVisitor { changed: false, state, has_return: false };
39
40 let ast = ast.map(
41 |program| visitor.reconstruct_program(program),
42 |library| library, );
44
45 visitor.state.ast = ast;
46 Ok(RemoveUnreachableOutput { changed: visitor.changed })
47 }
48}
49
50pub struct RemoveUnreachableVisitor<'state> {
51 pub state: &'state mut CompilerState,
52 pub changed: bool,
54 pub has_return: bool,
56}
57
58impl ProgramReconstructor for RemoveUnreachableVisitor<'_> {
59 fn reconstruct_function(&mut self, input: Function) -> Function {
60 self.has_return = false;
61 let res = Function {
62 annotations: input.annotations,
63 variant: input.variant,
64 identifier: input.identifier,
65 const_parameters: input
66 .const_parameters
67 .iter()
68 .map(|param| ConstParameter { type_: self.reconstruct_type(param.type_.clone()).0, ..param.clone() })
69 .collect(),
70 input: input
71 .input
72 .iter()
73 .map(|input| Input { type_: self.reconstruct_type(input.type_.clone()).0, ..input.clone() })
74 .collect(),
75 output: input
76 .output
77 .iter()
78 .map(|output| Output { type_: self.reconstruct_type(output.type_.clone()).0, ..output.clone() })
79 .collect(),
80 output_type: self.reconstruct_type(input.output_type).0,
81 block: self.reconstruct_block(input.block).0,
82 span: input.span,
83 id: input.id,
84 };
85 self.has_return = false;
86 res
87 }
88
89 fn reconstruct_constructor(&mut self, input: Constructor) -> Constructor {
90 self.has_return = false;
91 let res = Constructor {
92 annotations: input.annotations,
93 block: self.reconstruct_block(input.block).0,
94 span: input.span,
95 id: input.id,
96 };
97 self.has_return = false;
98 res
99 }
100}
101
102impl AstReconstructor for RemoveUnreachableVisitor<'_> {
103 type AdditionalInput = ();
104 type AdditionalOutput = ();
105
106 fn reconstruct_block(&mut self, input: Block) -> (Block, Self::AdditionalOutput) {
107 let statements_with_first_return_only = input
110 .statements
111 .into_iter()
112 .scan(false, |return_seen, s| {
113 let stmt = self.reconstruct_statement(s).0;
114 let res = (!*return_seen).then_some(stmt);
115 *return_seen |= self.has_return;
116 res
117 })
118 .collect();
119 (Block { statements: statements_with_first_return_only, span: input.span, id: input.id }, Default::default())
120 }
121
122 fn reconstruct_conditional(&mut self, input: ConditionalStatement) -> (Statement, Self::AdditionalOutput) {
123 let mut then_block_has_return = false;
126 let mut otherwise_block_has_return = false;
127 let previous_has_return = core::mem::replace(&mut self.has_return, then_block_has_return);
128
129 let then = self.reconstruct_block(input.then).0;
130 then_block_has_return = self.has_return;
131
132 let otherwise = input.otherwise.map(|otherwise| {
133 self.has_return = otherwise_block_has_return;
134 let res = Box::new(self.reconstruct_statement(*otherwise).0);
135 otherwise_block_has_return = self.has_return;
136 res
137 });
138
139 self.has_return = previous_has_return || (then_block_has_return && otherwise_block_has_return);
141
142 (
143 ConditionalStatement {
144 condition: self.reconstruct_expression(input.condition, &Default::default()).0,
145 then,
146 otherwise,
147 ..input
148 }
149 .into(),
150 Default::default(),
151 )
152 }
153
154 fn reconstruct_iteration(&mut self, input: IterationStatement) -> (Statement, Self::AdditionalOutput) {
155 let prior_has_return = core::mem::take(&mut self.has_return);
156 let block = self.reconstruct_block(input.block).0;
157 self.has_return = prior_has_return;
158
159 (
160 IterationStatement {
161 type_: input.type_.map(|ty| self.reconstruct_type(ty).0),
162 start: self.reconstruct_expression(input.start, &Default::default()).0,
163 stop: self.reconstruct_expression(input.stop, &Default::default()).0,
164 block,
165 ..input
166 }
167 .into(),
168 Default::default(),
169 )
170 }
171
172 fn reconstruct_return(&mut self, input: ReturnStatement) -> (Statement, Self::AdditionalOutput) {
173 self.has_return = true;
174 (
175 ReturnStatement {
176 expression: self.reconstruct_expression(input.expression, &Default::default()).0,
177 ..input
178 }
179 .into(),
180 Default::default(),
181 )
182 }
183}