leo_passes/function_inlining/
ast.rs1use super::FunctionInliningVisitor;
18use crate::Replacer;
19
20use leo_ast::*;
21
22use indexmap::IndexMap;
23use itertools::Itertools;
24
25impl AstReconstructor for FunctionInliningVisitor<'_> {
26 type AdditionalInput = ();
27 type AdditionalOutput = Vec<Statement>;
28
29 fn reconstruct_call(&mut self, input: CallExpression, _additional: &()) -> (Expression, Self::AdditionalOutput) {
31 if input.program.is_some_and(|prog| prog != self.program) {
33 return (input.into(), Default::default());
34 }
35
36 let (_, callee) = self
39 .reconstructed_functions
40 .iter()
41 .find(|(path, _)| *path == input.function.absolute_path())
42 .expect("guaranteed to exist due to post-order traversal of the call graph.");
43
44 match callee.variant {
46 Variant::Inline => {
47 let parameter_to_argument = callee
49 .input
50 .iter()
51 .map(|input| input.identifier().name)
52 .zip_eq(input.arguments)
53 .collect::<IndexMap<_, _>>();
54
55 let replace_path = |expr: &Expression| match expr {
57 Expression::Path(path) => parameter_to_argument
58 .get(&path.identifier().name)
59 .map_or(Expression::Path(path.clone()), |expr| expr.clone()),
60 _ => expr.clone(),
61 };
62
63 let mut inlined_statements = Replacer::new(replace_path, false , self.state)
64 .reconstruct_block(callee.block.clone())
65 .0
66 .statements;
67
68 let result = match inlined_statements.last() {
70 Some(Statement::Return(_)) => {
71 match inlined_statements.pop().unwrap() {
73 Statement::Return(ReturnStatement { expression, .. }) => expression,
74 _ => panic!("This branch checks that the last statement is a return statement."),
75 }
76 }
77 _ => {
78 let id = self.state.node_builder.next_id();
79 self.state.type_table.insert(id, Type::Unit);
80 UnitExpression { span: Default::default(), id }.into()
81 }
82 };
83
84 (result, inlined_statements)
85 }
86 Variant::Function
87 | Variant::Script
88 | Variant::AsyncFunction
89 | Variant::Transition
90 | Variant::AsyncTransition => (input.into(), Default::default()),
91 }
92 }
93
94 fn reconstruct_assign(&mut self, _input: AssignStatement) -> (Statement, Self::AdditionalOutput) {
96 panic!("`AssignStatement`s should not exist in the AST at this phase of compilation.")
97 }
98
99 fn reconstruct_block(&mut self, block: Block) -> (Block, Self::AdditionalOutput) {
101 let mut statements = Vec::with_capacity(block.statements.len());
102
103 for statement in block.statements {
104 let (reconstructed_statement, additional_statements) = self.reconstruct_statement(statement);
105 statements.extend(additional_statements);
106 statements.push(reconstructed_statement);
107 }
108
109 (Block { span: block.span, statements, id: block.id }, Default::default())
110 }
111
112 fn reconstruct_conditional(&mut self, input: ConditionalStatement) -> (Statement, Self::AdditionalOutput) {
114 if !self.is_async {
115 panic!("`ConditionalStatement`s should not be in the AST at this phase of compilation.")
116 } else {
117 (
118 ConditionalStatement {
119 condition: self.reconstruct_expression(input.condition, &()).0,
120 then: self.reconstruct_block(input.then).0,
121 otherwise: input.otherwise.map(|n| Box::new(self.reconstruct_statement(*n).0)),
122 span: input.span,
123 id: input.id,
124 }
125 .into(),
126 Default::default(),
127 )
128 }
129 }
130
131 fn reconstruct_definition(&mut self, mut input: DefinitionStatement) -> (Statement, Self::AdditionalOutput) {
134 let (value, mut statements) = self.reconstruct_expression(input.value, &());
135 match (input.place, value) {
136 (DefinitionPlace::Multiple(left), Expression::Tuple(right)) => {
138 assert_eq!(left.len(), right.elements.len());
139 for (identifier, rhs_value) in left.into_iter().zip(right.elements) {
140 let stmt = DefinitionStatement {
141 place: DefinitionPlace::Single(identifier),
142 type_: None,
143 value: rhs_value,
144 span: Default::default(),
145 id: self.state.node_builder.next_id(),
146 }
147 .into();
148
149 statements.push(stmt);
150 }
151 (Statement::dummy(), statements)
152 }
153
154 (place, value) => {
155 input.value = value;
156 input.place = place;
157 (input.into(), statements)
158 }
159 }
160 }
161
162 fn reconstruct_expression_statement(&mut self, input: ExpressionStatement) -> (Statement, Self::AdditionalOutput) {
164 let (expression, additional_statements) = self.reconstruct_expression(input.expression, &());
167
168 let statement = match expression {
170 Expression::Unit(_) => Statement::dummy(),
171 _ => ExpressionStatement { expression, ..input }.into(),
172 };
173
174 (statement, additional_statements)
175 }
176
177 fn reconstruct_iteration(&mut self, _: IterationStatement) -> (Statement, Self::AdditionalOutput) {
179 panic!("`IterationStatement`s should not be in the AST at this phase of compilation.");
180 }
181}