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