From 51e3ad9f78938c2d0e6f3c5863f24300a339ef45 Mon Sep 17 00:00:00 2001 From: evan-schott <53463459+evan-schott@users.noreply.github.com> Date: Tue, 5 Dec 2023 20:00:56 -0800 Subject: [PATCH] relax external struct shadowing --- .../src/code_generation/visit_expressions.rs | 2 +- .../passes/src/common/symbol_table/mod.rs | 43 +++++++++++++++++-- 2 files changed, 40 insertions(+), 5 deletions(-) diff --git a/compiler/passes/src/code_generation/visit_expressions.rs b/compiler/passes/src/code_generation/visit_expressions.rs index 97b87c34ff..284f629a15 100644 --- a/compiler/passes/src/code_generation/visit_expressions.rs +++ b/compiler/passes/src/code_generation/visit_expressions.rs @@ -519,7 +519,6 @@ impl<'a> CodeGenerator<'a> { } } - // TODO: Cleanup fn visit_call(&mut self, input: &'a CallExpression) -> (String, String) { let (mut call_instruction, has_finalize) = match &input.external { Some(external) => { @@ -531,6 +530,7 @@ impl<'a> CodeGenerator<'a> { }; let stub_scope: ProgramScope; // Lookup the imported program scope. + // TODO: Needs refactor. All imports are stubs now. let imported_program_scope = match self .program .imports diff --git a/compiler/passes/src/common/symbol_table/mod.rs b/compiler/passes/src/common/symbol_table/mod.rs index c69dea16f9..385317b055 100644 --- a/compiler/passes/src/common/symbol_table/mod.rs +++ b/compiler/passes/src/common/symbol_table/mod.rs @@ -23,7 +23,7 @@ pub use variable_symbol::*; use std::cell::RefCell; use leo_ast::{normalize_json_value, remove_key_from_json, Function, Struct}; -use leo_errors::{AstError, Result}; +use leo_errors::{AstError, LeoMessageCode, Result}; use leo_span::{Span, Symbol}; use indexmap::IndexMap; @@ -89,11 +89,46 @@ impl SymbolTable { Ok(()) } + /// Check if the struct is a duplicate of the existing struct. + /// This is used to allow redefinitions of external structs. + pub fn check_duplicate_struct(&self, old: &Struct, new: &Struct) -> bool { + if old.members.len() != new.members.len() { + return false; + } + + for (old_member, new_member) in old.members.iter().zip(new.members.iter()) { + if old_member.identifier.name != new_member.identifier.name { + return false; + } + if old_member.type_ != new_member.type_ { + return false; + } + } + true + } + /// Inserts a struct into the symbol table. pub fn insert_struct(&mut self, symbol: Symbol, insert: &Struct) -> Result<()> { - self.check_shadowing(symbol, insert.span)?; - self.structs.insert(symbol, insert.clone()); - Ok(()) + match self.check_shadowing(symbol, insert.span) { + Ok(_) => { + self.structs.insert(symbol, insert.clone()); + Ok(()) + } + Err(e) => { + if e.error_code() == AstError::shadowed_struct(symbol, insert.span).error_code() { + if self.check_duplicate_struct( + self.structs.get(&symbol).expect("Must be in symbol table since struct already referenced"), + insert, + ) { + Ok(()) + } else { + Err(AstError::redefining_external_struct(symbol).into()) + } + } else { + Err(e) + } + } + } } /// Inserts a variable into the symbol table.