mirror of
https://github.com/ProvableHQ/leo.git
synced 2025-01-07 19:37:02 +03:00
fixes
This commit is contained in:
parent
313add0493
commit
30cbed0e98
@ -291,18 +291,12 @@ impl ParserContext<'_> {
|
||||
}
|
||||
|
||||
/// Returns a [`Output`] AST node if the next tokens represent a function output.
|
||||
fn parse_function_output(&mut self) -> Result<Output> {
|
||||
// TODO: Could this span be made more accurate?
|
||||
fn parse_output(&mut self) -> Result<Output> {
|
||||
let mode = self.parse_mode()?;
|
||||
let (type_, span) = self.parse_type()?;
|
||||
Ok(Output { mode, type_, span, id: self.node_builder.next_id() })
|
||||
}
|
||||
|
||||
/// Returns a [`Output`] AST node if the next tokens represent a function output.
|
||||
fn parse_output(&mut self) -> Result<Output> {
|
||||
self.parse_function_output()
|
||||
}
|
||||
|
||||
/// Returns an [`Annotation`] AST node if the next tokens represent an annotation.
|
||||
fn parse_annotation(&mut self) -> Result<Annotation> {
|
||||
// Parse the `@` symbol and identifier.
|
||||
|
@ -104,7 +104,7 @@ impl ParserContext<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
Ok((Type::Composite(CompositeType { id: ident, program: None }), ident.span))
|
||||
Ok((Type::Composite(CompositeType { id: ident, program: self.program_name }), ident.span))
|
||||
} else if self.token.token == Token::LeftSquare {
|
||||
// Parse the left bracket.
|
||||
self.expect(&Token::LeftSquare)?;
|
||||
|
@ -59,17 +59,19 @@ pub struct SymbolTable {
|
||||
impl SymbolTable {
|
||||
/// Recursively checks if the symbol table contains an entry for the given symbol.
|
||||
/// Leo does not allow any variable shadowing or overlap between different symbols.
|
||||
pub fn check_shadowing(&self, location: &Location, span: Span) -> Result<()> {
|
||||
pub fn check_shadowing(&self, location: &Location, is_struct: bool, span: Span) -> Result<()> {
|
||||
if self.functions.contains_key(location) {
|
||||
return Err(AstError::shadowed_function(location.name, span).into());
|
||||
} else if self.structs.get(location).is_some() {
|
||||
} else if self.structs.get(location).is_some() && !(location.program.is_none() && is_struct) {
|
||||
// The second half of the conditional makes sure that structs are only caught for shadowing local records during ST creation, not for redefinition of external structs.
|
||||
return Err(AstError::shadowed_record(location.name, span).into());
|
||||
} else if self.structs.get(&Location::new(None, location.name)).is_some() {
|
||||
} else if self.structs.get(&Location::new(None, location.name)).is_some() && !is_struct {
|
||||
// Struct redefinition is allowed. If there are more than one occurrences, the error will be caught in the creator pass.
|
||||
return Err(AstError::shadowed_struct(location.name, span).into());
|
||||
} else if self.variables.contains_key(location) {
|
||||
return Err(AstError::shadowed_variable(location.name, span).into());
|
||||
}
|
||||
if let Some(parent) = self.parent.as_ref() { parent.check_shadowing(location, span) } else { Ok(()) }
|
||||
if let Some(parent) = self.parent.as_ref() { parent.check_shadowing(location, is_struct, span) } else { Ok(()) }
|
||||
}
|
||||
|
||||
/// Returns the current scope index.
|
||||
@ -83,7 +85,7 @@ impl SymbolTable {
|
||||
/// Inserts a function into the symbol table.
|
||||
pub fn insert_fn(&mut self, location: Location, insert: &Function) -> Result<()> {
|
||||
let id = self.scope_index();
|
||||
self.check_shadowing(&location, insert.span)?;
|
||||
self.check_shadowing(&location, false, insert.span)?;
|
||||
self.functions.insert(location, Self::new_function_symbol(id, insert));
|
||||
self.scopes.push(Default::default());
|
||||
Ok(())
|
||||
@ -91,20 +93,23 @@ impl SymbolTable {
|
||||
|
||||
/// Inserts a struct into the symbol table.
|
||||
pub fn insert_struct(&mut self, location: Location, insert: &Composite) -> Result<()> {
|
||||
// Check to see if the struct matches an existing one.
|
||||
if let Some(existing) = self.structs.get(&location) {
|
||||
if !self.check_eq_struct(insert, existing) {
|
||||
return Err(AstError::redefining_external_struct(location.name, existing.span).into());
|
||||
}
|
||||
return Ok(());
|
||||
// Check shadowing.
|
||||
self.check_shadowing(&location, !insert.is_record, insert.span)?;
|
||||
|
||||
if insert.is_record {
|
||||
// Insert the record into the symbol table.
|
||||
self.structs.insert(location, insert.clone());
|
||||
} else {
|
||||
// Don't need to check shadowing if the struct is already inserted.
|
||||
self.check_shadowing(&location, insert.span)?;
|
||||
if let Some(struct_) = self.structs.get(&Location::new(None, location.name)) {
|
||||
// Allow redefinition of external structs so long as the definitions match.
|
||||
if !self.check_eq_struct(insert, struct_) {
|
||||
return Err(AstError::redefining_external_struct(location.name, insert.span).into());
|
||||
}
|
||||
}
|
||||
// Insert with program location set to `None` to reflect that in snarkVM structs are not attached to programs (unlike records).
|
||||
self.structs.insert(Location::new(None, location.name), insert.clone());
|
||||
}
|
||||
|
||||
// Insert the struct into the symbol table.
|
||||
self.structs.insert(location, insert.clone());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -117,7 +122,7 @@ impl SymbolTable {
|
||||
return false;
|
||||
}
|
||||
for (member1, member2) in new.members.iter().zip(old.members.iter()) {
|
||||
if member1.name() != member2.name() || !member1.type_.eq_flat(&member2.type_) {
|
||||
if member1.name() != member2.name() || !member1.type_.eq_flat_relax_struct(&member2.type_) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -126,7 +131,7 @@ impl SymbolTable {
|
||||
|
||||
/// Inserts a variable into the symbol table.
|
||||
pub fn insert_variable(&mut self, location: Location, insert: VariableSymbol) -> Result<()> {
|
||||
self.check_shadowing(&location, insert.span)?;
|
||||
self.check_shadowing(&location, false, insert.span)?;
|
||||
self.variables.insert(location, insert);
|
||||
Ok(())
|
||||
}
|
||||
@ -157,8 +162,8 @@ impl SymbolTable {
|
||||
pub fn lookup_struct(&self, location: Location, main_program: Option<Symbol>) -> Option<&Composite> {
|
||||
if let Some(struct_) = self.structs.get(&location) {
|
||||
return Some(struct_);
|
||||
} else if location.program.is_none() {
|
||||
if let Some(struct_) = self.structs.get(&Location::new(main_program, location.name)) {
|
||||
} else if location.program == main_program {
|
||||
if let Some(struct_) = self.structs.get(&Location::new(None, location.name)) {
|
||||
return Some(struct_);
|
||||
}
|
||||
}
|
||||
|
@ -254,7 +254,7 @@ impl ExpressionConsumer for StaticSingleAssigner<'_> {
|
||||
// Lookup the struct definition.
|
||||
// Note that type checking guarantees that the correct struct definition exists.
|
||||
let struct_definition: &Composite =
|
||||
self.symbol_table.lookup_struct(Location::new(None, input.name.name), self.program).unwrap();
|
||||
self.symbol_table.lookup_struct(Location::new(self.program, input.name.name), self.program).unwrap();
|
||||
|
||||
// Initialize the list of reordered members.
|
||||
let mut reordered_members = Vec::with_capacity(members.len());
|
||||
|
@ -68,8 +68,8 @@ impl<'a> ProgramVisitor<'a> for SymbolTableCreator<'a> {
|
||||
}
|
||||
|
||||
fn visit_struct(&mut self, input: &'a Composite) {
|
||||
// Allow up to one local redefinition for each external struct.
|
||||
if !input.is_record {
|
||||
// Forbid redefinition of structs.
|
||||
if !self.structs.insert(input.name()) {
|
||||
return self.handler.emit_err::<LeoError>(AstError::shadowed_struct(input.name(), input.span).into());
|
||||
}
|
||||
|
@ -647,8 +647,7 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
|
||||
}
|
||||
|
||||
fn visit_struct_init(&mut self, input: &'a StructExpression, additional: &Self::AdditionalInput) -> Self::Output {
|
||||
let struct_ = self.lookup_struct(None, input.name.name);
|
||||
if let Some(struct_) = struct_ {
|
||||
if let Some(struct_) = self.lookup_struct(self.program_name, input.name.name) {
|
||||
// Check struct type name.
|
||||
let ret = self.check_expected_struct(&struct_, additional, input.name.span());
|
||||
|
||||
|
@ -1328,7 +1328,7 @@ impl<'a> TypeChecker<'a> {
|
||||
self.assert_type_is_valid(&finalize.output_type, finalize.span);
|
||||
}
|
||||
|
||||
/// Wrapper around lookup_struct that records all structs that are used in the program.
|
||||
/// Wrapper around lookup_struct that additionally records all structs that are used in the program.
|
||||
pub(crate) fn lookup_struct(&mut self, program: Option<Symbol>, name: Symbol) -> Option<Composite> {
|
||||
let struct_ =
|
||||
self.symbol_table.borrow().lookup_struct(Location::new(program, name), self.program_name).cloned();
|
||||
|
@ -36,7 +36,9 @@ impl<'a> Pass for TypeChecker<'a> {
|
||||
let mut visitor = TypeChecker::new(st, tt, handler);
|
||||
visitor.visit_program(ast.as_repr());
|
||||
handler.last_err().map_err(|e| *e)?;
|
||||
// Remove unused structs from the struct graph.
|
||||
|
||||
// Remove unused structs from the struct graph.
|
||||
// This prevents unused struct definitions from being included in the generated bytecode.
|
||||
visitor.struct_graph.retain_nodes(&visitor.used_structs);
|
||||
Ok((visitor.symbol_table.take(), visitor.struct_graph, visitor.call_graph))
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user