mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-12-25 03:04:13 +03:00
add dynamic check errors for circuits 1
This commit is contained in:
parent
40d26dce7f
commit
973e2a6afc
@ -14,18 +14,9 @@
|
||||
// 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, EdwardsTestCompiler};
|
||||
use crate::{assert_satisfied, expect_compiler_error, expect_dynamic_check_error, parse_program, EdwardsTestCompiler};
|
||||
use leo_compiler::errors::{CompilerError, ExpressionError, FunctionError, StatementError};
|
||||
|
||||
fn expect_fail(program: EdwardsTestCompiler) {
|
||||
match expect_compiler_error(program) {
|
||||
CompilerError::FunctionError(FunctionError::StatementError(StatementError::ExpressionError(
|
||||
ExpressionError::Error(_string),
|
||||
))) => {}
|
||||
error => panic!("Expected invalid circuit member error, got {}", error),
|
||||
}
|
||||
}
|
||||
|
||||
// Expressions
|
||||
|
||||
#[test]
|
||||
@ -41,15 +32,15 @@ fn test_inline_fail() {
|
||||
let bytes = include_bytes!("inline_fail.leo");
|
||||
let program = parse_program(bytes).unwrap();
|
||||
|
||||
expect_fail(program);
|
||||
expect_compiler_error(program);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_inline_undefined() {
|
||||
let bytes = include_bytes!("inline_undefined.leo");
|
||||
let program = parse_program(bytes).unwrap();
|
||||
let error = parse_program(bytes).err().unwrap();
|
||||
|
||||
expect_fail(program);
|
||||
expect_dynamic_check_error(error);
|
||||
}
|
||||
|
||||
// Members
|
||||
@ -65,9 +56,9 @@ fn test_member_variable() {
|
||||
#[test]
|
||||
fn test_member_variable_fail() {
|
||||
let bytes = include_bytes!("member_variable_fail.leo");
|
||||
let program = parse_program(bytes).unwrap();
|
||||
let error = parse_program(bytes).err().unwrap();
|
||||
|
||||
expect_fail(program);
|
||||
expect_dynamic_check_error(error);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -89,17 +80,17 @@ fn test_member_function() {
|
||||
#[test]
|
||||
fn test_member_function_fail() {
|
||||
let bytes = include_bytes!("member_function_fail.leo");
|
||||
let program = parse_program(bytes).unwrap();
|
||||
let error = parse_program(bytes).err().unwrap();
|
||||
|
||||
expect_fail(program);
|
||||
expect_dynamic_check_error(error);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_member_function_invalid() {
|
||||
let bytes = include_bytes!("member_function_invalid.leo");
|
||||
let program = parse_program(bytes).unwrap();
|
||||
let error = parse_program(bytes).err().unwrap();
|
||||
|
||||
expect_fail(program);
|
||||
expect_dynamic_check_error(error);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -129,17 +120,17 @@ fn test_member_static_function_nested() {
|
||||
#[test]
|
||||
fn test_member_static_function_invalid() {
|
||||
let bytes = include_bytes!("member_static_function_invalid.leo");
|
||||
let program = parse_program(bytes).unwrap();
|
||||
let error = parse_program(bytes).err().unwrap();
|
||||
|
||||
expect_fail(program)
|
||||
expect_dynamic_check_error(error)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_member_static_function_undefined() {
|
||||
let bytes = include_bytes!("member_static_function_undefined.leo");
|
||||
let program = parse_program(bytes).unwrap();
|
||||
let error = parse_program(bytes).err().unwrap();
|
||||
|
||||
expect_fail(program)
|
||||
expect_dynamic_check_error(error)
|
||||
}
|
||||
|
||||
// Mutability
|
||||
@ -213,9 +204,9 @@ fn test_mutate_variable_fail() {
|
||||
#[test]
|
||||
fn test_self_fail() {
|
||||
let bytes = include_bytes!("self_fail.leo");
|
||||
let program = parse_program(bytes).unwrap();
|
||||
let error = parse_program(bytes).err().unwrap();
|
||||
|
||||
expect_compiler_error(program);
|
||||
expect_dynamic_check_error(error);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -696,6 +696,15 @@ impl Frame {
|
||||
/// Returns the type of the identifier in the symbol table.
|
||||
///
|
||||
fn parse_identifier(&self, identifier: &Identifier) -> Result<Type, FrameError> {
|
||||
// Check Self type.
|
||||
if identifier.is_self_type() {
|
||||
// Check for frame circuit self type.
|
||||
let circuit_type = self.self_type_or_error(&identifier.span)?;
|
||||
|
||||
// Return new type with circuit identifier.
|
||||
return Ok(Type::Circuit(circuit_type.identifier));
|
||||
}
|
||||
|
||||
// Check variable symbol table.
|
||||
if let Some(type_) = self.get_variable(&identifier.name) {
|
||||
return Ok(type_.to_owned());
|
||||
@ -730,7 +739,6 @@ impl Frame {
|
||||
right: &Expression,
|
||||
span: &Span,
|
||||
) -> Result<Type, FrameError> {
|
||||
println!("left {}, right {}", left, right);
|
||||
// Get the left expression type.
|
||||
let left_type = self.parse_expression(left)?;
|
||||
|
||||
@ -998,6 +1006,16 @@ impl Frame {
|
||||
Ok(*element_type)
|
||||
}
|
||||
|
||||
///
|
||||
/// Returns the Self type of the frame or an error if it does not exist.
|
||||
///
|
||||
fn self_type_or_error(&self, span: &Span) -> Result<CircuitType, FrameError> {
|
||||
self.self_type
|
||||
.as_ref()
|
||||
.map(|circuit_type| circuit_type.clone())
|
||||
.ok_or_else(|| FrameError::circuit_self(span))
|
||||
}
|
||||
|
||||
///
|
||||
/// Returns the type of inline circuit expression.
|
||||
///
|
||||
@ -1009,14 +1027,15 @@ impl Frame {
|
||||
) -> Result<Type, FrameError> {
|
||||
// Check if identifier is Self circuit type.
|
||||
let circuit_type = if identifier.is_self() {
|
||||
self.self_type.clone()
|
||||
// Get the Self type of the frame.
|
||||
self.self_type_or_error(span)?
|
||||
} else {
|
||||
// Get circuit type.
|
||||
self.user_defined_types
|
||||
.get_circuit(&identifier.name)
|
||||
.map(|circuit_type| circuit_type.clone())
|
||||
}
|
||||
.unwrap();
|
||||
.ok_or_else(|| FrameError::undefined_circuit(identifier))?
|
||||
};
|
||||
|
||||
// Check the length of the circuit members.
|
||||
if circuit_type.variables.len() != members.len() {
|
||||
@ -1064,7 +1083,7 @@ impl Frame {
|
||||
let circuit_type = self.parse_circuit_name(type_, span)?;
|
||||
|
||||
// Look for member with matching name.
|
||||
Ok(circuit_type.member_type(&identifier).unwrap())
|
||||
Ok(circuit_type.member_type(&identifier)?)
|
||||
}
|
||||
|
||||
///
|
||||
@ -1092,7 +1111,7 @@ impl Frame {
|
||||
// Lookup circuit identifier.
|
||||
self.user_defined_types.get_circuit(&identifier.name).unwrap()
|
||||
}
|
||||
_ => unimplemented!("expected circuit type"),
|
||||
type_ => unimplemented!("expected circuit type {:?}", type_),
|
||||
})
|
||||
}
|
||||
|
||||
@ -1143,7 +1162,9 @@ impl Frame {
|
||||
let circuit_type = self.parse_circuit_name(type_, span)?;
|
||||
|
||||
// Find circuit function by identifier.
|
||||
Ok(circuit_type.member_function_type(identifier).unwrap())
|
||||
circuit_type
|
||||
.member_function_type(identifier)
|
||||
.ok_or_else(|| FrameError::undefined_circuit_function(identifier))
|
||||
}
|
||||
|
||||
///
|
||||
@ -1160,7 +1181,7 @@ impl Frame {
|
||||
|
||||
// Check that the function is non-static.
|
||||
if circuit_function_type.attributes.contains(&Attribute::Static) {
|
||||
unimplemented!("Called static function using dot syntax")
|
||||
return Err(FrameError::invalid_static_access(identifier));
|
||||
}
|
||||
|
||||
// Return the function type.
|
||||
@ -1181,7 +1202,7 @@ impl Frame {
|
||||
|
||||
// Check that the function is static.
|
||||
if !circuit_function_type.attributes.contains(&Attribute::Static) {
|
||||
unimplemented!("Called non-static function using double colon syntax")
|
||||
return Err(FrameError::invalid_member_access(identifier));
|
||||
}
|
||||
|
||||
Ok(circuit_function_type.function.to_owned())
|
||||
@ -1199,7 +1220,6 @@ impl Frame {
|
||||
span: &Span,
|
||||
) -> Result<Type, FrameError> {
|
||||
// Parse the function name.
|
||||
println!("expression {}", expression);
|
||||
let function_type = self.parse_function_name(expression, span)?;
|
||||
|
||||
// Check the length of arguments
|
||||
@ -1656,9 +1676,10 @@ impl TypeVariablePairs {
|
||||
match (left, right) {
|
||||
(Type::TypeVariable(variable), type_) => Ok(self.push(variable, type_)),
|
||||
(type_, Type::TypeVariable(variable)) => Ok(self.push(variable, type_)),
|
||||
(Type::Array(type1, dimensions1), Type::Array(type2, dimensions2)) => {
|
||||
self.push_pairs_array(type1, dimensions1, type2, dimensions2, span)
|
||||
(Type::Array(left_type, left_dimensions), Type::Array(right_type, right_dimensions)) => {
|
||||
self.push_pairs_array(left_type, left_dimensions, right_type, right_dimensions, span)
|
||||
}
|
||||
(Type::Tuple(left_types), Type::Tuple(right_types)) => self.push_pairs_tuple(left_types, right_types, span),
|
||||
(_, _) => Ok(()), // No `TypeVariable` found so we do not push any pairs.
|
||||
}
|
||||
}
|
||||
@ -1694,4 +1715,24 @@ impl TypeVariablePairs {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
///
|
||||
/// 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: &Vec<Type>,
|
||||
right_types: &Vec<Type>,
|
||||
span: &Span,
|
||||
) -> Result<(), TypeAssertionError> {
|
||||
// Iterate over each left == right pair of types.
|
||||
for (left, right) in left_types.iter().zip(right_types) {
|
||||
// Check for `TypeVariablePair`s.
|
||||
self.push_pairs(left, right, span)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
use crate::{ScopeError, TypeAssertionError};
|
||||
use leo_static_check::TypeError;
|
||||
use leo_typed::{Error as FormattedError, Span};
|
||||
use leo_typed::{Error as FormattedError, Identifier, Span};
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
@ -49,10 +49,55 @@ impl FrameError {
|
||||
}
|
||||
}
|
||||
|
||||
// ///
|
||||
// /// 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))
|
||||
// }
|
||||
///
|
||||
/// 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))
|
||||
}
|
||||
|
||||
///
|
||||
/// 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.to_owned())
|
||||
}
|
||||
|
||||
///
|
||||
/// 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.to_owned())
|
||||
}
|
||||
|
||||
///
|
||||
/// 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.to_owned())
|
||||
}
|
||||
|
||||
///
|
||||
/// 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.to_owned())
|
||||
}
|
||||
|
||||
///
|
||||
/// 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.to_owned())
|
||||
}
|
||||
}
|
||||
|
@ -46,8 +46,12 @@ pub struct Identifier {
|
||||
}
|
||||
|
||||
impl Identifier {
|
||||
pub fn is_self_type(&self) -> bool {
|
||||
self.name == "Self"
|
||||
}
|
||||
|
||||
pub fn is_self(&self) -> bool {
|
||||
self.name == "Self" || self.name == "self"
|
||||
self.is_self_type() || self.name == "self"
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user