mirror of
https://github.com/AleoHQ/leo.git
synced 2024-12-26 02:53:08 +03:00
add type-inference module
This commit is contained in:
parent
667392237f
commit
69a8b61efe
14
Cargo.lock
generated
14
Cargo.lock
generated
@ -1313,6 +1313,7 @@ dependencies = [
|
||||
"leo-package",
|
||||
"leo-state",
|
||||
"leo-symbol-table",
|
||||
"leo-type-inference",
|
||||
"num-bigint",
|
||||
"pest",
|
||||
"rand",
|
||||
@ -1494,6 +1495,19 @@ dependencies = [
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "leo-type-inference"
|
||||
version = "1.0.4"
|
||||
dependencies = [
|
||||
"leo-ast",
|
||||
"leo-grammar",
|
||||
"leo-imports",
|
||||
"leo-symbol-table",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.80"
|
||||
|
@ -37,7 +37,7 @@ members = [
|
||||
"package",
|
||||
"state",
|
||||
"symbol-table",
|
||||
# "type-inference",
|
||||
"type-inference",
|
||||
]
|
||||
|
||||
[dependencies.leo-ast]
|
||||
|
@ -53,9 +53,9 @@ version = "1.0.4"
|
||||
path = "../symbol-table"
|
||||
version = "1.0.4"
|
||||
|
||||
#[dependencies.leo-type-inference]
|
||||
#path = "../type-inference"
|
||||
#version = "1.0.4"
|
||||
[dependencies.leo-type-inference]
|
||||
path = "../type-inference"
|
||||
version = "1.0.4"
|
||||
|
||||
[dependencies.snarkos-curves]
|
||||
version = "1.1.3"
|
||||
|
@ -30,7 +30,7 @@ use leo_input::LeoInputParser;
|
||||
use leo_package::inputs::InputPairs;
|
||||
use leo_state::verify_local_data_commitment;
|
||||
use leo_symbol_table::SymbolTable;
|
||||
// use leo_type_inference::TypeInference;
|
||||
use leo_type_inference::TypeInference;
|
||||
|
||||
use snarkos_dpc::{base_dpc::instantiated::Components, SystemParameters};
|
||||
use snarkos_errors::gadgets::SynthesisError;
|
||||
@ -206,19 +206,19 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
|
||||
///
|
||||
pub(crate) fn check_program(&self) -> Result<(), CompilerError> {
|
||||
// Create a new symbol table from the program, imported_programs, and program_input.
|
||||
let _symbol_table =
|
||||
let symbol_table =
|
||||
SymbolTable::new(&self.program, &self.imported_programs, &self.program_input).map_err(|mut e| {
|
||||
e.set_path(&self.main_file_path);
|
||||
|
||||
e
|
||||
})?;
|
||||
|
||||
// // Run type inference check on program.
|
||||
// TypeInference::new(&self.program, symbol_table).map_err(|mut e| {
|
||||
// e.set_path(&self.main_file_path);
|
||||
//
|
||||
// e
|
||||
// })?;
|
||||
// Run type inference check on program.
|
||||
TypeInference::new(&self.program, symbol_table).map_err(|mut e| {
|
||||
e.set_path(&self.main_file_path);
|
||||
|
||||
e
|
||||
})?;
|
||||
|
||||
tracing::debug!("Program checks complete");
|
||||
|
||||
@ -253,10 +253,10 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
|
||||
self.imported_programs = ImportParser::parse(&self.program)?;
|
||||
|
||||
// Create a new symbol table from the program, imported programs, and program input.
|
||||
let _symbol_table = SymbolTable::new(&self.program, &self.imported_programs, &self.program_input)?;
|
||||
let symbol_table = SymbolTable::new(&self.program, &self.imported_programs, &self.program_input)?;
|
||||
|
||||
// // Run type inference check on program.
|
||||
// TypeInference::new(&self.program, symbol_table)?;
|
||||
// Run type inference check on program.
|
||||
TypeInference::new(&self.program, symbol_table)?;
|
||||
|
||||
tracing::debug!("Program parsing complete\n{:#?}", self.program);
|
||||
|
||||
|
@ -20,7 +20,7 @@ use leo_imports::ImportParserError;
|
||||
use leo_input::InputParserError;
|
||||
use leo_state::LocalDataVerificationError;
|
||||
use leo_symbol_table::SymbolTableError;
|
||||
// use leo_type_inference::TypeInferenceError;
|
||||
use leo_type_inference::TypeInferenceError;
|
||||
|
||||
use bincode::Error as SerdeError;
|
||||
use std::path::{Path, PathBuf};
|
||||
@ -71,8 +71,8 @@ pub enum CompilerError {
|
||||
|
||||
#[error("{}", _0)]
|
||||
SymbolTableError(#[from] SymbolTableError),
|
||||
// #[error("{}", _0)]
|
||||
// TypeInferenceError(#[from] TypeInferenceError),
|
||||
#[error("{}", _0)]
|
||||
TypeInferenceError(#[from] TypeInferenceError),
|
||||
}
|
||||
|
||||
impl CompilerError {
|
||||
@ -82,7 +82,7 @@ impl CompilerError {
|
||||
CompilerError::FunctionError(error) => error.set_path(path),
|
||||
CompilerError::OutputStringError(error) => error.set_path(path),
|
||||
CompilerError::SymbolTableError(error) => error.set_path(path),
|
||||
// CompilerError::TypeInferenceError(error) => error.set_path(path),
|
||||
CompilerError::TypeInferenceError(error) => error.set_path(path),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,7 @@
|
||||
use crate::{
|
||||
assert_satisfied,
|
||||
expect_compiler_error,
|
||||
expect_type_inference_error,
|
||||
get_output,
|
||||
parse_program,
|
||||
parse_program_with_input,
|
||||
@ -126,13 +127,13 @@ fn test_false_or_false() {
|
||||
assert_satisfied(program);
|
||||
}
|
||||
|
||||
// #[test]
|
||||
// fn test_true_or_u32() {
|
||||
// let bytes = include_bytes!("true_or_u32.leo");
|
||||
// let error = parse_program(bytes).err().unwrap();
|
||||
//
|
||||
// expect_type_inference_error(error);
|
||||
// }
|
||||
#[test]
|
||||
fn test_true_or_u32() {
|
||||
let bytes = include_bytes!("true_or_u32.leo");
|
||||
let error = parse_program(bytes).err().unwrap();
|
||||
|
||||
expect_type_inference_error(error);
|
||||
}
|
||||
|
||||
// Boolean and &&
|
||||
|
||||
@ -160,13 +161,13 @@ fn test_false_and_false() {
|
||||
assert_satisfied(program);
|
||||
}
|
||||
|
||||
// #[test]
|
||||
// fn test_true_and_u32() {
|
||||
// let bytes = include_bytes!("true_and_u32.leo");
|
||||
// let error = parse_program(bytes).err().unwrap();
|
||||
//
|
||||
// expect_type_inference_error(error);
|
||||
// }
|
||||
#[test]
|
||||
fn test_true_and_u32() {
|
||||
let bytes = include_bytes!("true_and_u32.leo");
|
||||
let error = parse_program(bytes).err().unwrap();
|
||||
|
||||
expect_type_inference_error(error);
|
||||
}
|
||||
|
||||
// All
|
||||
|
||||
|
@ -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::{assert_satisfied, expect_compiler_error, parse_program};
|
||||
use crate::{assert_satisfied, expect_compiler_error, expect_type_inference_error, parse_program};
|
||||
|
||||
// Expressions
|
||||
|
||||
@ -34,13 +34,13 @@ fn test_inline_fail() {
|
||||
expect_compiler_error(program);
|
||||
}
|
||||
|
||||
// #[test]
|
||||
// fn test_inline_undefined() {
|
||||
// let bytes = include_bytes!("inline_undefined.leo");
|
||||
// let error = parse_program(bytes).err().unwrap();
|
||||
//
|
||||
// expect_type_inference_error(error);
|
||||
// }
|
||||
#[test]
|
||||
fn test_inline_undefined() {
|
||||
let bytes = include_bytes!("inline_undefined.leo");
|
||||
let error = parse_program(bytes).err().unwrap();
|
||||
|
||||
expect_type_inference_error(error);
|
||||
}
|
||||
|
||||
// Members
|
||||
|
||||
@ -52,13 +52,13 @@ fn test_member_variable() {
|
||||
assert_satisfied(program);
|
||||
}
|
||||
|
||||
// #[test]
|
||||
// fn test_member_variable_fail() {
|
||||
// let bytes = include_bytes!("member_variable_fail.leo");
|
||||
// let error = parse_program(bytes).err().unwrap();
|
||||
//
|
||||
// expect_type_inference_error(error);
|
||||
// }
|
||||
#[test]
|
||||
fn test_member_variable_fail() {
|
||||
let bytes = include_bytes!("member_variable_fail.leo");
|
||||
let error = parse_program(bytes).err().unwrap();
|
||||
|
||||
expect_type_inference_error(error);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_member_variable_and_function() {
|
||||
@ -76,21 +76,21 @@ fn test_member_function() {
|
||||
assert_satisfied(program);
|
||||
}
|
||||
|
||||
// #[test]
|
||||
// fn test_member_function_fail() {
|
||||
// let bytes = include_bytes!("member_function_fail.leo");
|
||||
// let error = parse_program(bytes).err().unwrap();
|
||||
//
|
||||
// expect_type_inference_error(error);
|
||||
// }
|
||||
#[test]
|
||||
fn test_member_function_fail() {
|
||||
let bytes = include_bytes!("member_function_fail.leo");
|
||||
let error = parse_program(bytes).err().unwrap();
|
||||
|
||||
// #[test]
|
||||
// fn test_member_function_invalid() {
|
||||
// let bytes = include_bytes!("member_function_invalid.leo");
|
||||
// let error = parse_program(bytes).err().unwrap();
|
||||
//
|
||||
// expect_type_inference_error(error);
|
||||
// }
|
||||
expect_type_inference_error(error);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_member_function_invalid() {
|
||||
let bytes = include_bytes!("member_function_invalid.leo");
|
||||
let error = parse_program(bytes).err().unwrap();
|
||||
|
||||
expect_type_inference_error(error);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_member_function_nested() {
|
||||
@ -116,31 +116,31 @@ fn test_member_static_function_nested() {
|
||||
assert_satisfied(program);
|
||||
}
|
||||
|
||||
// #[test]
|
||||
// fn test_member_static_function_invalid() {
|
||||
// let bytes = include_bytes!("member_static_function_invalid.leo");
|
||||
// let error = parse_program(bytes).err().unwrap();
|
||||
//
|
||||
// expect_type_inference_error(error)
|
||||
// }
|
||||
#[test]
|
||||
fn test_member_static_function_invalid() {
|
||||
let bytes = include_bytes!("member_static_function_invalid.leo");
|
||||
let error = parse_program(bytes).err().unwrap();
|
||||
|
||||
// #[test]
|
||||
// fn test_member_static_function_undefined() {
|
||||
// let bytes = include_bytes!("member_static_function_undefined.leo");
|
||||
// let error = parse_program(bytes).err().unwrap();
|
||||
//
|
||||
// expect_type_inference_error(error)
|
||||
// }
|
||||
expect_type_inference_error(error)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_member_static_function_undefined() {
|
||||
let bytes = include_bytes!("member_static_function_undefined.leo");
|
||||
let error = parse_program(bytes).err().unwrap();
|
||||
|
||||
expect_type_inference_error(error)
|
||||
}
|
||||
|
||||
// Mutability
|
||||
|
||||
// #[test]
|
||||
// fn test_mutate_function_fail() {
|
||||
// let bytes = include_bytes!("mut_function_fail.leo");
|
||||
// let error = parse_program(bytes).err().unwrap();
|
||||
//
|
||||
// expect_type_inference_error(error);
|
||||
// }
|
||||
#[test]
|
||||
fn test_mutate_function_fail() {
|
||||
let bytes = include_bytes!("mut_function_fail.leo");
|
||||
let error = parse_program(bytes).err().unwrap();
|
||||
|
||||
expect_type_inference_error(error);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mutate_self_variable() {
|
||||
@ -158,29 +158,29 @@ fn test_mutate_self_variable_fail() {
|
||||
expect_compiler_error(program);
|
||||
}
|
||||
|
||||
// #[test]
|
||||
// fn test_mutate_self_function_fail() {
|
||||
// let bytes = include_bytes!("mut_self_function_fail.leo");
|
||||
// let error = parse_program(bytes).err().unwrap();
|
||||
//
|
||||
// expect_type_inference_error(error);
|
||||
// }
|
||||
#[test]
|
||||
fn test_mutate_self_function_fail() {
|
||||
let bytes = include_bytes!("mut_self_function_fail.leo");
|
||||
let error = parse_program(bytes).err().unwrap();
|
||||
|
||||
// #[test]
|
||||
// fn test_mutate_self_static_function_fail() {
|
||||
// let bytes = include_bytes!("mut_self_static_function_fail.leo");
|
||||
// let error = parse_program(bytes).err().unwrap();
|
||||
//
|
||||
// expect_type_inference_error(error);
|
||||
// }
|
||||
expect_type_inference_error(error);
|
||||
}
|
||||
|
||||
// #[test]
|
||||
// fn test_mutate_static_function_fail() {
|
||||
// let bytes = include_bytes!("mut_static_function_fail.leo");
|
||||
// let error = parse_program(bytes).err().unwrap();
|
||||
//
|
||||
// expect_type_inference_error(error);
|
||||
// }
|
||||
#[test]
|
||||
fn test_mutate_self_static_function_fail() {
|
||||
let bytes = include_bytes!("mut_self_static_function_fail.leo");
|
||||
let error = parse_program(bytes).err().unwrap();
|
||||
|
||||
expect_type_inference_error(error);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mutate_static_function_fail() {
|
||||
let bytes = include_bytes!("mut_static_function_fail.leo");
|
||||
let error = parse_program(bytes).err().unwrap();
|
||||
|
||||
expect_type_inference_error(error);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mutate_variable() {
|
||||
@ -200,13 +200,13 @@ fn test_mutate_variable_fail() {
|
||||
|
||||
// Self
|
||||
|
||||
// #[test]
|
||||
// fn test_self_fail() {
|
||||
// let bytes = include_bytes!("self_fail.leo");
|
||||
// let error = parse_program(bytes).err().unwrap();
|
||||
//
|
||||
// expect_type_inference_error(error);
|
||||
// }
|
||||
#[test]
|
||||
fn test_self_fail() {
|
||||
let bytes = include_bytes!("self_fail.leo");
|
||||
let error = parse_program(bytes).err().unwrap();
|
||||
|
||||
expect_type_inference_error(error);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_self_member_pass() {
|
||||
@ -224,13 +224,13 @@ fn test_self_member_invalid() {
|
||||
let _err = expect_compiler_error(program);
|
||||
}
|
||||
|
||||
// #[test]
|
||||
// fn test_self_member_undefined() {
|
||||
// let bytes = include_bytes!("self_member_undefined.leo");
|
||||
// let error = parse_program(bytes).err().unwrap();
|
||||
//
|
||||
// expect_type_inference_error(error);
|
||||
// }
|
||||
#[test]
|
||||
fn test_self_member_undefined() {
|
||||
let bytes = include_bytes!("self_member_undefined.leo");
|
||||
let error = parse_program(bytes).err().unwrap();
|
||||
|
||||
expect_type_inference_error(error);
|
||||
}
|
||||
|
||||
// All
|
||||
|
||||
|
@ -14,7 +14,14 @@
|
||||
// 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::{assert_satisfied, generate_main_input, get_output, parse_program, parse_program_with_input};
|
||||
use crate::{
|
||||
assert_satisfied,
|
||||
expect_type_inference_error,
|
||||
generate_main_input,
|
||||
get_output,
|
||||
parse_program,
|
||||
parse_program_with_input,
|
||||
};
|
||||
|
||||
use leo_ast::InputValue;
|
||||
use leo_input::types::{IntegerType, U8Type, UnsignedIntegerType};
|
||||
@ -22,22 +29,22 @@ use rand::{Rng, SeedableRng};
|
||||
use rand_xorshift::XorShiftRng;
|
||||
use snarkos_algorithms::prf::blake2s::Blake2s as B2SPRF;
|
||||
use snarkos_models::algorithms::PRF;
|
||||
//
|
||||
// #[test]
|
||||
// fn test_arguments_length_fail() {
|
||||
// let program_bytes = include_bytes!("arguments_length_fail.leo");
|
||||
// let error = parse_program(program_bytes).err().unwrap();
|
||||
//
|
||||
// expect_type_inference_error(error);
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn test_arguments_type_fail() {
|
||||
// let program_bytes = include_bytes!("arguments_type_fail.leo");
|
||||
// let error = parse_program(program_bytes).err().unwrap();
|
||||
//
|
||||
// expect_type_inference_error(error);
|
||||
// }
|
||||
#[test]
|
||||
fn test_arguments_length_fail() {
|
||||
let program_bytes = include_bytes!("arguments_length_fail.leo");
|
||||
let error = parse_program(program_bytes).err().unwrap();
|
||||
|
||||
expect_type_inference_error(error);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_arguments_type_fail() {
|
||||
let program_bytes = include_bytes!("arguments_type_fail.leo");
|
||||
let error = parse_program(program_bytes).err().unwrap();
|
||||
|
||||
expect_type_inference_error(error);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_blake2s_input() {
|
||||
|
@ -14,7 +14,14 @@
|
||||
// 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::{assert_satisfied, expect_compiler_error, get_output, parse_program, parse_program_with_input};
|
||||
use crate::{
|
||||
assert_satisfied,
|
||||
expect_compiler_error,
|
||||
expect_type_inference_error,
|
||||
get_output,
|
||||
parse_program,
|
||||
parse_program_with_input,
|
||||
};
|
||||
use leo_compiler::errors::{CompilerError, ExpressionError, FunctionError, StatementError};
|
||||
|
||||
#[test]
|
||||
@ -110,13 +117,13 @@ fn test_scope_fail() {
|
||||
}
|
||||
}
|
||||
|
||||
// #[test]
|
||||
// fn test_undefined() {
|
||||
// let bytes = include_bytes!("undefined.leo");
|
||||
// let error = parse_program(bytes).err().unwrap();
|
||||
//
|
||||
// expect_type_inference_error(error);
|
||||
// }
|
||||
#[test]
|
||||
fn test_undefined() {
|
||||
let bytes = include_bytes!("undefined.leo");
|
||||
let error = parse_program(bytes).err().unwrap();
|
||||
|
||||
expect_type_inference_error(error);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_value_unchanged() {
|
||||
@ -126,13 +133,13 @@ fn test_value_unchanged() {
|
||||
assert_satisfied(program);
|
||||
}
|
||||
|
||||
// #[test]
|
||||
// fn test_array_input() {
|
||||
// let bytes = include_bytes!("array_input.leo");
|
||||
// let error = parse_program(bytes).err().unwrap();
|
||||
//
|
||||
// expect_type_inference_error(error)
|
||||
// }
|
||||
#[test]
|
||||
fn test_array_input() {
|
||||
let bytes = include_bytes!("array_input.leo");
|
||||
let error = parse_program(bytes).err().unwrap();
|
||||
|
||||
expect_type_inference_error(error)
|
||||
}
|
||||
|
||||
// Test return multidimensional arrays
|
||||
|
||||
|
@ -180,10 +180,10 @@ pub(crate) fn expect_compiler_error(program: EdwardsTestCompiler) -> CompilerErr
|
||||
let mut cs = TestConstraintSystem::<Fq>::new();
|
||||
program.generate_constraints_helper(&mut cs).unwrap_err()
|
||||
}
|
||||
//
|
||||
// pub(crate) fn expect_type_inference_error(error: CompilerError) {
|
||||
// assert!(matches!(error, CompilerError::TypeInferenceError(_)))
|
||||
// }
|
||||
|
||||
pub(crate) fn expect_type_inference_error(error: CompilerError) {
|
||||
assert!(matches!(error, CompilerError::TypeInferenceError(_)))
|
||||
}
|
||||
|
||||
pub(crate) fn expect_symbol_table_error(error: CompilerError) {
|
||||
assert!(matches!(error, CompilerError::SymbolTableError(_)))
|
||||
|
@ -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::{assert_satisfied, expect_compiler_error, generate_main_input, parse_program};
|
||||
use crate::{assert_satisfied, expect_compiler_error, expect_type_inference_error, generate_main_input, parse_program};
|
||||
use leo_ast::InputValue;
|
||||
|
||||
#[test]
|
||||
@ -89,21 +89,21 @@ fn test_circuit_variable_mut() {
|
||||
assert_satisfied(program);
|
||||
}
|
||||
|
||||
// #[test]
|
||||
// fn test_circuit_function_mut() {
|
||||
// let bytes = include_bytes!("circuit_function_mut.leo");
|
||||
// let error = parse_program(bytes).err().unwrap();
|
||||
//
|
||||
// expect_type_inference_error(error);
|
||||
// }
|
||||
//
|
||||
// #[test]
|
||||
// fn test_circuit_static_function_mut() {
|
||||
// let bytes = include_bytes!("circuit_static_function_mut.leo");
|
||||
// let error = parse_program(bytes).err().unwrap();
|
||||
//
|
||||
// expect_type_inference_error(error);
|
||||
// }
|
||||
#[test]
|
||||
fn test_circuit_function_mut() {
|
||||
let bytes = include_bytes!("circuit_function_mut.leo");
|
||||
let error = parse_program(bytes).err().unwrap();
|
||||
|
||||
expect_type_inference_error(error);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_circuit_static_function_mut() {
|
||||
let bytes = include_bytes!("circuit_static_function_mut.leo");
|
||||
let error = parse_program(bytes).err().unwrap();
|
||||
|
||||
expect_type_inference_error(error);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_function_input() {
|
||||
|
@ -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::{assert_satisfied, generate_main_input, parse_program};
|
||||
use crate::{assert_satisfied, expect_type_inference_error, generate_main_input, parse_program};
|
||||
use leo_ast::InputValue;
|
||||
|
||||
pub mod conditional;
|
||||
@ -57,10 +57,10 @@ fn test_iteration_basic() {
|
||||
assert_satisfied(program);
|
||||
}
|
||||
|
||||
// #[test]
|
||||
// fn test_num_returns_fail() {
|
||||
// let bytes = include_bytes!("num_returns_fail.leo");
|
||||
// let error = parse_program(bytes).err().unwrap();
|
||||
//
|
||||
// expect_type_inference_error(error);
|
||||
// }
|
||||
#[test]
|
||||
fn test_num_returns_fail() {
|
||||
let bytes = include_bytes!("num_returns_fail.leo");
|
||||
let error = parse_program(bytes).err().unwrap();
|
||||
|
||||
expect_type_inference_error(error);
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ use crate::{expect_compiler_error, parse_input, parse_program};
|
||||
use leo_compiler::errors::{CompilerError, ExpressionError, FunctionError, StatementError};
|
||||
use leo_grammar::ParserError;
|
||||
use leo_input::InputParserError;
|
||||
// use leo_type_inference::errors::{FrameError, TypeAssertionError, TypeInferenceError};
|
||||
use leo_type_inference::errors::{FrameError, TypeAssertionError, TypeInferenceError};
|
||||
|
||||
pub mod identifiers;
|
||||
|
||||
@ -75,16 +75,16 @@ fn input_syntax_error() {
|
||||
}
|
||||
}
|
||||
|
||||
// #[test]
|
||||
// fn test_compare_mismatched_types() {
|
||||
// let bytes = include_bytes!("compare_mismatched_types.leo");
|
||||
// let error = parse_program(bytes).err().unwrap();
|
||||
//
|
||||
// // Expect a type inference error.
|
||||
// match error {
|
||||
// CompilerError::TypeInferenceError(TypeInferenceError::FrameError(FrameError::TypeAssertionError(
|
||||
// TypeAssertionError::Error(_),
|
||||
// ))) => {}
|
||||
// error => panic!("Expected type inference error, found {}", error),
|
||||
// }
|
||||
// }
|
||||
#[test]
|
||||
fn test_compare_mismatched_types() {
|
||||
let bytes = include_bytes!("compare_mismatched_types.leo");
|
||||
let error = parse_program(bytes).err().unwrap();
|
||||
|
||||
// Expect a type inference error.
|
||||
match error {
|
||||
CompilerError::TypeInferenceError(TypeInferenceError::FrameError(FrameError::TypeAssertionError(
|
||||
TypeAssertionError::Error(_),
|
||||
))) => {}
|
||||
error => panic!("Expected type inference error, found {}", error),
|
||||
}
|
||||
}
|
||||
|
43
type-inference/Cargo.toml
Normal file
43
type-inference/Cargo.toml
Normal file
@ -0,0 +1,43 @@
|
||||
[package]
|
||||
name = "leo-type-inference"
|
||||
version = "1.0.4"
|
||||
authors = [ "The Aleo Team <hello@aleo.org>" ]
|
||||
description = "Checks that a program is correct using type inference"
|
||||
homepage = "https://aleo.org"
|
||||
repository = "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.4"
|
||||
|
||||
[dependencies.leo-imports]
|
||||
path = "../imports"
|
||||
version = "1.0.4"
|
||||
|
||||
[dependencies.leo-grammar]
|
||||
path = "../grammar"
|
||||
version = "1.0.4"
|
||||
|
||||
[dependencies.leo-symbol-table]
|
||||
path = "../symbol-table"
|
||||
version = "1.0.4"
|
||||
|
||||
[dependencies.serde_json]
|
||||
version = "1.0"
|
||||
|
||||
[dependencies.serde]
|
||||
version = "1.0"
|
||||
|
||||
[dependencies.thiserror]
|
||||
version = "1.0"
|
27
type-inference/src/assertions/mod.rs
Normal file
27
type-inference/src/assertions/mod.rs
Normal file
@ -0,0 +1,27 @@
|
||||
// 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 type_assertion;
|
||||
pub use self::type_assertion::*;
|
||||
|
||||
pub mod type_equality;
|
||||
pub use self::type_equality::*;
|
||||
|
||||
pub mod type_membership;
|
||||
pub use self::type_membership::*;
|
||||
|
||||
pub mod type_variable_pair;
|
||||
pub use self::type_variable_pair::*;
|
74
type-inference/src/assertions/type_assertion.rs
Normal file
74
type-inference/src/assertions/type_assertion.rs
Normal file
@ -0,0 +1,74 @@
|
||||
// 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 crate::{TypeAssertionError, TypeEquality, TypeMembership, TypeVariablePairs};
|
||||
use leo_ast::Span;
|
||||
use leo_symbol_table::{Type, TypeVariable};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// A predicate that evaluates equality between two `Types`s.
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub enum TypeAssertion {
|
||||
Equality(TypeEquality),
|
||||
Membership(TypeMembership),
|
||||
}
|
||||
|
||||
impl TypeAssertion {
|
||||
///
|
||||
/// Returns a `TypeAssertion::Equality` predicate from given left and right `Types`s.
|
||||
///
|
||||
pub fn new_equality(left: Type, right: Type, span: &Span) -> Self {
|
||||
Self::Equality(TypeEquality::new(left, right, span))
|
||||
}
|
||||
|
||||
///
|
||||
/// Returns a `TypeAssertion::Membership` predicate from given and set `Type`s.
|
||||
///
|
||||
pub fn new_membership(given: Type, set: Vec<Type>, span: &Span) -> Self {
|
||||
Self::Membership(TypeMembership::new(given, set, span))
|
||||
}
|
||||
|
||||
///
|
||||
/// Returns one or more `TypeVariablePairs` generated by the given `TypeAssertion`.
|
||||
///
|
||||
pub fn pairs(&self) -> Result<TypeVariablePairs, TypeAssertionError> {
|
||||
match self {
|
||||
TypeAssertion::Equality(equality) => equality.pairs(),
|
||||
TypeAssertion::Membership(membership) => Err(TypeAssertionError::membership_pairs(membership)),
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Substitutes the given type for self if self is equal to the type variable.
|
||||
///
|
||||
pub fn substitute(&mut self, variable: &TypeVariable, type_: &Type) {
|
||||
match self {
|
||||
TypeAssertion::Equality(equality) => equality.substitute(variable, type_),
|
||||
TypeAssertion::Membership(membership) => membership.substitute(variable, type_),
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Checks if the `TypeAssertion` is satisfied.
|
||||
///
|
||||
pub fn evaluate(&self) -> Result<(), TypeAssertionError> {
|
||||
match self {
|
||||
TypeAssertion::Equality(equality) => equality.evaluate(),
|
||||
TypeAssertion::Membership(membership) => membership.evaluate(),
|
||||
}
|
||||
}
|
||||
}
|
68
type-inference/src/assertions/type_equality.rs
Normal file
68
type-inference/src/assertions/type_equality.rs
Normal file
@ -0,0 +1,68 @@
|
||||
// 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 crate::{TypeAssertionError, TypeVariablePairs};
|
||||
use leo_ast::Span;
|
||||
use leo_symbol_table::{Type, TypeVariable};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// A predicate that evaluates equality between two `Type`s.
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct TypeEquality {
|
||||
left: Type,
|
||||
right: Type,
|
||||
span: Span,
|
||||
}
|
||||
|
||||
impl TypeEquality {
|
||||
///
|
||||
/// Returns a `TypeEquality` predicate from given left and right `Types`s
|
||||
///
|
||||
pub fn new(left: Type, right: Type, span: &Span) -> Self {
|
||||
Self {
|
||||
left,
|
||||
right,
|
||||
span: span.to_owned(),
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Substitutes the given `TypeVariable` for each `Types` in the `TypeEquality`.
|
||||
///
|
||||
pub fn substitute(&mut self, variable: &TypeVariable, type_: &Type) {
|
||||
self.left.substitute(variable, type_);
|
||||
self.right.substitute(variable, type_);
|
||||
}
|
||||
|
||||
///
|
||||
/// Checks if the `self.left` == `self.right`.
|
||||
///
|
||||
pub fn evaluate(&self) -> Result<(), TypeAssertionError> {
|
||||
if self.left.eq(&self.right) {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(TypeAssertionError::equality_failed(&self.left, &self.right, &self.span))
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Returns the (type variable, type) pair from this assertion.
|
||||
///
|
||||
pub fn pairs(&self) -> Result<TypeVariablePairs, TypeAssertionError> {
|
||||
TypeVariablePairs::new(self.left.to_owned(), self.right.to_owned(), &self.span)
|
||||
}
|
||||
}
|
71
type-inference/src/assertions/type_membership.rs
Normal file
71
type-inference/src/assertions/type_membership.rs
Normal file
@ -0,0 +1,71 @@
|
||||
// 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 crate::TypeAssertionError;
|
||||
use leo_ast::Span;
|
||||
use leo_symbol_table::{Type, TypeVariable};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// A predicate that evaluates to true if the given type is equal to a member in the set vector of types.
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct TypeMembership {
|
||||
given: Type,
|
||||
set: Vec<Type>,
|
||||
span: Span,
|
||||
}
|
||||
|
||||
impl TypeMembership {
|
||||
///
|
||||
/// Returns a `TypeMembership` predicate from given and set `Type`s.
|
||||
///
|
||||
pub fn new(given: Type, set: Vec<Type>, span: &Span) -> Self {
|
||||
Self {
|
||||
given,
|
||||
set,
|
||||
span: span.to_owned(),
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Substitutes the given `TypeVariable` for each `Type` in the `TypeMembership`.
|
||||
///
|
||||
pub fn substitute(&mut self, variable: &TypeVariable, type_: &Type) {
|
||||
self.given.substitute(variable, type_)
|
||||
}
|
||||
|
||||
///
|
||||
/// Returns true if the given type is equal to a member of the set.
|
||||
///
|
||||
pub fn evaluate(&self) -> Result<(), TypeAssertionError> {
|
||||
if self.set.contains(&self.given) {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(TypeAssertionError::membership_failed(
|
||||
&self.given,
|
||||
&self.set,
|
||||
&self.span,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Returns the self.span.
|
||||
///
|
||||
pub fn span(&self) -> &Span {
|
||||
&self.span
|
||||
}
|
||||
}
|
137
type-inference/src/assertions/type_variable_pair.rs
Normal file
137
type-inference/src/assertions/type_variable_pair.rs
Normal file
@ -0,0 +1,137 @@
|
||||
// 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 crate::TypeAssertionError;
|
||||
use leo_ast::Span;
|
||||
use leo_symbol_table::{get_array_element_type, Type, TypeVariable};
|
||||
|
||||
/// A type variable -> type pair.
|
||||
pub struct TypeVariablePair(TypeVariable, Type);
|
||||
|
||||
impl TypeVariablePair {
|
||||
pub fn first(&self) -> &TypeVariable {
|
||||
&self.0
|
||||
}
|
||||
|
||||
pub fn second(&self) -> &Type {
|
||||
&self.1
|
||||
}
|
||||
}
|
||||
|
||||
/// A vector of `TypeVariablePair`s.
|
||||
pub struct TypeVariablePairs(Vec<TypeVariablePair>);
|
||||
|
||||
impl Default for TypeVariablePairs {
|
||||
fn default() -> Self {
|
||||
Self(Vec::new())
|
||||
}
|
||||
}
|
||||
|
||||
impl TypeVariablePairs {
|
||||
///
|
||||
/// Returns a new `TypeVariablePairs` struct from the given left and right types.
|
||||
///
|
||||
pub fn new(left: Type, right: Type, span: &Span) -> Result<Self, TypeAssertionError> {
|
||||
let mut pairs = Self::default();
|
||||
|
||||
// Push all `TypeVariablePair`s.
|
||||
pairs.push_pairs(left, right, span)?;
|
||||
|
||||
Ok(pairs)
|
||||
}
|
||||
|
||||
///
|
||||
/// Returns true if the self vector has no pairs.
|
||||
///
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.0.is_empty()
|
||||
}
|
||||
|
||||
///
|
||||
/// Returns the self vector of pairs.
|
||||
///
|
||||
pub fn get_pairs(&self) -> &[TypeVariablePair] {
|
||||
&self.0
|
||||
}
|
||||
|
||||
///
|
||||
/// Pushes a new `TypeVariablePair` struct to self.
|
||||
///
|
||||
pub fn push(&mut self, variable: TypeVariable, type_: Type) {
|
||||
// Create a new type variable -> type pair.
|
||||
let pair = TypeVariablePair(variable, type_);
|
||||
|
||||
// Push the pair to the self vector.
|
||||
self.0.push(pair);
|
||||
}
|
||||
|
||||
///
|
||||
/// Checks if the given left or right type contains a `TypeVariable`.
|
||||
/// If a `TypeVariable` is found, create a new `TypeVariablePair` between the given left
|
||||
/// and right type.
|
||||
///
|
||||
pub fn push_pairs(&mut self, left: Type, right: Type, span: &Span) -> Result<(), TypeAssertionError> {
|
||||
match (left, right) {
|
||||
(Type::TypeVariable(variable), type_) => {
|
||||
self.push(variable, type_);
|
||||
Ok(())
|
||||
}
|
||||
(type_, Type::TypeVariable(variable)) => {
|
||||
self.push(variable, type_);
|
||||
Ok(())
|
||||
}
|
||||
(Type::Array(left_type), Type::Array(right_type)) => self.push_pairs_array(*left_type, *right_type, span),
|
||||
(Type::Tuple(left_types), Type::Tuple(right_types)) => {
|
||||
self.push_pairs_tuple(left_types.into_iter(), right_types.into_iter(), span)
|
||||
}
|
||||
(_, _) => Ok(()), // No `TypeVariable` found so we do not push any pairs.
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Checks if the given left or right array type contains a `TypeVariable`.
|
||||
/// If a `TypeVariable` is found, create a new `TypeVariablePair` between the given left
|
||||
/// and right type.
|
||||
///
|
||||
fn push_pairs_array(&mut self, left_type: Type, right_type: Type, span: &Span) -> Result<(), TypeAssertionError> {
|
||||
// Get both array element types before comparison.
|
||||
let array1_element = get_array_element_type(&left_type);
|
||||
let array2_element = get_array_element_type(&right_type);
|
||||
|
||||
// Compare the array element types.
|
||||
self.push_pairs(array1_element.to_owned(), array2_element.to_owned(), span)
|
||||
}
|
||||
|
||||
///
|
||||
/// Checks if any given left or right tuple type contains a `TypeVariable`.
|
||||
/// If a `TypeVariable` is found, create a new `TypeVariablePair` between the given left
|
||||
/// and right type.
|
||||
///
|
||||
fn push_pairs_tuple(
|
||||
&mut self,
|
||||
left_types: impl Iterator<Item = Type>,
|
||||
right_types: impl Iterator<Item = Type>,
|
||||
span: &Span,
|
||||
) -> Result<(), TypeAssertionError> {
|
||||
// Iterate over each left == right pair of types.
|
||||
for (left, right) in left_types.into_iter().zip(right_types) {
|
||||
// Check for `TypeVariablePair`s.
|
||||
self.push_pairs(left, right, span)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
240
type-inference/src/errors/frame.rs
Normal file
240
type-inference/src/errors/frame.rs
Normal file
@ -0,0 +1,240 @@
|
||||
// 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 crate::{ScopeError, TypeAssertionError};
|
||||
use leo_ast::{Error as FormattedError, Expression, Identifier, Span};
|
||||
use leo_symbol_table::{Type, TypeError};
|
||||
|
||||
use std::path::Path;
|
||||
|
||||
/// Errors encountered when tracking variable names in a program.
|
||||
#[derive(Debug, Error)]
|
||||
pub enum FrameError {
|
||||
#[error("{}", _0)]
|
||||
Error(#[from] FormattedError),
|
||||
|
||||
#[error("{}", _0)]
|
||||
ScopeError(#[from] ScopeError),
|
||||
|
||||
#[error("{}", _0)]
|
||||
TypeAssertionError(#[from] TypeAssertionError),
|
||||
|
||||
#[error("{}", _0)]
|
||||
TypeError(#[from] TypeError),
|
||||
}
|
||||
|
||||
impl FrameError {
|
||||
///
|
||||
/// Set the filepath for the error stacktrace
|
||||
///
|
||||
pub fn set_path(&mut self, path: &Path) {
|
||||
match self {
|
||||
FrameError::Error(error) => error.set_path(path),
|
||||
FrameError::ScopeError(error) => error.set_path(path),
|
||||
FrameError::TypeAssertionError(error) => error.set_path(path),
|
||||
FrameError::TypeError(error) => error.set_path(path),
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Return a new formatted error with a given message and span information
|
||||
///
|
||||
fn new_from_span(message: String, span: &Span) -> Self {
|
||||
FrameError::Error(FormattedError::new_from_span(message, span.to_owned()))
|
||||
}
|
||||
|
||||
///
|
||||
/// Attempted to access the index of a non-array type.
|
||||
///
|
||||
pub fn array_access(actual: &Type, span: &Span) -> Self {
|
||||
let message = format!("Cannot access the index of non-array type `{}`.", actual);
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
///
|
||||
/// Attempted to access the `Self` type outside of a circuit context.
|
||||
///
|
||||
pub fn circuit_self(span: &Span) -> Self {
|
||||
let message = "The `Self` keyword is only valid inside a circuit context.".to_string();
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
///
|
||||
/// Two variables have been defined with the same name.
|
||||
///
|
||||
pub fn duplicate_variable(name: &str, span: &Span) -> Self {
|
||||
let message = format!("Duplicate variable definition found for `{}`", name);
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
///
|
||||
/// Attempted to create an empty array in a Leo program.
|
||||
///
|
||||
/// Arrays in Leo are not resizeable so defining empty arrays are effectively dead code.
|
||||
///
|
||||
pub fn empty_array(span: &Span) -> Self {
|
||||
let message = "Cannot create an empty array in a Leo program.".to_string();
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
///
|
||||
/// Expected a circuit name but found a different type.
|
||||
///
|
||||
pub fn invalid_circuit(type_: Type, span: &Span) -> Self {
|
||||
let message = format!("Expected a circuit type. Found type `{}`.", type_);
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
///
|
||||
/// Expected a function name but found a different expression.
|
||||
///
|
||||
pub fn invalid_function(expression: &Expression, span: &Span) -> Self {
|
||||
let message = format!("Expected a function name. Found expression `{}`.", expression);
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
///
|
||||
/// Expected a usize number for the index.
|
||||
///
|
||||
pub fn invalid_index(actual: String, span: &Span) -> Self {
|
||||
let message = format!("Expected constant number for index, found `{}`", actual);
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
///
|
||||
/// Attempted to call non-static member using `::`.
|
||||
///
|
||||
pub fn invalid_member_access(identifier: &Identifier) -> Self {
|
||||
let message = format!("non-static member `{}` must be accessed using `.` syntax.", identifier);
|
||||
|
||||
Self::new_from_span(message, &identifier.span)
|
||||
}
|
||||
|
||||
///
|
||||
/// Attempted to use the spread operator on a non-array type.
|
||||
///
|
||||
pub fn invalid_spread(actual: Type, span: &Span) -> Self {
|
||||
let message = format!(
|
||||
"The spread operator `...` can only be applied to array types. Found type `{}`.",
|
||||
actual
|
||||
);
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
///
|
||||
/// Attempted to call static member using `.`.
|
||||
///
|
||||
pub fn invalid_static_access(identifier: &Identifier) -> Self {
|
||||
let message = format!("Static member `{}` must be accessed using `::` syntax.", identifier);
|
||||
|
||||
Self::new_from_span(message, &identifier.span)
|
||||
}
|
||||
|
||||
///
|
||||
/// Attempted to create a circuit with the incorrect number of member variables.
|
||||
///
|
||||
pub fn num_circuit_variables(expected: usize, actual: usize, span: &Span) -> Self {
|
||||
let message = format!("Circuit expected {} variables, found {} variables.", expected, actual);
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
///
|
||||
/// Attempted to call a function with the incorrect number of inputs.
|
||||
///
|
||||
pub fn num_inputs(expected: usize, actual: usize, span: &Span) -> Self {
|
||||
let message = format!(
|
||||
"Function expected {} input variables, found {} inputs.",
|
||||
expected, actual
|
||||
);
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
///
|
||||
/// Attempted to access the index of a non-tuple type.
|
||||
///
|
||||
pub fn tuple_access(actual: &Type, span: &Span) -> Self {
|
||||
let message = format!("Cannot access the index of non-tuple type `{}`.", actual);
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
///
|
||||
/// Attempted to call a circuit type that is not defined in the current context.
|
||||
///
|
||||
pub fn undefined_circuit(identifier: &Identifier) -> Self {
|
||||
let message = format!("The circuit `{}` is not defined.", identifier);
|
||||
|
||||
Self::new_from_span(message, &identifier.span)
|
||||
}
|
||||
|
||||
///
|
||||
/// Attempted to call a circuit function that is not defined in the current context.
|
||||
///
|
||||
pub fn undefined_circuit_function(identifier: &Identifier) -> Self {
|
||||
let message = format!("The circuit function `{}` is not defined.", identifier);
|
||||
|
||||
Self::new_from_span(message, &identifier.span)
|
||||
}
|
||||
|
||||
///
|
||||
/// Attempted to call a function that is not defined in the current context.
|
||||
///
|
||||
pub fn undefined_function(identifier: &Identifier) -> Self {
|
||||
let message = format!("The function `{}` is not defined.", identifier);
|
||||
|
||||
Self::new_from_span(message, &identifier.span)
|
||||
}
|
||||
|
||||
///
|
||||
/// Attempted to call a variable that is not defined in the current context.
|
||||
///
|
||||
pub fn undefined_variable(identifier: &Identifier) -> Self {
|
||||
let message = format!("The variable `{}` is not defined.", identifier);
|
||||
|
||||
Self::new_from_span(message, &identifier.span)
|
||||
}
|
||||
|
||||
///
|
||||
/// Attempted to assign a tuple of variables to a single value.
|
||||
///
|
||||
pub fn not_enough_values(span: &Span) -> Self {
|
||||
let message = "Expected a tuple type for multiple defined variables".to_string();
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
///
|
||||
/// Attempted to assign a tuple with a different number of variables than values.
|
||||
///
|
||||
pub fn invalid_number_of_values(expected: usize, actual: usize, span: &Span) -> Self {
|
||||
let message = format!(
|
||||
"Incorrect number of defined variables. Expected `{}`, found `{}`.",
|
||||
expected, actual
|
||||
);
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
}
|
30
type-inference/src/errors/mod.rs
Normal file
30
type-inference/src/errors/mod.rs
Normal file
@ -0,0 +1,30 @@
|
||||
// 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 frame;
|
||||
pub use self::frame::*;
|
||||
|
||||
pub mod scope;
|
||||
pub use self::scope::*;
|
||||
|
||||
pub mod type_assertion;
|
||||
pub use self::type_assertion::*;
|
||||
|
||||
pub mod type_inference;
|
||||
pub use self::type_inference::*;
|
||||
|
||||
pub mod variable_table;
|
||||
pub use self::variable_table::*;
|
42
type-inference/src/errors/scope.rs
Normal file
42
type-inference/src/errors/scope.rs
Normal file
@ -0,0 +1,42 @@
|
||||
// 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 crate::VariableTableError;
|
||||
use leo_ast::Error as FormattedError;
|
||||
|
||||
use std::path::Path;
|
||||
|
||||
/// Errors encountered when evaluating variables in a scope.
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ScopeError {
|
||||
#[error("{}", _0)]
|
||||
Error(#[from] FormattedError),
|
||||
|
||||
#[error("{}", _0)]
|
||||
VariableTableError(#[from] VariableTableError),
|
||||
}
|
||||
|
||||
impl ScopeError {
|
||||
///
|
||||
/// Set the filepath for the error stacktrace.
|
||||
///
|
||||
pub fn set_path(&mut self, path: &Path) {
|
||||
match self {
|
||||
ScopeError::Error(error) => error.set_path(path),
|
||||
ScopeError::VariableTableError(error) => error.set_path(path),
|
||||
}
|
||||
}
|
||||
}
|
89
type-inference/src/errors/type_assertion.rs
Normal file
89
type-inference/src/errors/type_assertion.rs
Normal file
@ -0,0 +1,89 @@
|
||||
// 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 crate::TypeMembership;
|
||||
|
||||
use leo_ast::{Error as FormattedError, Span};
|
||||
use leo_symbol_table::Type;
|
||||
|
||||
use std::path::Path;
|
||||
|
||||
/// Errors encountered when attempting to solve a type assertion.
|
||||
#[derive(Debug, Error)]
|
||||
pub enum TypeAssertionError {
|
||||
#[error("{}", _0)]
|
||||
Error(#[from] FormattedError),
|
||||
}
|
||||
|
||||
impl TypeAssertionError {
|
||||
///
|
||||
/// Set the filepath for the error stacktrace.
|
||||
///
|
||||
pub fn set_path(&mut self, path: &Path) {
|
||||
match self {
|
||||
TypeAssertionError::Error(error) => error.set_path(path),
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Returns a new formatted error with a given message and span information.
|
||||
///
|
||||
fn new_from_span(message: String, span: &Span) -> Self {
|
||||
TypeAssertionError::Error(FormattedError::new_from_span(message, span.to_owned()))
|
||||
}
|
||||
|
||||
///
|
||||
/// Found mismatched types during program parsing.
|
||||
///
|
||||
pub fn equality_failed(left: &Type, right: &Type, span: &Span) -> Self {
|
||||
let message = format!("Mismatched types. Expected type `{}`, found type `{}`.", left, right);
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
///
|
||||
/// Given type is not a member of the set of expected types.
|
||||
///
|
||||
pub fn membership_failed(given: &Type, set: &[Type], span: &Span) -> Self {
|
||||
let message = format!(
|
||||
"Mismatched types. Given type `{}` is not in the expected type set `{:?}`.",
|
||||
given, set
|
||||
);
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
///
|
||||
/// Attempted to generate pairs from a membership assertion.
|
||||
///
|
||||
pub fn membership_pairs(membership: &TypeMembership) -> Self {
|
||||
let message = "Cannot generate a type variable -> type pair for the given type membership".to_string();
|
||||
|
||||
Self::new_from_span(message, membership.span())
|
||||
}
|
||||
|
||||
///
|
||||
/// Mismatched array type dimensions.
|
||||
///
|
||||
pub fn array_dimensions(dimensions1: &[usize], dimensions2: &[usize], span: &Span) -> Self {
|
||||
let message = format!(
|
||||
"Expected array with dimensions `{:?}`, found array with dimensions `{:?}`.",
|
||||
dimensions1, dimensions2
|
||||
);
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
}
|
42
type-inference/src/errors/type_inference.rs
Normal file
42
type-inference/src/errors/type_inference.rs
Normal file
@ -0,0 +1,42 @@
|
||||
// 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 crate::FrameError;
|
||||
use leo_ast::Error as FormattedError;
|
||||
|
||||
use std::path::Path;
|
||||
|
||||
/// Errors encountered when running type inference checks.
|
||||
#[derive(Debug, Error)]
|
||||
pub enum TypeInferenceError {
|
||||
#[error("{}", _0)]
|
||||
Error(#[from] FormattedError),
|
||||
|
||||
#[error("{}", _0)]
|
||||
FrameError(#[from] FrameError),
|
||||
}
|
||||
|
||||
impl TypeInferenceError {
|
||||
///
|
||||
/// Set the filepath for the error stacktrace.
|
||||
///
|
||||
pub fn set_path(&mut self, path: &Path) {
|
||||
match self {
|
||||
TypeInferenceError::Error(error) => error.set_path(path),
|
||||
TypeInferenceError::FrameError(error) => error.set_path(path),
|
||||
}
|
||||
}
|
||||
}
|
53
type-inference/src/errors/variable_table.rs
Normal file
53
type-inference/src/errors/variable_table.rs
Normal file
@ -0,0 +1,53 @@
|
||||
// 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::{Error as FormattedError, Span};
|
||||
|
||||
use std::path::Path;
|
||||
|
||||
/// Errors encountered when tracking variable names in a program.
|
||||
#[derive(Debug, Error)]
|
||||
pub enum VariableTableError {
|
||||
#[error("{}", _0)]
|
||||
Error(#[from] FormattedError),
|
||||
}
|
||||
|
||||
impl VariableTableError {
|
||||
///
|
||||
/// Set the filepath for the error stacktrace
|
||||
///
|
||||
pub fn set_path(&mut self, path: &Path) {
|
||||
match self {
|
||||
VariableTableError::Error(error) => error.set_path(path),
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Return a new formatted error with a given message and span information
|
||||
///
|
||||
fn new_from_span(message: String, span: Span) -> Self {
|
||||
VariableTableError::Error(FormattedError::new_from_span(message, span))
|
||||
}
|
||||
|
||||
///
|
||||
/// Attempted to lookup a variable name that does not exist in the table.
|
||||
///
|
||||
pub fn undefined_variable_name(name: &str, span: &Span) -> Self {
|
||||
let message = format!("Cannot find variable `{}` in this scope.", name);
|
||||
|
||||
Self::new_from_span(message, span.clone())
|
||||
}
|
||||
}
|
37
type-inference/src/lib.rs
Normal file
37
type-inference/src/lib.rs
Normal file
@ -0,0 +1,37 @@
|
||||
// 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/>.
|
||||
|
||||
//! A type inference check for a Leo program.
|
||||
//!
|
||||
//! This module contains the [`TypeInference`] type, which stores information needed to run a type
|
||||
//! inference check over a program.
|
||||
//!
|
||||
//! A new [`TypeInference`] type can be created from a [`LeoAst`] type and a [`Symbol Table`].
|
||||
|
||||
#[macro_use]
|
||||
extern crate thiserror;
|
||||
|
||||
pub mod assertions;
|
||||
pub use self::assertions::*;
|
||||
|
||||
pub mod type_inference;
|
||||
pub use self::type_inference::*;
|
||||
|
||||
pub mod errors;
|
||||
pub use self::errors::*;
|
||||
|
||||
pub mod objects;
|
||||
pub use self::objects::*;
|
1210
type-inference/src/objects/frame.rs
Normal file
1210
type-inference/src/objects/frame.rs
Normal file
File diff suppressed because it is too large
Load Diff
24
type-inference/src/objects/mod.rs
Normal file
24
type-inference/src/objects/mod.rs
Normal file
@ -0,0 +1,24 @@
|
||||
// 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 frame;
|
||||
pub use self::frame::*;
|
||||
|
||||
pub mod scope;
|
||||
pub use self::scope::*;
|
||||
|
||||
pub mod variable_table;
|
||||
pub use self::variable_table::*;
|
81
type-inference/src/objects/scope.rs
Normal file
81
type-inference/src/objects/scope.rs
Normal file
@ -0,0 +1,81 @@
|
||||
// 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 crate::{ScopeError, VariableTable};
|
||||
use leo_symbol_table::{FunctionInputType, Type};
|
||||
|
||||
/// A structure for tracking the types of defined variables in a block of code.
|
||||
#[derive(Clone, Default)]
|
||||
pub struct Scope {
|
||||
pub loop_variables: VariableTable,
|
||||
pub variables: VariableTable,
|
||||
}
|
||||
|
||||
impl Scope {
|
||||
///
|
||||
/// Returns a new `Scope` from an optional given `Scope`.
|
||||
///
|
||||
/// The new scope will contain the variables of the optional given `Scope`.
|
||||
///
|
||||
pub fn new(parent: Option<Scope>) -> Self {
|
||||
match parent {
|
||||
Some(scope) => scope,
|
||||
None => Self::default(),
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Inserts a variable name -> type mapping into the loop variable table.
|
||||
///
|
||||
pub fn insert_loop_variable(&mut self, name: String, type_: Type) -> Option<Type> {
|
||||
self.loop_variables.insert(name, type_)
|
||||
}
|
||||
|
||||
///
|
||||
/// Inserts a variable name -> type mapping into the variable table.
|
||||
///
|
||||
pub fn insert_variable(&mut self, name: String, type_: Type) -> Option<Type> {
|
||||
self.variables.insert(name, type_)
|
||||
}
|
||||
|
||||
///
|
||||
/// Returns a reference to the type corresponding to the loop variable name.
|
||||
///
|
||||
pub fn get_loop_variable(&self, name: &str) -> Option<&Type> {
|
||||
self.loop_variables.get(name)
|
||||
}
|
||||
|
||||
///
|
||||
/// Returns a reference to the type corresponding to the variable name.
|
||||
///
|
||||
/// Checks loop variables first, then non-loop variables.
|
||||
///
|
||||
pub fn get_variable(&self, name: &str) -> Option<&Type> {
|
||||
match self.get_loop_variable(name) {
|
||||
Some(loop_variable_type) => Some(loop_variable_type),
|
||||
None => self.variables.get(name),
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Inserts a vector of function input types into the `Scope` variable table.
|
||||
///
|
||||
pub fn insert_function_inputs(&mut self, function_inputs: &[FunctionInputType]) -> Result<(), ScopeError> {
|
||||
self.variables
|
||||
.insert_function_inputs(function_inputs)
|
||||
.map_err(ScopeError::VariableTableError)
|
||||
}
|
||||
}
|
67
type-inference/src/objects/variable_table.rs
Normal file
67
type-inference/src/objects/variable_table.rs
Normal file
@ -0,0 +1,67 @@
|
||||
// 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 crate::VariableTableError;
|
||||
use leo_symbol_table::{FunctionInputType, Type};
|
||||
use std::collections::HashMap;
|
||||
|
||||
/// Mapping of variable names to types
|
||||
#[derive(Clone)]
|
||||
pub struct VariableTable(pub HashMap<String, Type>);
|
||||
|
||||
impl VariableTable {
|
||||
///
|
||||
/// Insert a name -> type pair into the variable table.
|
||||
///
|
||||
/// If the variable table did not have this key present, [`None`] is returned.
|
||||
///
|
||||
/// If the variable table did have this key present, the type is updated, and the old
|
||||
/// type is returned.
|
||||
///
|
||||
pub fn insert(&mut self, name: String, type_: Type) -> Option<Type> {
|
||||
self.0.insert(name, type_)
|
||||
}
|
||||
|
||||
///
|
||||
/// Returns a reference to the type corresponding to the name.
|
||||
///
|
||||
/// If the variable table did not have this key present, throw an undefined variable error
|
||||
/// using the given span.
|
||||
///
|
||||
pub fn get(&self, name: &str) -> Option<&Type> {
|
||||
self.0.get(name)
|
||||
}
|
||||
|
||||
///
|
||||
/// Inserts a vector of function input types into the variable table.
|
||||
///
|
||||
pub fn insert_function_inputs(&mut self, function_inputs: &[FunctionInputType]) -> Result<(), VariableTableError> {
|
||||
for input in function_inputs {
|
||||
let input_name = input.identifier().name.clone();
|
||||
let input_type = input.type_();
|
||||
|
||||
// TODO (collinc97) throw an error for duplicate function input names.
|
||||
self.insert(input_name, input_type);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for VariableTable {
|
||||
fn default() -> Self {
|
||||
Self(HashMap::new())
|
||||
}
|
||||
}
|
138
type-inference/src/type_inference.rs
Normal file
138
type-inference/src/type_inference.rs
Normal file
@ -0,0 +1,138 @@
|
||||
// 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 crate::{Frame, Scope, TypeInferenceError};
|
||||
use leo_ast::{Circuit, CircuitMember, Function, Program};
|
||||
use leo_symbol_table::SymbolTable;
|
||||
|
||||
/// A type inference check for a Leo program.
|
||||
///
|
||||
/// A [`TypeInference`] type stores a stack of frames. A new frame is created for every
|
||||
/// function. Frames store type assertions that assert an expression is a type.
|
||||
/// Calling the `check()` method on a [`TypeInference`] checks that all type assertions are satisfied.
|
||||
pub struct TypeInference {
|
||||
table: SymbolTable,
|
||||
frames: Vec<Frame>,
|
||||
}
|
||||
|
||||
impl TypeInference {
|
||||
///
|
||||
/// Creates and runs a new `TypeInference` check on a given program and symbol table.
|
||||
///
|
||||
/// Evaluates all `TypeAssertion` predicates.
|
||||
///
|
||||
#[allow(clippy::new_ret_no_self)]
|
||||
pub fn new(program: &Program, symbol_table: SymbolTable) -> Result<(), TypeInferenceError> {
|
||||
let mut type_inference = Self {
|
||||
table: symbol_table,
|
||||
frames: Vec::new(),
|
||||
};
|
||||
|
||||
type_inference.parse_program(program)?;
|
||||
|
||||
type_inference.check()
|
||||
}
|
||||
|
||||
///
|
||||
/// Collects a vector of `TypeAssertion` predicates from a program.
|
||||
///
|
||||
fn parse_program(&mut self, program: &Program) -> Result<(), TypeInferenceError> {
|
||||
// Parse circuit types in program context.
|
||||
self.parse_circuits(program.circuits.iter().map(|(_identifier, circuit)| circuit))?;
|
||||
|
||||
// Parse functions in program context.
|
||||
self.parse_functions(program.functions.iter().map(|(_identifier, function)| function))
|
||||
}
|
||||
|
||||
///
|
||||
/// Collects a vector of `Frames`s from a vector of circuit functions.
|
||||
///
|
||||
fn parse_circuits<'a>(&mut self, circuits: impl Iterator<Item = &'a Circuit>) -> Result<(), TypeInferenceError> {
|
||||
for circuit in circuits {
|
||||
self.parse_circuit(circuit)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
///
|
||||
/// Collects a vector of `Frames`s from a circuit function.
|
||||
///
|
||||
/// Each frame collects a vector of `TypeAssertion` predicates from each function.
|
||||
///
|
||||
fn parse_circuit(&mut self, circuit: &Circuit) -> Result<(), TypeInferenceError> {
|
||||
let name = &circuit.circuit_name.name;
|
||||
|
||||
// Get circuit type from circuit symbol table.
|
||||
let circuit_type = self.table.get_circuit_type(name).unwrap().clone();
|
||||
|
||||
// Create a new function for each circuit member function.
|
||||
for circuit_member in &circuit.members {
|
||||
// ignore circuit member variables
|
||||
if let CircuitMember::CircuitFunction(_, function) = circuit_member {
|
||||
// Collect `TypeAssertion` predicates from the function.
|
||||
// Pass down circuit self type and circuit variable types to each function.
|
||||
let frame = Frame::new_circuit_function(
|
||||
function.to_owned(),
|
||||
circuit_type.clone(),
|
||||
Scope::default(),
|
||||
self.table.clone(),
|
||||
)?;
|
||||
|
||||
self.frames.push(frame)
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
///
|
||||
/// Collects a vector of `TypeAssertion` predicates from a vector of functions.
|
||||
///
|
||||
fn parse_functions<'a>(&mut self, functions: impl Iterator<Item = &'a Function>) -> Result<(), TypeInferenceError> {
|
||||
for function in functions {
|
||||
self.parse_function(function)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
///
|
||||
/// Collects a vector of `TypeAssertion` predicates from a function.
|
||||
///
|
||||
fn parse_function(&mut self, function: &Function) -> Result<(), TypeInferenceError> {
|
||||
let frame = Frame::new_function(function.to_owned(), None, None, self.table.clone())?;
|
||||
|
||||
self.frames.push(frame);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
///
|
||||
/// Returns the result of evaluating all `TypeAssertion` predicates.
|
||||
///
|
||||
/// Will attempt to substitute a `Type` for all `TypeVariable`s.
|
||||
/// Returns a `LeoResolvedAst` if all `TypeAssertion` predicates are true.
|
||||
/// Returns ERROR if a `TypeAssertion` predicate is false or a solution does not exist.
|
||||
///
|
||||
pub fn check(self) -> Result<(), TypeInferenceError> {
|
||||
for frame in self.frames {
|
||||
frame.check()?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
3
type-inference/tests/arrays/empty_array.leo
Normal file
3
type-inference/tests/arrays/empty_array.leo
Normal file
@ -0,0 +1,3 @@
|
||||
function main() {
|
||||
let a = [1u8; 0]; // Empty arrays are illegal in Leo programs since arrays cannot be resized.
|
||||
}
|
5
type-inference/tests/arrays/invalid_array_access.leo
Normal file
5
type-inference/tests/arrays/invalid_array_access.leo
Normal file
@ -0,0 +1,5 @@
|
||||
function main() {
|
||||
let a = (1u8, 2u8);
|
||||
|
||||
let b = a[0]; // It is illegal to index into a tuple using bracket syntax.
|
||||
}
|
5
type-inference/tests/arrays/invalid_spread.leo
Normal file
5
type-inference/tests/arrays/invalid_spread.leo
Normal file
@ -0,0 +1,5 @@
|
||||
function main() {
|
||||
let a: u8 = 1;
|
||||
|
||||
let b = [...a];
|
||||
}
|
44
type-inference/tests/arrays/mod.rs
Normal file
44
type-inference/tests/arrays/mod.rs
Normal file
@ -0,0 +1,44 @@
|
||||
// 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 crate::TestTypeInference;
|
||||
|
||||
#[test]
|
||||
fn test_empty_array() {
|
||||
let bytes = include_bytes!("empty_array.leo");
|
||||
|
||||
let check = TestTypeInference::new(bytes);
|
||||
|
||||
check.expect_error();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_invalid_array_access() {
|
||||
let bytes = include_bytes!("invalid_array_access.leo");
|
||||
|
||||
let check = TestTypeInference::new(bytes);
|
||||
|
||||
check.expect_error();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_invalid_spread() {
|
||||
let bytes = include_bytes!("invalid_spread.leo");
|
||||
|
||||
let check = TestTypeInference::new(bytes);
|
||||
|
||||
check.expect_error();
|
||||
}
|
4
type-inference/tests/circuits/invalid_circuit.leo
Normal file
4
type-inference/tests/circuits/invalid_circuit.leo
Normal file
@ -0,0 +1,4 @@
|
||||
function main() {
|
||||
let a = 1u8;
|
||||
let b = a::foo(); // Variable `a` is not a circuit type.
|
||||
}
|
25
type-inference/tests/circuits/mod.rs
Normal file
25
type-inference/tests/circuits/mod.rs
Normal file
@ -0,0 +1,25 @@
|
||||
// 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 crate::TestTypeInference;
|
||||
|
||||
#[test]
|
||||
fn test_invalid_circuit() {
|
||||
let bytes = include_bytes!("invalid_circuit.leo");
|
||||
let check = TestTypeInference::new(bytes);
|
||||
|
||||
check.expect_error();
|
||||
}
|
0
type-inference/tests/empty.leo
Normal file
0
type-inference/tests/empty.leo
Normal file
4
type-inference/tests/functions/invalid_function.leo
Normal file
4
type-inference/tests/functions/invalid_function.leo
Normal file
@ -0,0 +1,4 @@
|
||||
function main() {
|
||||
let a = 1u8;
|
||||
let b = a(); // Variable `a` is not a function.
|
||||
}
|
25
type-inference/tests/functions/mod.rs
Normal file
25
type-inference/tests/functions/mod.rs
Normal file
@ -0,0 +1,25 @@
|
||||
// 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 crate::TestTypeInference;
|
||||
|
||||
#[test]
|
||||
fn test_invalid_function() {
|
||||
let bytes = include_bytes!("invalid_function.leo");
|
||||
let check = TestTypeInference::new(bytes);
|
||||
|
||||
check.expect_error();
|
||||
}
|
84
type-inference/tests/mod.rs
Normal file
84
type-inference/tests/mod.rs
Normal file
@ -0,0 +1,84 @@
|
||||
// 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 arrays;
|
||||
pub mod circuits;
|
||||
pub mod functions;
|
||||
pub mod tuples;
|
||||
pub mod variables;
|
||||
|
||||
use leo_grammar::Grammar;
|
||||
use leo_type_inference::TypeInference;
|
||||
|
||||
use leo_ast::{Input, LeoAst, Program};
|
||||
use leo_imports::ImportParser;
|
||||
use leo_symbol_table::SymbolTable;
|
||||
use std::path::PathBuf;
|
||||
|
||||
const TEST_PROGRAM_PATH: &str = "";
|
||||
const TEST_PROGRAM_NAME: &str = "test";
|
||||
|
||||
/// A helper struct to test a `TypeInference` check.
|
||||
pub struct TestTypeInference {
|
||||
program: Program,
|
||||
symbol_table: SymbolTable,
|
||||
}
|
||||
|
||||
impl TestTypeInference {
|
||||
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 = Grammar::new(&file_path, &*file_string).unwrap();
|
||||
|
||||
// Get typed syntax tree.
|
||||
let typed = LeoAst::new(TEST_PROGRAM_NAME, &ast);
|
||||
let program = typed.into_repr();
|
||||
|
||||
// Create empty import parser.
|
||||
let import_parser = ImportParser::default();
|
||||
|
||||
// Create empty input.
|
||||
let input = Input::new();
|
||||
|
||||
// Create symbol table.
|
||||
let symbol_table = SymbolTable::new(&program, &import_parser, &input).unwrap();
|
||||
|
||||
// Store fields for new type inference check.
|
||||
Self { program, symbol_table }
|
||||
}
|
||||
|
||||
pub fn check(self) {
|
||||
TypeInference::new(&self.program, self.symbol_table).unwrap();
|
||||
}
|
||||
|
||||
pub fn expect_error(self) {
|
||||
assert!(TypeInference::new(&self.program, self.symbol_table).is_err());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_new() {
|
||||
let bytes = include_bytes!("empty.leo");
|
||||
|
||||
let type_inference = TestTypeInference::new(bytes);
|
||||
|
||||
type_inference.check()
|
||||
}
|
5
type-inference/tests/tuples/invalid_tuple_access.leo
Normal file
5
type-inference/tests/tuples/invalid_tuple_access.leo
Normal file
@ -0,0 +1,5 @@
|
||||
function main() {
|
||||
let a = [1u8; 3];
|
||||
|
||||
let b = a.0; // It is illegal to index into an array using dot syntax.
|
||||
}
|
25
type-inference/tests/tuples/mod.rs
Normal file
25
type-inference/tests/tuples/mod.rs
Normal file
@ -0,0 +1,25 @@
|
||||
// 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 crate::TestTypeInference;
|
||||
|
||||
#[test]
|
||||
fn test_invalid_tuple_access() {
|
||||
let bytes = include_bytes!("invalid_tuple_access.leo");
|
||||
let check = TestTypeInference::new(bytes);
|
||||
|
||||
check.expect_error();
|
||||
}
|
4
type-inference/tests/variables/duplicate_variable.leo
Normal file
4
type-inference/tests/variables/duplicate_variable.leo
Normal file
@ -0,0 +1,4 @@
|
||||
function main() {
|
||||
let a = 1u8;
|
||||
let a = 2u8; // Redefining variables with the same name is unsafe in Leo.
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
function main() {
|
||||
let (a, a) = (2u8, 2u8); // Defining multiple variables with the same name is unsafe in Leo.
|
||||
}
|
49
type-inference/tests/variables/mod.rs
Normal file
49
type-inference/tests/variables/mod.rs
Normal file
@ -0,0 +1,49 @@
|
||||
// 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 crate::TestTypeInference;
|
||||
|
||||
#[test]
|
||||
fn test_duplicate_variable() {
|
||||
let bytes = include_bytes!("duplicate_variable.leo");
|
||||
let check = TestTypeInference::new(bytes);
|
||||
|
||||
check.expect_error();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_duplicate_variable_multi() {
|
||||
let bytes = include_bytes!("duplicate_variable_multi.leo");
|
||||
let check = TestTypeInference::new(bytes);
|
||||
|
||||
check.expect_error();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_not_enough_values() {
|
||||
let bytes = include_bytes!("not_enough_values.leo");
|
||||
let check = TestTypeInference::new(bytes);
|
||||
|
||||
check.expect_error();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_too_many_values() {
|
||||
let bytes = include_bytes!("too_many_values.leo");
|
||||
let check = TestTypeInference::new(bytes);
|
||||
|
||||
check.expect_error();
|
||||
}
|
3
type-inference/tests/variables/not_enough_values.leo
Normal file
3
type-inference/tests/variables/not_enough_values.leo
Normal file
@ -0,0 +1,3 @@
|
||||
function main() {
|
||||
let (a, b): (u8, u8) = 1; // A tuple of values must be used when defining two variables.
|
||||
}
|
3
type-inference/tests/variables/too_many_values.leo
Normal file
3
type-inference/tests/variables/too_many_values.leo
Normal file
@ -0,0 +1,3 @@
|
||||
function main() {
|
||||
let (a, b): (u8, u8) = (1, 2, 3); // Cannot assign 2 variables to 3 values.
|
||||
}
|
Loading…
Reference in New Issue
Block a user