leo_passes/static_single_assignment/
program.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
17use super::SsaFormingVisitor;
18
19use leo_ast::{
20    Block,
21    Composite,
22    Constructor,
23    ConstructorConsumer,
24    Function,
25    FunctionConsumer,
26    Identifier,
27    Member,
28    Module,
29    ModuleConsumer,
30    Node as _,
31    Program,
32    ProgramConsumer,
33    ProgramScope,
34    ProgramScopeConsumer,
35    StatementConsumer,
36    StructConsumer,
37};
38use leo_span::{Symbol, sym};
39
40use indexmap::IndexMap;
41
42impl StructConsumer for SsaFormingVisitor<'_> {
43    type Output = Composite;
44
45    /// Reconstructs records in the program, ordering its fields such that `owner` and is the first field.
46    fn consume_struct(&mut self, struct_: Composite) -> Self::Output {
47        match struct_.is_record {
48            false => struct_,
49            true => {
50                let mut members = Vec::with_capacity(struct_.members.len());
51                let mut member_map: IndexMap<Symbol, Member> =
52                    struct_.members.into_iter().map(|member| (member.identifier.name, member)).collect();
53
54                // Add the owner field to the beginning of the members list.
55                // Note that type checking ensures that the owner field exists.
56                members.push(member_map.shift_remove(&sym::owner).unwrap());
57
58                // Add the remaining fields to the members list.
59                members.extend(member_map.into_iter().map(|(_, member)| member));
60
61                Composite { members, ..struct_ }
62            }
63        }
64    }
65}
66
67impl FunctionConsumer for SsaFormingVisitor<'_> {
68    type Output = Function;
69
70    /// Reconstructs the `Function`s in the `Program`, while allocating the appropriate `RenameTable`s.
71    fn consume_function(&mut self, mut function: Function) -> Self::Output {
72        // Allocate a `RenameTable` for the function.
73        self.push();
74
75        if self.rename_defs {
76            // For each input, change to a unique name.
77            for input_variable in function.input.iter_mut() {
78                let old_identifier = input_variable.identifier;
79                let new_symbol = self.state.assigner.unique_symbol(old_identifier, "$$");
80                let new_identifier = Identifier::new(new_symbol, self.state.node_builder.next_id());
81                input_variable.identifier = new_identifier;
82
83                // Add the new identifier to the type table.
84                self.state.type_table.insert(new_identifier.id(), input_variable.type_.clone());
85
86                // Associate the old name with its ID.
87                self.rename_table.update(old_identifier.name, old_identifier.name, old_identifier.id);
88
89                // And make the rename.
90                self.rename_table.update(old_identifier.name, new_identifier.name, old_identifier.id);
91            }
92        }
93
94        function.block =
95            Block { span: function.block.span, id: function.block.id, statements: self.consume_block(function.block) };
96
97        // Remove the `RenameTable` for the function.
98        self.pop();
99
100        function
101    }
102}
103
104impl ConstructorConsumer for SsaFormingVisitor<'_> {
105    type Output = Constructor;
106
107    /// Reconstructs the `Constructor` in the `Program`, while allocating the appropriate `RenameTable`s.
108    fn consume_constructor(&mut self, mut constructor: Constructor) -> Self::Output {
109        // Allocate a `RenameTable` for the constructor.
110        self.push();
111        // Rename the constructor's block.
112        constructor.block = Block {
113            span: constructor.block.span,
114            id: constructor.block.id,
115            statements: self.consume_block(constructor.block),
116        };
117        // Remove the `RenameTable` for the constructor.
118        self.pop();
119
120        constructor
121    }
122}
123
124impl ProgramScopeConsumer for SsaFormingVisitor<'_> {
125    type Output = ProgramScope;
126
127    fn consume_program_scope(&mut self, input: ProgramScope) -> Self::Output {
128        self.program = input.program_id.name.name;
129        ProgramScope {
130            program_id: input.program_id,
131            consts: input.consts,
132            structs: input.structs.into_iter().map(|(i, s)| (i, self.consume_struct(s))).collect(),
133            mappings: input.mappings,
134            functions: input.functions.into_iter().map(|(i, f)| (i, self.consume_function(f))).collect(),
135            constructor: input.constructor.map(|c| self.consume_constructor(c)),
136            span: input.span,
137        }
138    }
139}
140
141impl ProgramConsumer for SsaFormingVisitor<'_> {
142    type Output = Program;
143
144    fn consume_program(&mut self, input: Program) -> Self::Output {
145        Program {
146            modules: input.modules.into_iter().map(|(path, module)| (path, self.consume_module(module))).collect(),
147            imports: input
148                .imports
149                .into_iter()
150                .map(|(name, (import, span))| (name, (self.consume_program(import), span)))
151                .collect(),
152            stubs: input.stubs,
153            program_scopes: input
154                .program_scopes
155                .into_iter()
156                .map(|(name, scope)| (name, self.consume_program_scope(scope)))
157                .collect(),
158        }
159    }
160}
161
162impl ModuleConsumer for SsaFormingVisitor<'_> {
163    type Output = Module;
164
165    fn consume_module(&mut self, input: Module) -> Self::Output {
166        Module {
167            path: input.path,
168            program_name: self.program,
169            structs: input.structs.into_iter().map(|(i, s)| (i, self.consume_struct(s))).collect(),
170            functions: input.functions.into_iter().map(|(i, f)| (i, self.consume_function(f))).collect(),
171            consts: input.consts,
172        }
173    }
174}