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"
}
}