From 973e2a6afc5e95209ad539cfe613bd22e7f2a1bc Mon Sep 17 00:00:00 2001 From: collin Date: Sat, 24 Oct 2020 02:53:09 -0700 Subject: [PATCH] add dynamic check errors for circuits 1 --- compiler/tests/circuits/mod.rs | 41 ++++++++----------- dynamic-check/src/dynamic_check.rs | 65 ++++++++++++++++++++++++------ dynamic-check/src/errors/frame.rs | 59 +++++++++++++++++++++++---- typed/src/common/identifier.rs | 6 ++- 4 files changed, 126 insertions(+), 45 deletions(-) diff --git a/compiler/tests/circuits/mod.rs b/compiler/tests/circuits/mod.rs index 4c9c8665e9..f192067104 100644 --- a/compiler/tests/circuits/mod.rs +++ b/compiler/tests/circuits/mod.rs @@ -14,18 +14,9 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -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] diff --git a/dynamic-check/src/dynamic_check.rs b/dynamic-check/src/dynamic_check.rs index 61308fa892..a3fab01667 100644 --- a/dynamic-check/src/dynamic_check.rs +++ b/dynamic-check/src/dynamic_check.rs @@ -696,6 +696,15 @@ impl Frame { /// Returns the type of the identifier in the symbol table. /// fn parse_identifier(&self, identifier: &Identifier) -> Result { + // 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 { - 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 { + 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 { // 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 { // 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, + right_types: &Vec, + 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(()) + } } diff --git a/dynamic-check/src/errors/frame.rs b/dynamic-check/src/errors/frame.rs index b6ff758e55..0bf5f2e961 100644 --- a/dynamic-check/src/errors/frame.rs +++ b/dynamic-check/src/errors/frame.rs @@ -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()) + } } diff --git a/typed/src/common/identifier.rs b/typed/src/common/identifier.rs index c10474e62c..6b08d8b58b 100644 --- a/typed/src/common/identifier.rs +++ b/typed/src/common/identifier.rs @@ -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" } }