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}