Skip to content

Commit 72a9acc

Browse files
committed
Refactored SymbolTable and related changes.
The SymbolTable design is now a little simpler, and local scopes don't have tables to store functions, structs, etc, since those are only globals anyway. Remove the symbol table json code. Revise code catching assignments in conditionals in async functions. Previously, code like this: if x { let y: u8 = 1u8; { y = 2u8; } } would trigger the error, but it should actually pass. Can use locators for local records and mappings Remove the N type parameter in TypeChecker. Instead, we have a `NetworkLimits` struct which contains the values the TypeChecker will actually use. This cuts down on code bloat a bit.
1 parent 51fd5dc commit 72a9acc

File tree

711 files changed

+1767
-2129
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

711 files changed

+1767
-2129
lines changed

compiler/ast/src/common/location.rs

Lines changed: 4 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -14,52 +14,17 @@
1414
// You should have received a copy of the GNU General Public License
1515
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
1616

17-
use crate::CompositeType;
1817
use leo_span::Symbol;
19-
use serde::{Deserialize, Deserializer, Serialize, Serializer};
18+
use serde::{Deserialize, Serialize};
2019

21-
// Create custom struct to wrap (Symbol, Symbol) so that it can be serialized and deserialized.
22-
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
20+
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
2321
pub struct Location {
24-
pub program: Option<Symbol>,
22+
pub program: Symbol,
2523
pub name: Symbol,
2624
}
2725

