From effdfc7628f6b162d6cdc74013727768e1f6104c Mon Sep 17 00:00:00 2001 From: collin Date: Tue, 6 Oct 2020 17:20:51 -0700 Subject: [PATCH] add leo dynamic check module --- Cargo.lock | 13 + Cargo.toml | 5 + compiler/src/function/function.rs | 4 +- core/src/packages/unstable/blake2s.rs | 2 +- dynamic-check/Cargo.toml | 40 +++ dynamic-check/src/dynamic_check.rs | 305 ++++++++++++++++++ dynamic-check/src/lib.rs | 18 ++ dynamic-check/tests/empty.leo | 0 dynamic-check/tests/mod.rs | 73 +++++ symbol-table/src/errors/type_.rs | 14 +- symbol-table/src/types/circuits/circuit.rs | 6 +- .../src/types/circuits/circuit_variable.rs | 4 +- symbol-table/src/types/functions/function.rs | 4 +- .../src/types/functions/function_input.rs | 4 +- .../functions/function_input_variable.rs | 8 +- .../src/types/functions/function_output.rs | 12 +- symbol-table/src/types/type_.rs | 78 ++--- symbol-table/src/types/variables/variable.rs | 8 +- typed/src/functions/function.rs | 6 +- 19 files changed, 529 insertions(+), 75 deletions(-) create mode 100644 dynamic-check/Cargo.toml create mode 100644 dynamic-check/src/dynamic_check.rs create mode 100644 dynamic-check/src/lib.rs create mode 100644 dynamic-check/tests/empty.leo create mode 100644 dynamic-check/tests/mod.rs diff --git a/Cargo.lock b/Cargo.lock index 6bef767a1c..6495689c93 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1276,6 +1276,18 @@ dependencies = [ "thiserror", ] +[[package]] +name = "leo-dynamic-check" +version = "1.0.3" +dependencies = [ + "leo-ast", + "leo-imports", + "leo-symbol-table", + "leo-typed", + "serde", + "thiserror", +] + [[package]] name = "leo-gadgets" version = "1.0.3" @@ -1329,6 +1341,7 @@ dependencies = [ "lazy_static", "leo-compiler", "leo-core", + "leo-dynamic-check", "leo-gadgets", "leo-imports", "leo-input", diff --git a/Cargo.toml b/Cargo.toml index e014240d55..367ce011de 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,6 +29,7 @@ members = [ "ast", "compiler", "core", + "dynamic-check", "gadgets", "imports", "input", @@ -47,6 +48,10 @@ version = "1.0.3" path = "./core" version = "1.0.1" +[dependencies.leo-dynamic-check] +path = "./dynamic-check" +version = "1.0.3" + [dependencies.leo-gadgets] path = "./gadgets" version = "1.0.3" diff --git a/compiler/src/function/function.rs b/compiler/src/function/function.rs index bca4d761e6..07a8bb6894 100644 --- a/compiler/src/function/function.rs +++ b/compiler/src/function/function.rs @@ -103,7 +103,7 @@ impl> ConstrainedProgram { function_name.clone(), None, statement.clone(), - function.returns.clone(), + function.output.clone(), declared_circuit_reference.clone(), )?; @@ -116,7 +116,7 @@ impl> ConstrainedProgram { Self::conditionally_select_result(cs, &mut return_values, results, function.span.clone())?; if let ConstrainedValue::Tuple(ref returns) = return_values { - let return_types = match function.returns { + let return_types = match function.output { Some(Type::Tuple(types)) => types.len(), Some(_) => 1usize, None => 0usize, diff --git a/core/src/packages/unstable/blake2s.rs b/core/src/packages/unstable/blake2s.rs index 2dfa759c88..f64de3d0fb 100644 --- a/core/src/packages/unstable/blake2s.rs +++ b/core/src/packages/unstable/blake2s.rs @@ -86,7 +86,7 @@ impl CoreCircuit for Blake2sCircuit { span: span.clone(), }), ], - returns: Some(Type::Array(Box::new(Type::IntegerType(IntegerType::U8)), vec![32usize])), + output: Some(Type::Array(Box::new(Type::IntegerType(IntegerType::U8)), vec![32usize])), statements: vec![Statement::Return( Expression::CoreFunctionCall( Self::name(), diff --git a/dynamic-check/Cargo.toml b/dynamic-check/Cargo.toml new file mode 100644 index 0000000000..c00cbf8219 --- /dev/null +++ b/dynamic-check/Cargo.toml @@ -0,0 +1,40 @@ +[package] +name = "leo-dynamic-check" +version = "1.0.3" +authors = [ "The Aleo Team " ] +description = "Checks that a program is correct using type inference" +homepage = "https://aleo.org" +respository = "https://github.com/AleoHQ/leo" +keywords = [ + "aleo", + "cryptography", + "leo", + "programming-language", + "zero-knowledge" +] +categories = [ "cryptography::croptocurrencies", "web-programming" ] +include = [ "Cargo.toml", "src", "README.md", "LICENSE.md" ] +license = "GPL-3.0" +edition = "2018" + +[dependencies.leo-ast] +path = "../ast" +version = "1.0.3" + +[dependencies.leo-imports] +path = "../imports" +version = "1.0.3" + +[dependencies.leo-symbol-table] +path = "../symbol-table" +version = "1.0.3" + +[dependencies.leo-typed] +path = "../typed" +version = "1.0.3" + +[dependencies.serde] +version = "1.0" + +[dependencies.thiserror] +version = "1.0" \ No newline at end of file diff --git a/dynamic-check/src/dynamic_check.rs b/dynamic-check/src/dynamic_check.rs new file mode 100644 index 0000000000..4a3f68fb1e --- /dev/null +++ b/dynamic-check/src/dynamic_check.rs @@ -0,0 +1,305 @@ +// Copyright (C) 2019-2020 Aleo Systems Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +use leo_typed::{Expression, Function, Identifier, Program, Span, Statement}; + +use leo_symbol_table::{ExtendedType, FunctionType, SymbolTable}; +use serde::{Deserialize, Serialize}; +use std::collections::HashSet; + +/// Performs a dynamic type inference check over a program. +pub struct DynamicCheck { + symbol_table: SymbolTable, + functions: Vec, +} + +impl DynamicCheck { + /// + /// Return a new `DynamicCheck` from a given program and symbol table. + /// + pub fn new(program: &Program, symbol_table: SymbolTable) -> Self { + let mut dynamic_check = Self { + symbol_table, + functions: vec![], + }; + + dynamic_check.parse_program(program); + + dynamic_check + } + + /// + /// Collects a vector of `TypeAssertion` predicates from a program. + /// + fn parse_program(&mut self, program: &Program) { + let functions = program + .functions + .iter() + .map(|(_identifier, function)| function) + .collect::>(); + + self.parse_functions(functions); + } + + /// + /// Collects a vector of `TypeAssertion` predicates from a vector of functions. + /// + fn parse_functions(&mut self, functions: Vec<&Function>) { + for function in functions { + self.parse_function(function) + } + } + + /// + /// Collects a vector of `TypeAssertion` predicates from a function. + /// + fn parse_function(&mut self, function: &Function) { + let function_body = FunctionBody::new(function.clone(), self.symbol_table.clone()); + + self.functions.push(function_body); + } + + /// + /// Return the result of evaluating all `TypeAssertion` predicates. + /// + /// Will attempt to substitute a `Type` for all `TypeVariable`s. + /// Returns `true` if all `TypeAssertion` predicates are true. + /// Returns ERROR if a `TypeAssertion` predicate is false or a solution does not exist. + /// + pub fn solve(self) -> bool { + for function_body in self.functions { + function_body.solve(); + } + + true + } +} + +/// A vector of `TypeAssertion` predicates created from a function body. +#[derive(Clone)] +pub struct FunctionBody { + function_type: FunctionType, + symbol_table: SymbolTable, + type_assertions: Vec, + type_variables: HashSet, +} + +impl FunctionBody { + /// + /// Collects a vector of `TypeAssertion` predicates from a function. + /// + pub fn new(function: Function, symbol_table: SymbolTable) -> Self { + let name = &function.identifier.name; + let function_type = symbol_table.get_function(name).unwrap().clone(); + + let mut function_body = Self { + function_type, + symbol_table, + type_assertions: vec![], + type_variables: HashSet::new(), + }; + + // Create type assertions for function statements + function_body.parse_statements(&function.statements); + + function_body + } + + /// + /// Collects a vector of `TypeAssertion` predicates from a vector of statements. + /// + fn parse_statements(&mut self, statements: &Vec) { + for statement in statements { + self.parse_statement(statement); + } + } + + /// + /// Collects a vector of `TypeAssertion` predicates from a statement. + /// + fn parse_statement(&mut self, statement: &Statement) { + match statement { + Statement::Return(expression, span) => { + self.parse_statement_return(expression, span); + } + statement => unimplemented!("statement {} not implemented", statement), + } + } + + /// + /// Collects a `TypeAssertion` predicate from a statement return. + /// + fn parse_statement_return(&mut self, expression: &Expression, _span: &Span) { + // Get the function output type. + let output_type = &self.function_type.output.type_; + + // Create the left hand side of a type assertion. + let left = TypeElement::Type(output_type.clone()); + + // Create the right hand side from the statement return expression. + let right = TypeElement::new(expression, self.symbol_table.clone()); + + // Create a new type assertion for the statement return. + let type_assertion = TypeAssertion::new(left, right); + + // Push the new type assertion to this function's list of type assertions. + self.type_assertions.push(type_assertion) + } + + /// + /// Iteratively solves all `TypeAssertions`. + /// + fn solve(self) { + let mut unsolved = self.type_assertions.clone(); + + while !unsolved.is_empty() { + // Pop type assertion from list + let type_assertion = unsolved.pop().unwrap(); + + println!("assertion: {:?}", type_assertion); + + // Get type variable and type + if let Some((type_variable, type_)) = type_assertion.get_substitute() { + // Substitute type variable for type in unsolved + for original in &mut unsolved { + original.substitute(&type_variable, &type_) + } + } + } + + // for type_assertion in unsolved.pop() { + // if let Some((type_variable, type_)) = type_assertion.get_substitute() { + // // Substitute type variable in unsolved type assertions + // for mut original in unsolved { + // original.substitute(type_variable, type_) + // } + // } + // } + } +} + +/// A predicate that evaluates equality between two `TypeElement`s. +#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] +pub struct TypeAssertion { + left: TypeElement, + right: TypeElement, +} + +impl TypeAssertion { + /// + /// Return a `TypeAssertion` predicate from given left and right `TypeElement`s + /// + pub fn new(left: TypeElement, right: TypeElement) -> Self { + Self { left, right } + } + + /// + /// Substitute the given `TypeVariable` for each `TypeElement` in the `TypeAssertion`. + /// + pub fn substitute(&mut self, variable: &TypeVariable, type_: &TypeElement) { + self.left.substitute(variable, type_); + self.right.substitute(variable, type_); + } + + /// + /// Returns true if the left `TypeElement` is equal to the right `TypeElement`. + /// + pub fn evaluate(&self) -> bool { + self.left.eq(&self.right) + } + + pub fn get_substitute(&self) -> Option<(TypeVariable, TypeElement)> { + match (&self.left, &self.right) { + (TypeElement::Variable(variable), element) => Some((variable.clone(), element.clone())), + (TypeElement::Type(type_), TypeElement::Variable(variable)) => { + Some((variable.clone(), TypeElement::Type(type_.clone()))) + } + (TypeElement::Type(_), TypeElement::Type(_)) => None, + } + } +} + +/// A `Type` or a `TypeVariable` in a `TypeAssertion`. +#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] +pub enum TypeElement { + Type(ExtendedType), + Variable(TypeVariable), +} + +impl TypeElement { + /// + /// Return a new `TypeElement` from the given expression and symbol table. + /// + pub fn new(expression: &Expression, _symbol_table: SymbolTable) -> Self { + match expression { + Expression::Identifier(identifier) => Self::from(identifier.clone()), + Expression::Implicit(name, _) => Self::from(name.clone()), + Expression::Boolean(_, _) => Self::boolean(), + expression => unimplemented!("expression {} not implemented", expression), + } + } + + /// + /// Return a boolean `TypeElement`. + /// + pub fn boolean() -> Self { + TypeElement::Type(ExtendedType::Boolean) + } + + /// + /// Substitute the given `TypeElement` if self is equal to the given `TypeVariable`. + /// + pub fn substitute(&mut self, variable: &TypeVariable, type_: &TypeElement) { + match self { + TypeElement::Type(_) => {} + TypeElement::Variable(original) => { + if original.eq(&variable) { + *self = type_.clone() + } + } + } + } +} + +impl From for TypeElement { + fn from(name: String) -> Self { + Self::Variable(TypeVariable::from(name)) + } +} + +impl From for TypeElement { + fn from(identifier: Identifier) -> Self { + Self::Variable(TypeVariable::from(identifier)) + } +} + +/// An unknown type in a `TypeAssertion`. +#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] +pub struct TypeVariable { + name: String, +} + +impl From for TypeVariable { + fn from(name: String) -> Self { + Self { name } + } +} + +impl From for TypeVariable { + fn from(identifier: Identifier) -> Self { + Self::from(identifier.name) + } +} diff --git a/dynamic-check/src/lib.rs b/dynamic-check/src/lib.rs new file mode 100644 index 0000000000..ddebbdd6a7 --- /dev/null +++ b/dynamic-check/src/lib.rs @@ -0,0 +1,18 @@ +// Copyright (C) 2019-2020 Aleo Systems Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +pub mod dynamic_check; +pub use self::dynamic_check::*; diff --git a/dynamic-check/tests/empty.leo b/dynamic-check/tests/empty.leo new file mode 100644 index 0000000000..e69de29bb2 diff --git a/dynamic-check/tests/mod.rs b/dynamic-check/tests/mod.rs new file mode 100644 index 0000000000..21c3928b25 --- /dev/null +++ b/dynamic-check/tests/mod.rs @@ -0,0 +1,73 @@ +// Copyright (C) 2019-2020 Aleo Systems Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +use leo_ast::LeoAst; +use leo_dynamic_check::DynamicCheck; + +use leo_symbol_table::SymbolTable; +use leo_typed::LeoTypedAst; +use std::path::PathBuf; + +const TEST_PROGRAM_PATH: &str = ""; +const TEST_PROGRAM_NAME: &str = "test"; + +/// A helper struct to test a `DynamicCheck`. +pub struct TestDynamicCheck { + dynamic_check: DynamicCheck, +} + +impl TestDynamicCheck { + pub fn new(bytes: &[u8]) -> Self { + // Get file string from bytes. + let file_string = String::from_utf8_lossy(bytes); + + // Get test file path. + let file_path = PathBuf::from(TEST_PROGRAM_PATH); + + // Get parser syntax tree. + let ast = LeoAst::new(&file_path, &*file_string).unwrap(); + + // Get typed syntax tree. + let typed = LeoTypedAst::new(TEST_PROGRAM_NAME, &ast); + let program = typed.into_repr(); + + // Create symbol table. + let mut symbol_table = SymbolTable::new(None); + + // Load symbols into symbol table. + symbol_table.pass_one(&program).unwrap(); + + symbol_table.pass_two(&program).unwrap(); + + // Create dynamic check + let dynamic_check = DynamicCheck::new(&program, symbol_table); + + Self { dynamic_check } + } + + pub fn solve(self) { + self.dynamic_check.solve(); + } +} + +#[test] +fn test_new() { + let bytes = include_bytes!("empty.leo"); + + let dynamic_check = TestDynamicCheck::new(bytes); + + dynamic_check.solve() +} diff --git a/symbol-table/src/errors/type_.rs b/symbol-table/src/errors/type_.rs index 5ae5f8a9be..1b6e85c5a0 100644 --- a/symbol-table/src/errors/type_.rs +++ b/symbol-table/src/errors/type_.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -use crate::Type; +use crate::ExtendedType; use leo_typed::{Error as FormattedError, Identifier, Span}; use std::path::PathBuf; @@ -46,7 +46,7 @@ impl TypeError { /// /// Expected an array type from the given expression. /// - pub fn invalid_array(actual: &Type, span: Span) -> Self { + pub fn invalid_array(actual: &ExtendedType, span: Span) -> Self { let message = format!("Expected array type, found type `{}`.", actual); Self::new_from_span(message, span) @@ -55,7 +55,7 @@ impl TypeError { /// /// Expected a circuit type from the given expression. /// - pub fn invalid_circuit(actual: &Type, span: Span) -> Self { + pub fn invalid_circuit(actual: &ExtendedType, span: Span) -> Self { let message = format!("Expected circuit type, found type `{}`.", actual); Self::new_from_span(message, span) @@ -64,7 +64,7 @@ impl TypeError { /// /// Expected a function type from the given expression. /// - pub fn invalid_function(actual: &Type, span: Span) -> Self { + pub fn invalid_function(actual: &ExtendedType, span: Span) -> Self { let message = format!("Expected function type, found type `{}`.", actual); Self::new_from_span(message, span) @@ -73,7 +73,7 @@ impl TypeError { /// /// Expected an integer type from the given expression. /// - pub fn invalid_integer(actual: &Type, span: Span) -> Self { + pub fn invalid_integer(actual: &ExtendedType, span: Span) -> Self { let message = format!("Expected integer type, found type `{}`.", actual); Self::new_from_span(message, span) @@ -82,7 +82,7 @@ impl TypeError { /// /// Expected a tuple type from the given expression. /// - pub fn invalid_tuple(actual: &Type, span: Span) -> Self { + pub fn invalid_tuple(actual: &ExtendedType, span: Span) -> Self { let message = format!("Expected tuple type, found type `{}`.", actual); Self::new_from_span(message, span) @@ -91,7 +91,7 @@ impl TypeError { /// /// The value of the expression does not match the given explicit type. /// - pub fn mismatched_types(expected: &Type, actual: &Type, span: Span) -> Self { + pub fn mismatched_types(expected: &ExtendedType, actual: &ExtendedType, span: Span) -> Self { let message = format!("Expected type `{}`, found type `{}`.", expected, actual); Self::new_from_span(message, span) diff --git a/symbol-table/src/types/circuits/circuit.rs b/symbol-table/src/types/circuits/circuit.rs index 8d1df94a91..c60fbc736a 100644 --- a/symbol-table/src/types/circuits/circuit.rs +++ b/symbol-table/src/types/circuits/circuit.rs @@ -17,10 +17,10 @@ use crate::{ types::circuits::{CircuitFunctionType, CircuitVariableType}, Attribute, + ExtendedType, FunctionType, ResolvedNode, SymbolTable, - Type, TypeError, }; use leo_typed::{Circuit, CircuitMember, Identifier}; @@ -63,7 +63,7 @@ impl ResolvedNode for CircuitType { match member { CircuitMember::CircuitVariable(is_mutable, variable_identifier, type_) => { // Resolve the type of the circuit member variable. - let type_ = Type::from_circuit( + let type_ = ExtendedType::from_circuit( table, type_, circuit_identifier.clone(), @@ -118,7 +118,7 @@ impl CircuitType { /// If the member is a circuit variable, then the type of the variable is returned. /// If the member is a circuit function, then the return type of the function is returned. /// - pub fn member_type(&self, identifier: &Identifier) -> Result<&Type, TypeError> { + pub fn member_type(&self, identifier: &Identifier) -> Result<&ExtendedType, TypeError> { // Check if the circuit member is a circuit variable. let matched_variable = self .variables diff --git a/symbol-table/src/types/circuits/circuit_variable.rs b/symbol-table/src/types/circuits/circuit_variable.rs index 55b8326b8a..4f936d1237 100644 --- a/symbol-table/src/types/circuits/circuit_variable.rs +++ b/symbol-table/src/types/circuits/circuit_variable.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -use crate::{Attribute, Type}; +use crate::{Attribute, ExtendedType}; use leo_typed::Identifier; use serde::{Deserialize, Serialize}; @@ -24,7 +24,7 @@ pub struct CircuitVariableType { /// The name of the circuit variable pub identifier: Identifier, /// The type of the circuit variable - pub type_: Type, + pub type_: ExtendedType, /// The attributes of the circuit variable pub attributes: Vec, } diff --git a/symbol-table/src/types/functions/function.rs b/symbol-table/src/types/functions/function.rs index f446ec95ec..3a3d98475a 100644 --- a/symbol-table/src/types/functions/function.rs +++ b/symbol-table/src/types/functions/function.rs @@ -60,7 +60,7 @@ impl ResolvedNode for FunctionType { } // Type check function output - let output = FunctionOutputType::resolve(table, (unresolved.returns, unresolved.span))?; + let output = FunctionOutputType::resolve(table, (unresolved.output, unresolved.span))?; Ok(FunctionType { identifier: unresolved.identifier, @@ -114,7 +114,7 @@ impl FunctionType { let output = FunctionOutputType::from_circuit( table, circuit_name.clone(), - unresolved_function.returns, + unresolved_function.output, unresolved_function.span, )?; diff --git a/symbol-table/src/types/functions/function_input.rs b/symbol-table/src/types/functions/function_input.rs index 74df8ede4c..63bf3412c4 100644 --- a/symbol-table/src/types/functions/function_input.rs +++ b/symbol-table/src/types/functions/function_input.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -use crate::{FunctionInputVariableType, ResolvedNode, SymbolTable, Type, TypeError, VariableType}; +use crate::{ExtendedType, FunctionInputVariableType, ResolvedNode, SymbolTable, TypeError, VariableType}; use leo_typed::{FunctionInput, Identifier}; use serde::{Deserialize, Serialize}; @@ -61,7 +61,7 @@ impl FunctionInputType { /// /// Return the `Type` of the current function input. /// - pub fn type_(&self) -> &Type { + pub fn type_(&self) -> &ExtendedType { match self { FunctionInputType::InputKeyword(_) => unimplemented!("ERROR: input type not implemented"), FunctionInputType::Variable(variable) => &variable.type_, diff --git a/symbol-table/src/types/functions/function_input_variable.rs b/symbol-table/src/types/functions/function_input_variable.rs index 5987d5e78f..ecb8086a1b 100644 --- a/symbol-table/src/types/functions/function_input_variable.rs +++ b/symbol-table/src/types/functions/function_input_variable.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -use crate::{Attribute, ResolvedNode, SymbolTable, Type, TypeError, VariableType}; +use crate::{Attribute, ExtendedType, ResolvedNode, SymbolTable, TypeError, VariableType}; use leo_typed::{FunctionInputVariable, Identifier, Span}; use serde::{Deserialize, Serialize}; @@ -25,7 +25,7 @@ pub struct FunctionInputVariableType { pub identifier: Identifier, /// Type of function input. - pub type_: Type, + pub type_: ExtendedType, /// The attributes of the function input. pub attributes: Vec, @@ -44,7 +44,7 @@ impl ResolvedNode for FunctionInputVariableType { /// Performs a lookup in the given symbol table if the type is user-defined. /// fn resolve(table: &mut SymbolTable, unresolved: Self::UnresolvedNode) -> Result { - let type_ = Type::resolve(table, (unresolved.type_, unresolved.span.clone()))?; + let type_ = ExtendedType::resolve(table, (unresolved.type_, unresolved.span.clone()))?; let attributes = if unresolved.mutable { vec![Attribute::Mutable] } else { @@ -74,7 +74,7 @@ impl FunctionInputVariableType { unresolved_function_input: FunctionInputVariable, circuit_name: Identifier, ) -> Result { - let type_ = Type::from_circuit( + let type_ = ExtendedType::from_circuit( table, unresolved_function_input.type_, circuit_name, diff --git a/symbol-table/src/types/functions/function_output.rs b/symbol-table/src/types/functions/function_output.rs index 0f403b6ae4..837d1568ab 100644 --- a/symbol-table/src/types/functions/function_output.rs +++ b/symbol-table/src/types/functions/function_output.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -use crate::{ResolvedNode, SymbolTable, Type, TypeError}; +use crate::{ExtendedType, ResolvedNode, SymbolTable, TypeError}; use leo_typed::{Identifier, Span, Type as UnresolvedType}; @@ -23,7 +23,7 @@ use serde::{Deserialize, Serialize}; #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct FunctionOutputType { /// Type of function output. - pub type_: Type, + pub type_: ExtendedType, } impl ResolvedNode for FunctionOutputType { @@ -41,8 +41,8 @@ impl ResolvedNode for FunctionOutputType { let span = unresolved.1; let type_ = match function_output { - None => Type::Tuple(vec![]), // functions with no return value return an empty tuple - Some(type_) => Type::resolve(table, (type_, span))?, + None => ExtendedType::Tuple(vec![]), // functions with no return value return an empty tuple + Some(type_) => ExtendedType::resolve(table, (type_, span))?, }; Ok(FunctionOutputType { type_ }) @@ -65,8 +65,8 @@ impl FunctionOutputType { span: Span, ) -> Result { let output_type = match unresolved { - None => Type::Tuple(vec![]), - Some(type_) => Type::from_circuit(table, type_, circuit_name, span)?, + None => ExtendedType::Tuple(vec![]), + Some(type_) => ExtendedType::from_circuit(table, type_, circuit_name, span)?, }; Ok(FunctionOutputType { type_: output_type }) diff --git a/symbol-table/src/types/type_.rs b/symbol-table/src/types/type_.rs index 9a13e979a1..9dc6105469 100644 --- a/symbol-table/src/types/type_.rs +++ b/symbol-table/src/types/type_.rs @@ -23,7 +23,7 @@ use std::fmt; /// /// This type cannot be an implicit or `Self` type. #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -pub enum Type { +pub enum ExtendedType { // Data types Address, Boolean, @@ -32,15 +32,15 @@ pub enum Type { IntegerType(IntegerType), // Data type wrappers - Array(Box, Vec), - Tuple(Vec), + Array(Box, Vec), + Tuple(Vec), // User defined types Circuit(Identifier), Function(Identifier), } -impl ResolvedNode for Type { +impl ResolvedNode for ExtendedType { type Error = TypeError; type UnresolvedNode = (UnresolvedType, Span); @@ -54,24 +54,24 @@ impl ResolvedNode for Type { let span = unresolved.1; Ok(match type_ { - UnresolvedType::Address => Type::Address, - UnresolvedType::Boolean => Type::Boolean, - UnresolvedType::Field => Type::Field, - UnresolvedType::Group => Type::Group, - UnresolvedType::IntegerType(integer) => Type::IntegerType(integer), + UnresolvedType::Address => ExtendedType::Address, + UnresolvedType::Boolean => ExtendedType::Boolean, + UnresolvedType::Field => ExtendedType::Field, + UnresolvedType::Group => ExtendedType::Group, + UnresolvedType::IntegerType(integer) => ExtendedType::IntegerType(integer), UnresolvedType::Array(type_, dimensions) => { - let array_type = Type::resolve(table, (*type_, span))?; + let array_type = ExtendedType::resolve(table, (*type_, span))?; - Type::Array(Box::new(array_type), dimensions) + ExtendedType::Array(Box::new(array_type), dimensions) } UnresolvedType::Tuple(types) => { let tuple_types = types .into_iter() - .map(|type_| Type::resolve(table, (type_, span.clone()))) + .map(|type_| ExtendedType::resolve(table, (type_, span.clone()))) .collect::, _>>()?; - Type::Tuple(tuple_types) + ExtendedType::Tuple(tuple_types) } UnresolvedType::Circuit(identifier) => { @@ -80,7 +80,7 @@ impl ResolvedNode for Type { .get_circuit(&identifier.name) .ok_or(TypeError::undefined_circuit(identifier))?; - Type::Circuit(circuit_type.identifier.clone()) + ExtendedType::Circuit(circuit_type.identifier.clone()) } UnresolvedType::SelfType => { @@ -91,7 +91,7 @@ impl ResolvedNode for Type { } } -impl Type { +impl ExtendedType { /// /// Resolve a type inside of a circuit definition. /// @@ -105,27 +105,27 @@ impl Type { ) -> Result { Ok(match type_ { UnresolvedType::Array(type_, dimensions) => { - let array_type = Type::from_circuit(table, *type_, circuit_name, span)?; - Type::Array(Box::new(array_type), dimensions) + let array_type = ExtendedType::from_circuit(table, *type_, circuit_name, span)?; + ExtendedType::Array(Box::new(array_type), dimensions) } UnresolvedType::Tuple(types) => { let tuple_types = types .into_iter() - .map(|type_| Type::from_circuit(table, type_, circuit_name.clone(), span.clone())) + .map(|type_| ExtendedType::from_circuit(table, type_, circuit_name.clone(), span.clone())) .collect::, _>>()?; - Type::Tuple(tuple_types) + ExtendedType::Tuple(tuple_types) } - UnresolvedType::SelfType => Type::Circuit(circuit_name), + UnresolvedType::SelfType => ExtendedType::Circuit(circuit_name), // The unresolved type does not depend on the current circuit definition - unresolved => Type::resolve(table, (unresolved, span))?, + unresolved => ExtendedType::resolve(table, (unresolved, span))?, }) } /// /// Returns `Ok` if the given expected type is `Some` and expected type == actual type. /// - pub fn check_type(expected_option: &Option, actual: &Type, span: Span) -> Result<(), TypeError> { + pub fn check_type(expected_option: &Option, actual: &ExtendedType, span: Span) -> Result<(), TypeError> { if let Some(expected) = expected_option { if expected.ne(actual) { return Err(TypeError::mismatched_types(expected, actual, span)); @@ -139,7 +139,7 @@ impl Type { /// pub fn check_type_integer(&self, span: Span) -> Result<(), TypeError> { match self { - Type::IntegerType(_) => Ok(()), + ExtendedType::IntegerType(_) => Ok(()), // Throw mismatched type error type_ => Err(TypeError::invalid_integer(type_, span)), } @@ -148,9 +148,9 @@ impl Type { /// /// Returns array element type and dimensions if self is an expected array type `Type::Array`. /// - pub fn get_type_array(&self, span: Span) -> Result<(&Type, &Vec), TypeError> { + pub fn get_type_array(&self, span: Span) -> Result<(&ExtendedType, &Vec), TypeError> { match self { - Type::Array(element_type, dimensions) => Ok((element_type, dimensions)), + ExtendedType::Array(element_type, dimensions) => Ok((element_type, dimensions)), // Throw mismatched type error type_ => Err(TypeError::invalid_array(type_, span)), } @@ -159,9 +159,9 @@ impl Type { /// /// Returns tuple element types if self is an expected tuple type `Type::Tuple`. /// - pub fn get_type_tuple(&self, span: Span) -> Result<&Vec, TypeError> { + pub fn get_type_tuple(&self, span: Span) -> Result<&Vec, TypeError> { match self { - Type::Tuple(types) => Ok(types), + ExtendedType::Tuple(types) => Ok(types), // Throw mismatched type error type_ => Err(TypeError::invalid_tuple(type_, span)), } @@ -172,7 +172,7 @@ impl Type { /// pub fn get_type_circuit(&self, span: Span) -> Result<&Identifier, TypeError> { match self { - Type::Circuit(identifier) => Ok(identifier), + ExtendedType::Circuit(identifier) => Ok(identifier), // Throw mismatched type error type_ => Err(TypeError::invalid_circuit(type_, span)), } @@ -183,23 +183,23 @@ impl Type { /// pub fn get_type_function(&self, span: Span) -> Result<&Identifier, TypeError> { match self { - Type::Function(identifier) => Ok(identifier), + ExtendedType::Function(identifier) => Ok(identifier), // Throw mismatched type error type_ => Err(TypeError::invalid_function(type_, span)), } } } -impl fmt::Display for Type { +impl fmt::Display for ExtendedType { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match &self { - Type::Address => write!(f, "address"), - Type::Boolean => write!(f, "bool"), - Type::Field => write!(f, "field"), - Type::Group => write!(f, "group"), - Type::IntegerType(integer_type) => write!(f, "{}", integer_type), + ExtendedType::Address => write!(f, "address"), + ExtendedType::Boolean => write!(f, "bool"), + ExtendedType::Field => write!(f, "field"), + ExtendedType::Group => write!(f, "group"), + ExtendedType::IntegerType(integer_type) => write!(f, "{}", integer_type), - Type::Array(type_, dimensions) => { + ExtendedType::Array(type_, dimensions) => { let dimensions_string = dimensions .iter() .map(|dimension| format!("{}", dimension)) @@ -208,14 +208,14 @@ impl fmt::Display for Type { write!(f, "[{}; ({})]", *type_, dimensions_string) } - Type::Tuple(tuple) => { + ExtendedType::Tuple(tuple) => { let tuple_string = tuple.iter().map(|x| format!("{}", x)).collect::>().join(", "); write!(f, "({})", tuple_string) } - Type::Circuit(identifier) => write!(f, "circuit {}", identifier), - Type::Function(identifier) => write!(f, "function {}", identifier), + ExtendedType::Circuit(identifier) => write!(f, "circuit {}", identifier), + ExtendedType::Function(identifier) => write!(f, "function {}", identifier), } } } diff --git a/symbol-table/src/types/variables/variable.rs b/symbol-table/src/types/variables/variable.rs index 4d30977fb7..e5ef783d93 100644 --- a/symbol-table/src/types/variables/variable.rs +++ b/symbol-table/src/types/variables/variable.rs @@ -13,7 +13,7 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -use crate::{Attribute, Type}; +use crate::{Attribute, ExtendedType}; use leo_typed::{Circuit, Function, Identifier}; use crate::FunctionInputVariableType; @@ -25,7 +25,7 @@ use std::fmt; #[derive(Clone, Debug, Eq, PartialEq, Hash)] pub struct VariableType { pub identifier: Identifier, - pub type_: Type, + pub type_: ExtendedType, pub attributes: Vec, } @@ -44,7 +44,7 @@ impl From for VariableType { VariableType { identifier: identifier.clone(), - type_: Type::Circuit(identifier), + type_: ExtendedType::Circuit(identifier), attributes: vec![], } } @@ -56,7 +56,7 @@ impl From for VariableType { VariableType { identifier: identifier.clone(), - type_: Type::Function(identifier.clone()), + type_: ExtendedType::Function(identifier.clone()), attributes: vec![], } } diff --git a/typed/src/functions/function.rs b/typed/src/functions/function.rs index 9d1e1d718b..ab16d6b2ce 100644 --- a/typed/src/functions/function.rs +++ b/typed/src/functions/function.rs @@ -24,7 +24,7 @@ use std::fmt; pub struct Function { pub identifier: Identifier, pub input: Vec, - pub returns: Option, + pub output: Option, pub statements: Vec, pub span: Span, } @@ -47,7 +47,7 @@ impl<'ast> From> for Function { Function { identifier: function_name, input: parameters, - returns, + output: returns, statements, span: Span::from(function.span), } @@ -67,7 +67,7 @@ impl Function { .map(|x| format!("{}", x)) .collect::>() .join(","); - let returns = self.returns.as_ref().map(|type_| format!("{}", type_)); + let returns = self.output.as_ref().map(|type_| format!("{}", type_)); let statements = self .statements .iter()