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 mut ast = std::mem::take(&mut state.ast);
38 let mut visitor = RemoveUnreachableVisitor { changed: false, state, has_return: false };
39 ast.ast = visitor.reconstruct_program(ast.ast);
40 visitor.state.ast = ast;
41 Ok(RemoveUnreachableOutput { changed: visitor.changed })
42 }
43}
44
45pub struct RemoveUnreachableVisitor<'state> {
46 pub state: &'state mut CompilerState,
47 pub changed: bool,
49 pub has_return: bool,
51}
52
53impl ProgramReconstructor for RemoveUnreachableVisitor<'_> {
54 fn reconstruct_function(&mut self, input: Function) -> Function {
55 self.has_return = false;
56 let res = Function {
57 annotations: input.annotations,
58 variant: input.variant,
59 identifier: input.identifier,
60 const_parameters: input
61 .const_parameters
62 .iter()
63 .map(|param| ConstParameter { type_: self.reconstruct_type(param.type_.clone()).0, ..param.clone() })
64 .collect(),
65 input: input
66 .input
67 .iter()
68 .map(|input| Input { type_: self.reconstruct_type(input.type_.clone()).0, ..input.clone() })
69 .collect(),
70 output: input
71 .output
72 .iter()
73 .map(|output| Output { type_: self.reconstruct_type(output.type_.clone()).0, ..output.clone() })
74 .collect(),
75 output_type: self.reconstruct_type(input.output_type).0,
76 block: self.reconstruct_block(input.block).0,
77 span: input.span,
78 id: input.id,
79 };
80 self.has_return = false;
81 res
82 }
83
84 fn reconstruct_constructor(&mut self, input: Constructor) -> Constructor {
85 self.has_return = false;
86 let res = Constructor {
87 annotations: input.annotations,
88 block: self.reconstruct_block(input.block).0,
89 span: input.span,
90 id: input.id,
91 };
92 self.has_return = false;
93 res
94 }
95}
96
97impl AstReconstructor for RemoveUnreachableVisitor<'_> {
98 type AdditionalInput = ();
99 type AdditionalOutput = ();
100
101 fn reconstruct_block(&mut self, input: Block) -> (Block, Self::AdditionalOutput) {
102 let statements_with_first_return_only = input
105 .statements
106 .into_iter()
107 .scan(false, |return_seen, s| {
108 let stmt = self.reconstruct_statement(s).0;
109 let res = (!*return_seen).then_some(stmt);
110 *return_seen |= self.has_return;
111 res
112 })
113 .filter_map(Some)
114 .collect();
115 (Block { statements: statements_with_first_return_only, span: input.span, id: input.id }, Default::default())
116 }
117
118 fn reconstruct_conditional(&mut self, input: ConditionalStatement) -> (Statement, Self::AdditionalOutput) {
119 let mut then_block_has_return = false;
122 let mut otherwise_block_has_return = false;
123 let previous_has_return = core::mem::replace(&mut self.has_return, then_block_has_return);
124
125 let then = self.reconstruct_block(input.then).0;
126 then_block_has_return = self.has_return;
127
128 let otherwise = input.otherwise.map(|otherwise| {
129 self.has_return = otherwise_block_has_return;
130 let res = Box::new(self.reconstruct_statement(*otherwise).0);
131 otherwise_block_has_return = self.has_return;
132 res
133 });
134
135 self.has_return = previous_has_return || (then_block_has_return && otherwise_block_has_return);
137
138 (
139 ConditionalStatement {
140 condition: self.reconstruct_expression(input.condition, &Default::default()).0,
141 then,
142 otherwise,
143 ..input
144 }
145 .into(),
146 Default::default(),
147 )
148 }
149
150 fn reconstruct_iteration(&mut self, input: IterationStatement) -> (Statement, Self::AdditionalOutput) {
151 let prior_has_return = core::mem::take(&mut self.has_return);
152 let block = self.reconstruct_block(input.block).0;
153 self.has_return = prior_has_return;
154
155 (
156 IterationStatement {
157 type_: input.type_.map(|ty| self.reconstruct_type(ty).0),
158 start: self.reconstruct_expression(input.start, &Default::default()).0,
159 stop: self.reconstruct_expression(input.stop, &Default::default()).0,
160 block,
161 ..input
162 }
163 .into(),
164 Default::default(),
165 )
166 }
167
168 fn reconstruct_return(&mut self, input: ReturnStatement) -> (Statement, Self::AdditionalOutput) {
169 self.has_return = true;
170 (
171 ReturnStatement {
172 expression: self.reconstruct_expression(input.expression, &Default::default()).0,
173 ..input
174 }
175 .into(),
176 Default::default(),
177 )
178 }
179}