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::{CompositeType, ProgramReconstructor as _, StructExpression};
48use leo_errors::Result;
49use leo_span::Symbol;
50
51mod ast;
52
53mod program;
54
55mod visitor;
56use visitor::*;
57
58#[derive(Debug)]
59pub struct MonomorphizationOutput {
60    /// If we encountered calls to const generic functions that were not resolved, keep track of them in this vector
61    pub unresolved_calls: Vec<leo_ast::CallExpression>,
62    /// If we encountered const generic struct expressions that were not resolved, keep track of them in this vector
63    pub unresolved_struct_exprs: Vec<StructExpression>,
64    /// If we encountered const generic struct type instantiations that were not resolved, keep track of them in this
65    /// vector
66    pub unresolved_struct_types: Vec<CompositeType>,
67    /// Did we change anything in this program?
68    pub changed: bool,
69}
70
71pub struct Monomorphization;
72
73impl Pass for Monomorphization {
74    type Input = ();
75    type Output = MonomorphizationOutput;
76
77    const NAME: &str = "Monomorphization";
78
79    fn do_pass(_input: Self::Input, state: &mut crate::CompilerState) -> Result<Self::Output> {
80        let mut ast = std::mem::take(&mut state.ast);
81        let mut visitor = MonomorphizationVisitor {
82            state,
83            program: Symbol::intern(""),
84            reconstructed_functions: indexmap::IndexMap::new(),
85            function_map: indexmap::IndexMap::new(),
86            struct_map: indexmap::IndexMap::new(),
87            monomorphized_functions: indexmap::IndexSet::new(),
88            reconstructed_structs: indexmap::IndexMap::new(),
89            monomorphized_structs: indexmap::IndexSet::new(),
90            unresolved_calls: Vec::new(),
91            unresolved_struct_exprs: Vec::new(),
92            unresolved_struct_types: Vec::new(),
93            changed: false,
94        };
95        ast.ast = visitor.reconstruct_program(ast.ast);
96        visitor.state.handler.last_err()?;
97        visitor.state.ast = ast;
98
99        Ok(MonomorphizationOutput {
100            unresolved_calls: visitor.unresolved_calls,
101            unresolved_struct_exprs: visitor.unresolved_struct_exprs,
102            unresolved_struct_types: visitor.unresolved_struct_types,
103            changed: visitor.changed,
104        })
105    }
106}