mirror of
https://github.com/AleoHQ/leo.git
synced 2024-12-01 18:56:38 +03:00
add leo dynamic check module
This commit is contained in:
parent
d5a9cefe7c
commit
effdfc7628
13
Cargo.lock
generated
13
Cargo.lock
generated
@ -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",
|
||||
|
@ -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"
|
||||
|
@ -103,7 +103,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
function_name.clone(),
|
||||
None,
|
||||
statement.clone(),
|
||||
function.returns.clone(),
|
||||
function.output.clone(),
|
||||
declared_circuit_reference.clone(),
|
||||
)?;
|
||||
|
||||
@ -116,7 +116,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
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,
|
||||
|
@ -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(),
|
||||
|
40
dynamic-check/Cargo.toml
Normal file
40
dynamic-check/Cargo.toml
Normal file
@ -0,0 +1,40 @@
|
||||
[package]
|
||||
name = "leo-dynamic-check"
|
||||
version = "1.0.3"
|
||||
authors = [ "The Aleo Team <hello@aleo.org>" ]
|
||||
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"
|
305
dynamic-check/src/dynamic_check.rs
Normal file
305
dynamic-check/src/dynamic_check.rs
Normal file
@ -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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
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<FunctionBody>,
|
||||
}
|
||||
|
||||
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::<Vec<_>>();
|
||||
|
||||
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<TypeAssertion>,
|
||||
type_variables: HashSet<TypeVariable>,
|
||||
}
|
||||
|
||||
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<Statement>) {
|
||||
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<String> for TypeElement {
|
||||
fn from(name: String) -> Self {
|
||||
Self::Variable(TypeVariable::from(name))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Identifier> 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<String> for TypeVariable {
|
||||
fn from(name: String) -> Self {
|
||||
Self { name }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Identifier> for TypeVariable {
|
||||
fn from(identifier: Identifier) -> Self {
|
||||
Self::from(identifier.name)
|
||||
}
|
||||
}
|
18
dynamic-check/src/lib.rs
Normal file
18
dynamic-check/src/lib.rs
Normal file
@ -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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
pub mod dynamic_check;
|
||||
pub use self::dynamic_check::*;
|
0
dynamic-check/tests/empty.leo
Normal file
0
dynamic-check/tests/empty.leo
Normal file
73
dynamic-check/tests/mod.rs
Normal file
73
dynamic-check/tests/mod.rs
Normal file
@ -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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
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()
|
||||
}
|
@ -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::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)
|
||||
|
@ -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
|
||||
|
@ -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::{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<Attribute>,
|
||||
}
|
||||
|
@ -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,
|
||||
)?;
|
||||
|
||||
|
@ -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::{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_,
|
||||
|
@ -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::{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<Attribute>,
|
||||
@ -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<Self, Self::Error> {
|
||||
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<Self, TypeError> {
|
||||
let type_ = Type::from_circuit(
|
||||
let type_ = ExtendedType::from_circuit(
|
||||
table,
|
||||
unresolved_function_input.type_,
|
||||
circuit_name,
|
||||
|
@ -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::{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<Self, TypeError> {
|
||||
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 })
|
||||
|
@ -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<Type>, Vec<usize>),
|
||||
Tuple(Vec<Type>),
|
||||
Array(Box<ExtendedType>, Vec<usize>),
|
||||
Tuple(Vec<ExtendedType>),
|
||||
|
||||
// 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::<Result<Vec<_>, _>>()?;
|
||||
|
||||
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<Self, TypeError> {
|
||||
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::<Result<Vec<_>, _>>()?;
|
||||
|
||||
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<Self>, actual: &Type, span: Span) -> Result<(), TypeError> {
|
||||
pub fn check_type(expected_option: &Option<Self>, 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<usize>), TypeError> {
|
||||
pub fn get_type_array(&self, span: Span) -> Result<(&ExtendedType, &Vec<usize>), 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<Type>, TypeError> {
|
||||
pub fn get_type_tuple(&self, span: Span) -> Result<&Vec<ExtendedType>, 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::<Vec<_>>().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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,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::{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<Attribute>,
|
||||
}
|
||||
|
||||
@ -44,7 +44,7 @@ impl From<Circuit> for VariableType {
|
||||
|
||||
VariableType {
|
||||
identifier: identifier.clone(),
|
||||
type_: Type::Circuit(identifier),
|
||||
type_: ExtendedType::Circuit(identifier),
|
||||
attributes: vec![],
|
||||
}
|
||||
}
|
||||
@ -56,7 +56,7 @@ impl From<Function> for VariableType {
|
||||
|
||||
VariableType {
|
||||
identifier: identifier.clone(),
|
||||
type_: Type::Function(identifier.clone()),
|
||||
type_: ExtendedType::Function(identifier.clone()),
|
||||
attributes: vec![],
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ use std::fmt;
|
||||
pub struct Function {
|
||||
pub identifier: Identifier,
|
||||
pub input: Vec<FunctionInput>,
|
||||
pub returns: Option<Type>,
|
||||
pub output: Option<Type>,
|
||||
pub statements: Vec<Statement>,
|
||||
pub span: Span,
|
||||
}
|
||||
@ -47,7 +47,7 @@ impl<'ast> From<AstFunction<'ast>> 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::<Vec<_>>()
|
||||
.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()
|
||||
|
Loading…
Reference in New Issue
Block a user