leo_passes/monomorphization/mod.rs
1// Copyright (C) 2019-2025 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//! Performs monomorphization of const generic functions within a `ProgramScope`.
18//!
19//! This pass identifies all `inline` functions that take const generic parameters (e.g., `foo::[N: u32]()`)
20//! and replaces each unique instantiation (e.g., `foo::[3]()`, `foo::[7]()`) with a concrete version of the function
21//! where the const parameter is replaced with its actual value. These concrete instances are generated, added to the
22//! reconstructed function list, and inserted into the final program scope.
23//!
24//! If a function has been monomorphized and is no longer referenced by any unresolved calls,
25//! it will be removed from the reconstructed functions and pruned from the call graph.
26//!
27//! ### Example
28//!
29//! ```leo
30//! transition main(x: u32, y: u32) -> u32 {
31//! return foo::[3u32]() + foo::[7u32]();
32//! }
33//!
34//! inline foo::[N: u32]() -> u32 {
35//! return N;
36//! }
37//! ```
38//!
39//! In the example above:
40//! - `foo::[3u32]()` and `foo::[7u32]()` are two distinct instantiations of `foo::[N]`.
41//! - This pass will generate two monomorphized versions of `foo`, one for each unique const argument `M` and `P`.
42//! - These are inserted into the output `ProgramScope` as separate functions with unique names.
43//! - If `foo::[N]` is no longer referenced in any calls, the original generic function is removed.
44
45use crate::Pass;
46
47use leo_ast::ProgramReconstructor as _;
48use leo_errors::Result;
49use leo_span::Symbol;
50
51mod expression;
52
53mod program;
54
55mod visitor;
56use visitor::*;
57
58pub struct MonomorphizationOutput {
59 /// If we encountered calls to const generic functions that were not resolved, keep track of them in this vector
60 pub unresolved_calls: Vec<leo_ast::CallExpression>,
61 /// Did we monomorphize any const generic functions?
62 pub resolved_some_calls: bool,
63}
64
65impl leo_ast::StatementReconstructor for MonomorphizationVisitor<'_> {}
66
67pub struct Monomorphization;
68
69impl Pass for Monomorphization {
70 type Input = ();
71 type Output = MonomorphizationOutput;
72
73 const NAME: &str = "Monomorphization";
74
75 fn do_pass(_input: Self::Input, state: &mut crate::CompilerState) -> Result<Self::Output> {
76 let mut ast = std::mem::take(&mut state.ast);
77 let mut visitor = MonomorphizationVisitor {
78 state,
79 program: Symbol::intern(""),
80 function: Symbol::intern(""),
81 reconstructed_functions: indexmap::IndexMap::new(),
82 monomorphized_functions: indexmap::IndexSet::new(),
83 unresolved_calls: Vec::new(),
84 };
85 ast.ast = visitor.reconstruct_program(ast.ast);
86 visitor.state.handler.last_err().map_err(|e| *e)?;
87 visitor.state.ast = ast;
88
89 Ok(MonomorphizationOutput {
90 unresolved_calls: visitor.unresolved_calls,
91 resolved_some_calls: !visitor.monomorphized_functions.is_empty(),
92 })
93 }
94}