diff --git a/compiler/ast/src/passes/visitor_director.rs b/compiler/ast/src/passes/visitor_director.rs index f1cb373a21..9fee6cdda1 100644 --- a/compiler/ast/src/passes/visitor_director.rs +++ b/compiler/ast/src/passes/visitor_director.rs @@ -76,7 +76,6 @@ impl<'a, V: ExpressionVisitor<'a>> VisitorDirector<'a, V> { pub fn visit_call(&mut self, input: &'a CallExpression) { if let VisitResult::VisitChildren = self.visitor.visit_call(input) { - self.visit_expression(&input.function); for expr in input.arguments.iter() { self.visit_expression(expr); } diff --git a/compiler/passes/src/symbol_table/table.rs b/compiler/passes/src/symbol_table/table.rs index 5425c24af5..3ec37efa08 100644 --- a/compiler/passes/src/symbol_table/table.rs +++ b/compiler/passes/src/symbol_table/table.rs @@ -16,7 +16,7 @@ use std::fmt::Display; -use leo_ast::Function; +use leo_ast::{DefinitionStatement, Function, FunctionInput}; use leo_errors::{AstError, Result}; use leo_span::Symbol; @@ -31,7 +31,7 @@ pub struct SymbolTable<'a> { functions: IndexMap, /// Variables represents functions variable definitions and input variables. /// This field is not populated till necessary. - variables: VariableSymbol<'a>, + pub(crate) variables: VariableSymbol<'a>, } impl<'a> SymbolTable<'a> { @@ -48,15 +48,35 @@ impl<'a> SymbolTable<'a> { self.variables.clear(); } - pub fn insert_fn(&mut self, symbol: Symbol, function: &'a Function) -> Result<()> { + pub fn insert_fn(&mut self, symbol: Symbol, insert: &'a Function) -> Result<()> { self.check_shadowing(&symbol)?; - self.functions.insert(symbol, function); + self.functions.insert(symbol, insert); Ok(()) } - pub fn lookup_fn(&mut self, symbol: &Symbol) -> Option<&&'a Function> { + pub fn insert_fn_input(&mut self, symbol: Symbol, insert: &'a FunctionInput) -> Result<()> { + self.check_shadowing(&symbol)?; + self.variables.inputs.insert(symbol, insert); + Ok(()) + } + + pub fn insert_variable(&mut self, symbol: Symbol, insert: &'a DefinitionStatement) -> Result<()> { + self.check_shadowing(&symbol)?; + self.variables.variables.insert(symbol, insert); + Ok(()) + } + + pub fn lookup_fn(&self, symbol: &Symbol) -> Option<&&'a Function> { self.functions.get(symbol) } + + pub fn lookup_fn_input(&self, symbol: &Symbol) -> Option<&&'a FunctionInput> { + self.variables.inputs.get(symbol) + } + + pub fn lookup_var(&self, symbol: &Symbol) -> Option<&&'a DefinitionStatement> { + self.variables.variables.get(symbol) + } } impl<'a> Display for SymbolTable<'a> { diff --git a/compiler/passes/src/symbol_table/variable_symbol.rs b/compiler/passes/src/symbol_table/variable_symbol.rs index 01d3bd4776..0903c84dcf 100644 --- a/compiler/passes/src/symbol_table/variable_symbol.rs +++ b/compiler/passes/src/symbol_table/variable_symbol.rs @@ -17,7 +17,7 @@ use std::fmt::Display; use indexmap::IndexMap; -use leo_ast::{DefinitionStatement, FunctionInput, FunctionInputVariable}; +use leo_ast::{DefinitionStatement, FunctionInput, Node}; use leo_errors::{AstError, Result}; use leo_span::Symbol; @@ -27,33 +27,20 @@ pub struct VariableSymbol<'a> { /// For example if we are in a if block inside a function. /// The parent would be the functions variables and inputs. /// This field is populated as necessary. - parent: Option>>, + pub(crate) parent: Option>>, /// The input variables defined in a scope. /// This field is populated as necessary. - inputs: IndexMap, + pub(crate) inputs: IndexMap, /// The variables defined in a scope. /// This field is populated as necessary. - variables: IndexMap, + pub(crate) variables: IndexMap, } impl<'a> VariableSymbol<'a> { - pub fn new(parent: Option>>, inputs: Vec<&'a FunctionInput>) -> Self { - Self { - parent, - inputs: inputs - .iter() - .map(|input| { - let inner = input.get_variable(); - (inner.identifier.name, inner) - }) - .collect(), - variables: IndexMap::new(), - } - } - pub fn check_shadowing(&self, symbol: &Symbol) -> Result<()> { if let Some(input) = self.inputs.get(symbol) { - Err(AstError::shadowed_function_input(symbol, &input.span).into()) + let span = input.span(); + Err(AstError::shadowed_function_input(symbol, span).into()) } else if let Some(var) = self.variables.get(symbol) { Err(AstError::shadowed_variable(symbol, &var.span).into()) } else if let Some(parent) = &self.parent { diff --git a/compiler/passes/src/type_checker/check.rs b/compiler/passes/src/type_checker/check.rs index 5d6f78446d..9494175b63 100644 --- a/compiler/passes/src/type_checker/check.rs +++ b/compiler/passes/src/type_checker/check.rs @@ -15,28 +15,101 @@ // along with the Leo library. If not, see . use leo_ast::*; +use leo_errors::Result; use crate::TypeChecker; +impl<'a> TypeChecker<'a> { + fn compare_types(&self, t1: Result>, t2: Result>) { + match (t1, t2) { + (Ok(Some(t1)), Ok(Some(t2))) if t1 != t2 => self.handler.emit_err(todo!()), + (Ok(Some(t)), Ok(None)) | (Ok(None), Ok(Some(t))) => self.handler.emit_err(todo!()), + (Err(err), Ok(None)) | (Ok(None), Err(err)) => self.handler.emit_err(err), + (Err(err1), Err(err2)) => { + self.handler.emit_err(err1); + self.handler.emit_err(err2); + } + _ => {} + } + } +} + impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {} +// we can safely unwrap all self.parent instances because +// statements should always have some parent block impl<'a> StatementVisitor<'a> for TypeChecker<'a> { fn visit_return(&mut self, input: &'a ReturnStatement) -> VisitResult { let parent = self.parent.unwrap(); + if let Some(func) = self.symbol_table.lookup_fn(&parent) { - // if func.get_type()? != input.get_type()? { - // // self.handler.emit_err(err); - // } + self.compare_types(func.get_type(), input.get_type()); } VisitResult::VisitChildren } + + fn visit_definition(&mut self, input: &'a DefinitionStatement) -> VisitResult { + input.variable_names.iter().for_each(|v| { + if let Err(err) = self.symbol_table.insert_variable(v.identifier.name, input) { + self.handler.emit_err(err); + } + }); + + VisitResult::VisitChildren + } + + fn visit_assign(&mut self, input: &'a AssignStatement) -> VisitResult { + let input_var = self.symbol_table.lookup_fn_input(&input.assignee.identifier.name); + let var = self.symbol_table.lookup_var(&input.assignee.identifier.name); + + match (input_var, var) { + (Some(var), None) => { + self.compare_types(var.get_type(), input.value.get_type()); + } + (None, Some(var)) => { + self.compare_types(var.get_type(), input.value.get_type()); + } + (None, None) => self.handler.emit_err(todo!()), + // Don't have to error here as shadowing checks are done during insertions. + _ => {} + } + + Default::default() + } + + fn visit_conditional(&mut self, _input: &'a ConditionalStatement) -> VisitResult { + Default::default() + } + + fn visit_iteration(&mut self, _input: &'a IterationStatement) -> VisitResult { + Default::default() + } + + fn visit_console(&mut self, _input: &'a ConsoleStatement) -> VisitResult { + Default::default() + } + + fn visit_expression_statement(&mut self, _input: &'a ExpressionStatement) -> VisitResult { + Default::default() + } + + fn visit_block(&mut self, _input: &'a Block) -> VisitResult { + Default::default() + } } impl<'a> ProgramVisitor<'a> for TypeChecker<'a> { fn visit_function(&mut self, input: &'a Function) -> VisitResult { self.symbol_table.clear_variables(); self.parent = Some(input.name()); + input.input.iter().for_each(|i| { + let symbol = i.get_variable().identifier.name; + if let Err(err) = self.symbol_table.insert_fn_input(symbol, i) { + self.handler.emit_err(err); + } + }); + VisitResult::VisitChildren } } diff --git a/leo/errors/src/errors/parser/parser_errors.rs b/leo/errors/src/errors/parser/parser_errors.rs index 687c97c911..bd7bae6151 100644 --- a/leo/errors/src/errors/parser/parser_errors.rs +++ b/leo/errors/src/errors/parser/parser_errors.rs @@ -291,9 +291,9 @@ create_messages!( /// When the user tries to pass an implicit value. @formatted implicit_values_not_allowed { - args: (input: impl Display), - msg: format!("Could not parse the implicit value: {}.", input), - help: None, + args: (input: impl Display), + msg: format!("Could not parse the implicit value: {}.", input), + help: None, } /// When a escaped unicode char was given but no following closing symbol.