Skip to content

Commit

Permalink
Add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
evan-schott committed Apr 16, 2024
1 parent c296f61 commit 27ef7e5
Show file tree
Hide file tree
Showing 675 changed files with 6,819 additions and 6,658 deletions.
4 changes: 2 additions & 2 deletions compiler/passes/src/flattening/flatten_expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,15 +83,15 @@ impl ExpressionReconstructor for Flattener<'_> {
};

// Note that type checking guarantees that both expressions have the same same type. This is a sanity check.
assert!(first_type.eq_flat(&second_type));
assert!(first_type.eq_flat_relax_struct(&second_type));

match &first_type {
Type::Array(first_type) => self.ternary_array(first_type, &input.condition, &first, &second),
Type::Composite(first_type) => {
// Get the struct definitions.
let first_type = self
.symbol_table
.lookup_struct(Location::new(first_type.program, first_type.id.name))
.lookup_struct(Location::new(None, first_type.id.name), self.program)
.unwrap();
self.ternary_struct(first_type, &input.condition, &first, &second)
}
Expand Down
22 changes: 21 additions & 1 deletion compiler/passes/src/flattening/flatten_program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,29 @@

use crate::Flattener;

use leo_ast::{Finalize, Function, ProgramReconstructor, StatementReconstructor};
use leo_ast::{Finalize, Function, ProgramReconstructor, ProgramScope, Statement, StatementReconstructor};

impl ProgramReconstructor for Flattener<'_> {
/// Flattens a program scope.
fn reconstruct_program_scope(&mut self, input: ProgramScope) -> ProgramScope {
self.program = Some(input.program_id.name.name);
ProgramScope {
program_id: input.program_id,
structs: input.structs.into_iter().map(|(i, c)| (i, self.reconstruct_struct(c))).collect(),
mappings: input.mappings.into_iter().map(|(id, mapping)| (id, self.reconstruct_mapping(mapping))).collect(),
functions: input.functions.into_iter().map(|(i, f)| (i, self.reconstruct_function(f))).collect(),
consts: input
.consts
.into_iter()
.map(|(i, c)| match self.reconstruct_const(c) {
(Statement::Const(declaration), _) => (i, declaration),
_ => unreachable!("`reconstruct_const` can only return `Statement::Const`"),
})
.collect(),
span: input.span,
}
}

/// Flattens a function's body and finalize block, if it exists.
fn reconstruct_function(&mut self, function: Function) -> Function {
// First, flatten the finalize block. This allows us to initialize self.finalizes correctly.
Expand Down
13 changes: 12 additions & 1 deletion compiler/passes/src/flattening/flattener.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ use leo_ast::{
Type,
UnitExpression,
};
use leo_span::Symbol;

pub struct Flattener<'a> {
/// The symbol table associated with the program.
Expand All @@ -64,6 +65,8 @@ pub struct Flattener<'a> {
/// Note that returns are inserted in the order they are encountered during a pre-order traversal of the AST.
/// Note that type checking guarantees that there is at most one return in a basic block.
pub(crate) returns: Vec<(Option<Expression>, ReturnStatement)>,
/// The program name.
pub(crate) program: Option<Symbol>,
}

impl<'a> Flattener<'a> {
Expand All @@ -73,7 +76,15 @@ impl<'a> Flattener<'a> {
node_builder: &'a NodeBuilder,
assigner: &'a Assigner,
) -> Self {
Self { symbol_table, type_table, node_builder, assigner, condition_stack: Vec::new(), returns: Vec::new() }
Self {
symbol_table,
type_table,
node_builder,
assigner,
condition_stack: Vec::new(),
returns: Vec::new(),
program: None,
}
}

/// Clears the state associated with `ReturnStatements`, returning the ones that were previously stored.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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(self.program, input.name.name)).unwrap();
self.symbol_table.lookup_struct(Location::new(None, input.name.name), self.program).unwrap();

// Initialize the list of reordered members.
let mut reordered_members = Vec::with_capacity(members.len());
Expand Down
25 changes: 12 additions & 13 deletions compiler/passes/src/type_checking/check_expressions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.

use crate::{Location, TypeChecker};
use crate::{Location, TypeChecker, VariableSymbol};

use leo_ast::*;
use leo_errors::{emitter::Handler, TypeCheckerError};
Expand Down Expand Up @@ -206,11 +206,7 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
match self.visit_expression(&access.inner, &None) {
Some(Type::Composite(struct_)) => {
// Retrieve the struct definition associated with `identifier`.
let struct_ = self
.symbol_table
.borrow()
.lookup_struct(Location::new(struct_.program, struct_.id.name))
.cloned();
let struct_ = self.lookup_struct(struct_.program, struct_.id.name);
if let Some(struct_) = struct_ {
// Check that `access.name` is a member of the struct.
match struct_.members.iter().find(|member| member.name() == access.name.name) {
Expand Down Expand Up @@ -613,7 +609,7 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {

// Check function argument types.
func.input.iter().zip(input.arguments.iter()).for_each(|(expected, argument)| {
self.visit_expression(argument, &Some(expected.type_()));
self.visit_expression(argument, &Some(expected.type_().clone()));
});

// Add the call to the call graph.
Expand Down Expand Up @@ -651,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.symbol_table.borrow().lookup_struct(Location::new(self.program_name, input.name.name)).cloned();
let struct_ = self.lookup_struct(None, input.name.name);
if let Some(struct_) = struct_ {
// Check struct type name.
let ret = self.check_expected_struct(&struct_, additional, input.name.span());
Expand Down Expand Up @@ -698,12 +693,14 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
}

fn visit_identifier(&mut self, input: &'a Identifier, expected: &Self::AdditionalInput) -> Self::Output {
let var_: VariableSymbol;
if let Some(var) = self.symbol_table.borrow().lookup_variable(Location::new(None, input.name)) {
Some(self.assert_and_return_type(var.type_.clone(), expected, input.span()))
var_ = var.clone();
} else {
self.emit_err(TypeCheckerError::unknown_sym("variable", input.name, input.span()));
None
return None;
}
Some(self.assert_and_return_type(var_.type_.clone(), expected, input.span()))
}

fn visit_literal(&mut self, input: &'a Literal, expected: &Self::AdditionalInput) -> Self::Output {
Expand Down Expand Up @@ -771,14 +768,16 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {

fn visit_locator(&mut self, input: &'a LocatorExpression, expected: &Self::AdditionalInput) -> Self::Output {
// Check that the locator points to a valid resource in the ST.
let loc_: VariableSymbol;
if let Some(var) =
self.symbol_table.borrow().lookup_variable(Location::new(Some(input.program.name.name), input.name))
{
Some(self.assert_and_return_type(var.type_.clone(), expected, input.span()))
loc_ = var.clone();
} else {
self.emit_err(TypeCheckerError::unknown_sym("variable", input.name, input.span()));
None
return None;
}
Some(self.assert_and_return_type(loc_.type_.clone(), expected, input.span()))
}

fn visit_ternary(&mut self, input: &'a TernaryExpression, expected: &Self::AdditionalInput) -> Self::Output {
Expand Down
8 changes: 2 additions & 6 deletions compiler/passes/src/type_checking/check_program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -241,9 +241,7 @@ impl<'a> ProgramVisitor<'a> for TypeChecker<'a> {
match input.key_type.clone() {
Type::Tuple(_) => self.emit_err(TypeCheckerError::invalid_mapping_type("key", "tuple", input.span)),
Type::Composite(struct_type) => {
if let Some(struct_) =
self.symbol_table.borrow().lookup_struct(Location::new(struct_type.program, struct_type.id.name))
{
if let Some(struct_) = self.lookup_struct(struct_type.program, struct_type.id.name) {
if struct_.is_record {
self.emit_err(TypeCheckerError::invalid_mapping_type("key", "record", input.span));
}
Expand All @@ -260,9 +258,7 @@ impl<'a> ProgramVisitor<'a> for TypeChecker<'a> {
match input.value_type.clone() {
Type::Tuple(_) => self.emit_err(TypeCheckerError::invalid_mapping_type("value", "tuple", input.span)),
Type::Composite(struct_type) => {
if let Some(struct_) =
self.symbol_table.borrow().lookup_struct(Location::new(struct_type.program, struct_type.id.name))
{
if let Some(struct_) = self.lookup_struct(struct_type.program, struct_type.id.name) {
if struct_.is_record {
self.emit_err(TypeCheckerError::invalid_mapping_type("value", "record", input.span));
}
Expand Down
11 changes: 2 additions & 9 deletions compiler/passes/src/type_checking/check_statements.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
// Check that the type of the definition is defined.
self.assert_type_is_valid(&input.type_, input.span);

// Check that the type of the definition is not a unit type, singleton tuple type, nested tuple type, or external struct type.
// Check that the type of the definition is not a unit type, singleton tuple type, or nested tuple type.
match &input.type_ {
// If the type is an empty tuple, return an error.
Type::Unit => self.emit_err(TypeCheckerError::lhs_must_be_identifier_or_tuple(input.span)),
Expand All @@ -221,19 +221,12 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
if matches!(type_, Type::Tuple(_)) {
self.emit_err(TypeCheckerError::nested_tuple_type(input.span))
}
if let Type::Composite(composite) = type_ {
self.assert_internal_struct(composite, input.span);
}
}
}
},
Type::Mapping(_) | Type::Err => unreachable!(
"Parsing guarantees that `mapping` and `err` types are not present at this location in the AST."
),
// Make sure there are no instances of external structs created.
Type::Composite(composite) => {
self.assert_internal_struct(composite, input.span);
}
// Otherwise, the type is valid.
_ => (), // Do nothing
}
Expand Down Expand Up @@ -450,7 +443,7 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {

// Check function argument types.
finalize.input.iter().zip(arguments.iter()).for_each(|(expected, argument)| {
self.visit_expression(argument, &Some(expected.type_()));
self.visit_expression(argument, &Some(expected.type_().clone()));
});
}
}
Expand Down
Loading

0 comments on commit 27ef7e5

Please sign in to comment.