2826
impl Location {
29-
// Create new Location instance.
30-
pub fn new(program: Option<Symbol>, name: Symbol) -> Location {
27+
pub fn new(program: Symbol, name: Symbol) -> Location {
3128
Location { program, name }
3229
}
3330
}
34-
35-
impl From<&CompositeType> for Location {
36-
fn from(composite: &CompositeType) -> Location {
37-
Location::new(composite.program, composite.id.name)
38-
}
39-
}
40-
41-
impl Serialize for Location {
42-
fn serialize<S>(&self, serializer: S) -> leo_errors::Result<S::Ok, S::Error>
43-
where
44-
S: Serializer,
45-
{
46-
let condensed_str = match self.program {
47-
Some(program) => format!("{}/{}", program, self.name),
48-
None => format!("{}", self.name),
49-
};
50-
serializer.serialize_str(&condensed_str)
51-
}
52-
}
53-
54-
impl<'de> Deserialize<'de> for Location {
55-
fn deserialize<D>(deserializer: D) -> leo_errors::Result<Location, D::Error>
56-
where
57-
D: Deserializer<'de>,
58-
{
59-
let s = String::deserialize(deserializer)?;
60-
let mut parts: Vec<&str> = s.split('/').collect();
61-
let program = if parts.len() == 1 { None } else { Some(Symbol::intern(parts.remove(0))) };
62-
let name = Symbol::intern(parts.first().unwrap());
63-
Ok(Location::new(program, name))
64-
}
65-
}

compiler/ast/src/stub/function_stub.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ impl FunctionStub {
178178
id: Default::default(),
179179
type_: Type::Future(FutureType::new(
180180
Vec::new(),
181-
Some(Location::new(Some(program), Identifier::from(function.name()).name)),
181+
Some(Location::new(program, Identifier::from(function.name()).name)),
182182
false,
183183
)),
184184
}],
@@ -278,7 +278,7 @@ impl FunctionStub {
278278
FutureFinalizeType(val) => Type::Future(FutureType::new(
279279
Vec::new(),
280280
Some(Location::new(
281-
Some(Identifier::from(val.program_id().name()).name),
281+
Identifier::from(val.program_id().name()).name,
282282
Symbol::intern(&format!("finalize/{}", val.resource())),
283283
)),
284284
false,

compiler/compiler/src/compiler.rs

Lines changed: 5 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ use crate::CompilerOptions;
2323
pub use leo_ast::Ast;
2424
use leo_ast::{NodeBuilder, Program, Stub};
2525
use leo_errors::{CompilerError, Result, emitter::Handler};
26-
pub use leo_passes::SymbolTable;
2726
use leo_passes::*;
2827
use leo_span::{Symbol, source_map::FileName, symbol::with_session_globals};
2928

@@ -147,19 +146,17 @@ impl<'a, N: Network> Compiler<'a, N> {
147146
/// Runs the symbol table pass.
148147
pub fn symbol_table_pass(&self) -> Result<SymbolTable> {
149148
let symbol_table = SymbolTableCreator::do_pass((&self.ast, self.handler))?;
150-
if self.compiler_options.output.initial_symbol_table {
151-
self.write_symbol_table_to_json("initial_symbol_table.json", &symbol_table)?;
152-
}
153149
Ok(symbol_table)
154150
}
155151

156152
/// Runs the type checker pass.
157153
pub fn type_checker_pass(&'a self, symbol_table: SymbolTable) -> Result<(SymbolTable, StructGraph, CallGraph)> {
158154
let (symbol_table, struct_graph, call_graph) =
159-
TypeChecker::<N>::do_pass((&self.ast, self.handler, symbol_table, &self.type_table))?;
160-
if self.compiler_options.output.type_checked_symbol_table {
161-
self.write_symbol_table_to_json("type_checked_symbol_table.json", &symbol_table)?;
162-
}
155+
TypeChecker::do_pass((&self.ast, self.handler, symbol_table, &self.type_table, NetworkLimits {
156+
max_array_elements: N::MAX_ARRAY_ELEMENTS,
157+
max_mappings: N::MAX_MAPPINGS,
158+
max_functions: N::MAX_FUNCTIONS,
159+
}))?;
163160
Ok((symbol_table, struct_graph, call_graph))
164161
}
165162

@@ -190,10 +187,6 @@ impl<'a, N: Network> Compiler<'a, N> {
190187
self.write_ast_to_json("unrolled_ast.json")?;
191188
}
192189

193-
if self.compiler_options.output.unrolled_symbol_table {
194-
self.write_symbol_table_to_json("unrolled_symbol_table.json", &symbol_table)?;
195-
}
196-
197190
Ok(symbol_table)
198191
}
199192

@@ -340,22 +333,6 @@ impl<'a, N: Network> Compiler<'a, N> {
340333
Ok(())
341334
}
342335

343-
/// Writes the Symbol Table to a JSON file.
344-
fn write_symbol_table_to_json(&self, file_suffix: &str, symbol_table: &SymbolTable) -> Result<()> {
345-
// Remove `Span`s if they are not enabled.
346-
if self.compiler_options.output.symbol_table_spans_enabled {
347-
symbol_table
348-
.to_json_file(self.output_directory.clone(), &format!("{}.{file_suffix}", self.program_name))?;
349-
} else {
350-
symbol_table.to_json_file_without_keys(
351-
self.output_directory.clone(),
352-
&format!("{}.{file_suffix}", self.program_name),
353-
&["_span", "span"],
354-
)?;
355-
}
356-
Ok(())
357-
}
358-
359336
/// Merges the dependencies defined in `program.json` with the dependencies imported in `.leo` file
360337
pub fn add_import_stubs(&mut self) -> Result<()> {
361338
// Create a list of both the explicit dependencies specified in the `.leo` file, as well as the implicit ones derived from those dependencies.

compiler/compiler/src/options.rs

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,6 @@ pub struct BuildOptions {
3636

3737
#[derive(Clone, Default)]
3838
pub struct OutputOptions {
39-
//// Whether spans are enabled in the output symbol tables.
40-
pub symbol_table_spans_enabled: bool,
41-
// If enabled writes the symbol table after symbol table pass
42-
pub initial_symbol_table: bool,
43-
/// If enabled writes the symbol table after type checking.
44-
pub type_checked_symbol_table: bool,
45-
/// If enabled writes the symbol table after loop unrolling.
46-
pub unrolled_symbol_table: bool,
4739
/// Whether spans are enabled in the output ASTs.
4840
pub ast_spans_enabled: bool,
4941
/// If enabled writes the AST after parsing.

compiler/compiler/tests/integration/compile.rs

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -72,10 +72,6 @@ fn run_test(test: Test, handler: &Handler, buf: &BufferEmitter) -> Result<Value,
7272
let compiler_options = CompilerOptions {
7373
build,
7474
output: OutputOptions {
75-
symbol_table_spans_enabled: false,
76-
initial_symbol_table: true,
77-
type_checked_symbol_table: true,
78-
unrolled_symbol_table: true,
7975
ast_spans_enabled: false,
8076
initial_ast: true,
8177
unrolled_ast: true,
@@ -137,19 +133,12 @@ fn run_test(test: Test, handler: &Handler, buf: &BufferEmitter) -> Result<Value,
137133
let (initial_ast, unrolled_ast, ssa_ast, flattened_ast, destructured_ast, inlined_ast, dce_ast) =
138134
hash_asts(&program_name);
139135

140-
// Hash the symbol tables.
141-
let (initial_symbol_table, type_checked_symbol_table, unrolled_symbol_table) =
142-
hash_symbol_tables(&program_name);
143-
144136
// Clean up the output directory.
145137
if fs::read_dir("/tmp/output").is_ok() {
146138
fs::remove_dir_all(Path::new("/tmp/output")).expect("Error failed to clean up output dir.");
147139
}
148140

149141
let output = CompileOutput {
150-
initial_symbol_table,
151-
type_checked_symbol_table,
152-
unrolled_symbol_table,
153142
initial_ast,
154143
unrolled_ast,
155144
ssa_ast,

compiler/compiler/tests/integration/execute.rs

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -89,10 +89,6 @@ fn run_test(test: Test, handler: &Handler, buf: &BufferEmitter) -> Result<Value,
8989
let compiler_options = CompilerOptions {
9090
build,
9191
output: OutputOptions {
92-
symbol_table_spans_enabled: false,
93-
initial_symbol_table: true,
94-
type_checked_symbol_table: true,
95-
unrolled_symbol_table: true,
9692
ast_spans_enabled: false,
9793
initial_ast: true,
9894
unrolled_ast: true,
@@ -179,19 +175,12 @@ fn run_test(test: Test, handler: &Handler, buf: &BufferEmitter) -> Result<Value,
179175
let (initial_ast, unrolled_ast, ssa_ast, flattened_ast, destructured_ast, inlined_ast, dce_ast) =
180176
hash_asts(&program_name);
181177

182-
// Hash the symbol tables.
183-
let (initial_symbol_table, type_checked_symbol_table, unrolled_symbol_table) =
184-
hash_symbol_tables(&program_name);
185-
186178
// Clean up the output directory.
187179
if fs::read_dir("/tmp/output").is_ok() {
188180
fs::remove_dir_all(Path::new("/tmp/output")).expect("Error failed to clean up output dir.");
189181
}
190182

191183
let output = CompileOutput {
192-
initial_symbol_table,
193-
type_checked_symbol_table,
194-
unrolled_symbol_table,
195184
initial_ast,
196185
unrolled_ast,
197186
ssa_ast,

compiler/compiler/tests/integration/utilities/mod.rs

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -61,14 +61,6 @@ pub fn hash_asts(program_name: &str) -> (String, String, String, String, String,
6161
(initial_ast, unrolled_ast, ssa_ast, flattened_ast, destructured_ast, inlined_ast, dce_ast)
6262
}
6363

64-
pub fn hash_symbol_tables(program_name: &str) -> (String, String, String) {
65-
let initial_symbol_table = hash_file(&format!("/tmp/output/{program_name}.initial_symbol_table.json"));
66-
let type_checked_symbol_table = hash_file(&format!("/tmp/output/{program_name}.type_checked_symbol_table.json"));
67-
let unrolled_symbol_table = hash_file(&format!("/tmp/output/{program_name}.unrolled_symbol_table.json"));
68-
69-
(initial_symbol_table, type_checked_symbol_table, unrolled_symbol_table)
70-
}
71-
7264
pub fn get_cwd_option(test: &Test) -> Option<PathBuf> {
7365
// Check for CWD option:
7466
// ``` cwd: import ```

compiler/compiler/tests/integration/utilities/output.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,6 @@ use super::*;
1818

1919
#[derive(Deserialize, PartialEq, Eq, Serialize)]
2020
pub struct CompileOutput {
21-
pub initial_symbol_table: String,
22-
pub type_checked_symbol_table: String,
23-
pub unrolled_symbol_table: String,
2421
pub initial_ast: String,
2522
pub unrolled_ast: String,
2623
pub ssa_ast: String,

compiler/passes/src/code_generation/visit_expressions.rs

Lines changed: 26 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,12 @@ impl<'a> CodeGenerator<'a> {
8888
}
8989

9090
fn visit_locator(&mut self, input: &'a LocatorExpression) -> (String, String) {
91-
(format!("{input}"), String::new())
91+
if input.program.name.name == self.program_id.expect("Locators only appear within programs.").name.name {
92+
// This locator refers to the current program, so we only output the name, not the program.
93+
(format!("{}", input.name), String::new())
94+
} else {
95+
(format!("{input}"), String::new())
96+
}
9297
}
9398

9499
fn visit_binary(&mut self, input: &'a BinaryExpression) -> (String, String) {
@@ -518,28 +523,28 @@ impl<'a> CodeGenerator<'a> {
518523
_ => unreachable!("Parsing guarantees that a function name is always an identifier."),
519524
};
520525

521-
// Check if function is external.
522-
let main_program = input.program.unwrap();
526+
let caller_program = self.program_id.expect("Calls only appear within programs.").name.name;
527+
let callee_program = input.program.unwrap_or(caller_program);
528+
529+
let func_symbol = self
530+
.symbol_table
531+
.lookup_function(Location::new(callee_program, function_name))
532+
.expect("Type checking guarantees functions exist");
533+
523534
// Need to determine the program the function originated from as well as if the function has a finalize block.
524-
let mut call_instruction = if main_program != self.program_id.unwrap().name.name {
535+
let mut call_instruction = if caller_program != callee_program {
525536
// All external functions must be defined as stubs.
526-
if self.program.stubs.get(&main_program).is_some() {
527-
format!(" call {}.aleo/{}", main_program, input.function)
528-
} else {
529-
unreachable!("Type checking guarantees that imported and stub programs are well defined.")
530-
}
537+
assert!(
538+
self.program.stubs.get(&callee_program).is_some(),
539+
"Type checking guarantees that imported and stub programs are present."
540+
);
541+
format!(" call {}.aleo/{}", callee_program, input.function)
542+
} else if func_symbol.function.variant.is_async() {
543+
format!(" async {}", self.current_function.unwrap().identifier)
531544
} else {
532-
// Lookup in symbol table to determine if its an async function.
533-
if let Some(func) = self.symbol_table.lookup_fn_symbol(Location::new(input.program, function_name)) {
534-
if func.variant.is_async() && input.program.unwrap() == self.program_id.unwrap().name.name {
535-
format!(" async {}", self.current_function.unwrap().identifier)
536-
} else {
537-
format!(" call {}", input.function)
538-
}
539-
} else {
540-
unreachable!("Type checking guarantees that all functions are well defined.")
541-
}
545+
format!(" call {}", input.function)
542546
};
547+
543548
let mut instructions = String::new();
544549

545550
for argument in input.arguments.iter() {
@@ -552,8 +557,7 @@ impl<'a> CodeGenerator<'a> {
552557
let mut destinations = Vec::new();
553558

554559
// Create operands for the output registers.
555-
let func = &self.symbol_table.lookup_fn_symbol(Location::new(Some(main_program), function_name)).unwrap();
556-
match func.output_type.clone() {
560+
match func_symbol.function.output_type.clone() {
557561
Type::Unit => {} // Do nothing
558562
Type::Tuple(tuple) => match tuple.length() {
559563
0 | 1 => unreachable!("Parsing guarantees that a tuple type has at least two elements"),
@@ -573,7 +577,7 @@ impl<'a> CodeGenerator<'a> {
573577
}
574578

575579
// Add a register for async functions to represent the future created.
576-
if func.variant == Variant::AsyncFunction {
580+
if func_symbol.function.variant == Variant::AsyncFunction {
577581
let destination_register = format!("r{}", self.next_register);
578582
destinations.push(destination_register);
579583
self.next_register += 1;

compiler/passes/src/code_generation/visit_program.rs

Lines changed: 13 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -47,26 +47,17 @@ impl<'a> CodeGenerator<'a> {
4747
// Note that the unwrap is safe since type checking guarantees that the struct dependency graph is acyclic.
4848
let order = self.struct_graph.post_order().unwrap();
4949

50-
// Create a mapping of symbols to references of structs so can perform constant-time lookups.
51-
let structs_map: IndexMap<Symbol, &Composite> = self
52-
.symbol_table
53-
.structs
54-
.iter()
55-
.filter_map(|(name, struct_)| {
56-
// Only include structs and local records.
57-
if !(struct_.is_record
58-
&& struct_.external.map(|program| program != self.program_id.unwrap().name.name).unwrap_or(false))
59-
{
60-
Some((name.name, struct_))
61-
} else {
62-
None
63-
}
64-
})
65-
.collect();
50+
let this_program = self.program_id.unwrap().name.name;
51+
52+
let lookup = |name: Symbol| {
53+
self.symbol_table
54+
.lookup_struct(name)
55+
.or_else(|| self.symbol_table.lookup_record(Location::new(this_program, name)))
56+
};
6657

6758
// Visit each `Struct` or `Record` in the post-ordering and produce an Aleo struct or record.
6859
for name in order.into_iter() {
69-
if let Some(struct_) = structs_map.get(&name) {
60+
if let Some(struct_) = lookup(name) {
7061
program_string.push_str(&self.visit_struct_or_record(struct_));
7162
}
7263
}
@@ -90,13 +81,10 @@ impl<'a> CodeGenerator<'a> {
9081
// Generate code for the associated finalize function.
9182
let finalize = &self
9283
.symbol_table
93-
.lookup_fn_symbol(Location::new(
94-
Some(self.program_id.unwrap().name.name),
95-
function.identifier.name,
96-
))
84+
.lookup_function(Location::new(self.program_id.unwrap().name.name, function.identifier.name))
9785
.unwrap()
9886
.clone()
99-
.finalize
87+
.finalizer
10088
.unwrap();
10189
// Write the finalize string.
10290
function_string.push_str(&self.visit_function_with(
@@ -205,11 +193,10 @@ impl<'a> CodeGenerator<'a> {
205193
};
206194
// Futures are displayed differently in the input section. `input r0 as foo.aleo/bar.future;`
207195
if matches!(input.type_, Type::Future(_)) {
208-
let location = futures
196+
let location = *futures
209197
.next()
210-
.expect("Type checking guarantees we have future locations for each future input")
211-
.clone();
212-
format!("{}.aleo/{}.future", location.program.unwrap(), location.name)
198+
.expect("Type checking guarantees we have future locations for each future input");
199+
format!("{}.aleo/{}.future", location.program, location.name)
213200
} else {
214201
self.visit_type_with_visibility(&input.type_, visibility)
215202
}

0 commit comments

Comments
 (0)