1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
// Copyright (C) 2019-2026 Provable Inc.
// This file is part of the Leo library.
// The Leo library is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// The Leo library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
//! Monomorphizes const generic functions and composites across every program reachable from the
//! top-level compilation unit.
//!
//! Each unique instantiation of a const generic function (`foo::[3u32]()`, `foo::[7u32]()`) or
//! composite (`Vec::[3u32]`, `Vec::[5u32]`) is replaced with a concrete specialization in which
//! the const parameters are substituted with their literal values. Specializations are given a
//! unique name (e.g. `foo::[3u32]`) and inserted alongside — or, when the original generic is no
//! longer referenced, in place of — their source definition.
//!
//! ### Example
//!
//! ```leo
//! transition main(x: u32, y: u32) -> u32 {
//! return foo::[3u32]() + foo::[7u32]();
//! }
//!
//! inline foo::[N: u32]() -> u32 {
//! return N;
//! }
//! ```
//!
//! Two concrete versions of `foo` are generated — one per const argument — and the original
//! generic `foo::[N]` is pruned once no unresolved call refers to it.
//!
//! ### Algorithm
//!
//! The pass is a single holistic walk, not a recursive per-stub pass. Conceptually:
//!
//! 1. **Seed** `function_map` and `composite_map` with every function and composite reachable
//! from the top-level `Program` — its own scopes and modules, plus the contents of every
//! `FromLeo`, `FromLibrary`, and `FromAleo` stub. Inserts from the current program come last
//! so they override any stub placeholders.
//! 2. **Specialize composites** in post-order of the composite graph. A composite field may
//! instantiate another generic composite, so callees must be monomorphized before their users.
//! Specialized composites preserve their full module path (`types::Vec` → `types::Vec::[3u32]`)
//! to prevent same-named structs in different submodules from colliding.
//! 3. **Specialize functions** via a post-order DFS over the call graph. Roots are every
//! program's entry points, constructors, and non-generic top-level `fn`s — external roots
//! included, so a generic closure called only from within an imported program still gets
//! rewritten. `self.program` is set to each callee's own program during traversal so
//! cross-program edges are interpreted from the callee's perspective.
//! 4. **Carry through** external definitions the DFS did not reach (they are still needed for
//! stub assembly); drop current-program leftovers as dead code.
//! 5. **Assemble stubs** from the now-populated `reconstructed_*` maps. `FromLeo` stubs are
//! rebuilt directly; `FromLibrary` stubs are reconstructed so their items pick up any
//! monomorphized composite references.
//! 6. **Prune originals**: an original generic is removed once every call to it has been
//! rewritten to a specialization. If unresolved calls remain, the original is kept so
//! subsequent runs of this pass (inside the `ConstPropUnrollAndMorphing` fixed-point loop)
//! can finish the job.
use cratePass;
use ;
use Result;
use Symbol;
use *;
;