leo_passes/function_inlining/mod.rs
1// Copyright (C) 2019-2026 Provable Inc.
2// This file is part of the Leo library.
3
4// The Leo library is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// The Leo library is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
16
17//! The Function Inlining pass traverses the AST and inlines function at their call site.
18//! See https://en.wikipedia.org/wiki/Inline_expansion for more information.
19//! The pass also reorders `Function`s in a reconstructed `ProgramScope` so that they are in a post-order of the call graph.
20//! In other words, a callee function will appear before a caller function in the order.
21//!
22//! Consider the following flattened Leo code.
23//! ```leo
24//! function main(flag: u8, value: u8) -> u8 {
25//! $var$0 = flag == 0u8;
26//! $var$1 = foo(value);
27//! value$2 = $var$1;
28//! value$3 = $var$0 ? value$2 : value;
29//! return value$3;
30//! }
31//!
32//! inline foo(x: u8) -> u8 {
33//! $var$4 = x * x;
34//! return $var$4;
35//! }
36//! ```
37//!
38//! The inlining pass produces the following code.
39//! ```leo
40//! inline foo(x: u8) -> u8 {
41//! $var$4 = x * x;
42//! return $var$4;
43//! }
44//!
45//! function main(flag: u8, value: u8) -> u8 {
46//! $var$0 = flag == 0u8;
47//! $var$4$5 = value * value;
48//! $var$1 = $var$4$5;
49//! value$2 = $var$1;
50//! value$3 = $var$0 ? value$2 : value;
51//! return value$3;
52//! }
53//! ```
54
55use crate::Pass;
56
57use analysis::AnalysisVisitor;
58use indexmap::IndexMap;
59use leo_ast::{ProgramReconstructor, ProgramVisitor};
60use leo_errors::Result;
61use leo_span::Symbol;
62use transform::TransformVisitor;
63
64mod analysis;
65mod transform;
66
67pub struct FunctionInlining;
68
69impl Pass for FunctionInlining {
70 type Input = ();
71 type Output = ();
72
73 const NAME: &str = "FunctionInlining";
74
75 fn do_pass(_input: Self::Input, state: &mut crate::CompilerState) -> Result<Self::Output> {
76 // Phase 1: Analysis - collect functions that ought always be inlined
77 let mut analyzer = AnalysisVisitor::new();
78 state.ast.visit(
79 |program| analyzer.visit_program(program),
80 |_library| {
81 // no-op for libraries
82 },
83 );
84
85 // Phase 2: Transformation - convert Function to Inline where needed
86 let ast = std::mem::take(&mut state.ast);
87 let mut visitor = TransformVisitor {
88 state,
89 reconstructed_functions: Vec::new(),
90 program: Symbol::intern(""),
91 function_map: IndexMap::new(),
92 is_onchain: false,
93 always_inline: analyzer.functions_to_inline,
94 };
95
96 let ast = ast.map(
97 |program| visitor.reconstruct_program(program),
98 |library| library, // no-op for libraries
99 );
100
101 visitor.state.handler.last_err()?;
102 visitor.state.ast = ast;
103
104 Ok(())
105 }
106}