mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-12-29 13:14:05 +03:00
add new dynamic check errors and tests for tuples and arrays
This commit is contained in:
parent
d3125a0f9f
commit
c4a7e36623
@ -879,11 +879,11 @@ impl Frame {
|
||||
///
|
||||
/// Returns the type of the accessed tuple element.
|
||||
///
|
||||
fn parse_tuple_access(&mut self, type_: Type, index: usize, _span: &Span) -> Result<Type, FrameError> {
|
||||
fn parse_tuple_access(&mut self, type_: Type, index: usize, span: &Span) -> Result<Type, FrameError> {
|
||||
// Check the type is a tuple.
|
||||
let elements = match type_ {
|
||||
Type::Tuple(elements) => elements,
|
||||
_ => unimplemented!("expected a tuple type"),
|
||||
type_ => return Err(FrameError::tuple_access(&type_, span)),
|
||||
};
|
||||
|
||||
let element_type = elements[index].clone();
|
||||
@ -902,7 +902,7 @@ impl Frame {
|
||||
// Parse all array elements.
|
||||
for expression in expressions {
|
||||
// Get the type and count of elements in each spread or expression.
|
||||
let (type_, element_count) = self.parse_spread_or_expression(expression)?;
|
||||
let (type_, element_count) = self.parse_spread_or_expression(expression, span)?;
|
||||
|
||||
// Assert that array element types are the same.
|
||||
if let Some(prev_type) = element_type {
|
||||
@ -919,7 +919,7 @@ impl Frame {
|
||||
// Return an error for empty arrays.
|
||||
let type_ = match element_type {
|
||||
Some(type_) => type_,
|
||||
None => unimplemented!("return empty array error"),
|
||||
None => return Err(FrameError::empty_array(span)),
|
||||
};
|
||||
|
||||
Ok(Type::Array(Box::new(type_), vec![count]))
|
||||
@ -928,7 +928,11 @@ impl Frame {
|
||||
///
|
||||
/// Returns the type and count of elements in a spread or expression.
|
||||
///
|
||||
fn parse_spread_or_expression(&mut self, s_or_e: &SpreadOrExpression) -> Result<(Type, usize), FrameError> {
|
||||
fn parse_spread_or_expression(
|
||||
&mut self,
|
||||
s_or_e: &SpreadOrExpression,
|
||||
span: &Span,
|
||||
) -> Result<(Type, usize), FrameError> {
|
||||
Ok(match s_or_e {
|
||||
SpreadOrExpression::Spread(expression) => {
|
||||
// Parse the type of the spread array expression.
|
||||
@ -937,7 +941,7 @@ impl Frame {
|
||||
// Check that the type is an array.
|
||||
let (element_type, mut dimensions) = match array_type {
|
||||
Type::Array(element_type, dimensions) => (element_type, dimensions),
|
||||
_ => unimplemented!("Spread type must be an array"),
|
||||
type_ => return Err(FrameError::invalid_spread(type_, span)),
|
||||
};
|
||||
|
||||
// A spread copies the elements of an array.
|
||||
@ -980,7 +984,7 @@ impl Frame {
|
||||
// Check the type is an array.
|
||||
let (element_type, _dimensions) = match type_ {
|
||||
Type::Array(type_, dimensions) => (type_, dimensions),
|
||||
_ => unimplemented!("expected an array type"),
|
||||
type_ => return Err(FrameError::array_access(&type_, span)),
|
||||
};
|
||||
|
||||
// Get the length of the array.
|
||||
|
@ -15,7 +15,7 @@
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::{ScopeError, TypeAssertionError};
|
||||
use leo_static_check::TypeError;
|
||||
use leo_static_check::{Type, TypeError};
|
||||
use leo_typed::{Error as FormattedError, Identifier, Span};
|
||||
|
||||
use std::path::PathBuf;
|
||||
@ -52,8 +52,17 @@ 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))
|
||||
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)
|
||||
}
|
||||
|
||||
///
|
||||
@ -62,7 +71,7 @@ impl FrameError {
|
||||
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())
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
///
|
||||
@ -71,7 +80,18 @@ impl FrameError {
|
||||
pub fn duplicate_variable(name: &str, span: &Span) -> Self {
|
||||
let message = format!("Duplicate variable definition found for `{}`", name);
|
||||
|
||||
Self::new_from_span(message, span.to_owned())
|
||||
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)
|
||||
}
|
||||
|
||||
///
|
||||
@ -80,7 +100,19 @@ impl FrameError {
|
||||
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())
|
||||
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)
|
||||
}
|
||||
|
||||
///
|
||||
@ -89,7 +121,7 @@ impl FrameError {
|
||||
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())
|
||||
Self::new_from_span(message, &identifier.span)
|
||||
}
|
||||
|
||||
///
|
||||
@ -98,7 +130,7 @@ impl FrameError {
|
||||
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.clone())
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
///
|
||||
@ -110,7 +142,16 @@ impl FrameError {
|
||||
expected, actual
|
||||
);
|
||||
|
||||
Self::new_from_span(message, span.clone())
|
||||
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)
|
||||
}
|
||||
|
||||
///
|
||||
@ -119,7 +160,7 @@ impl FrameError {
|
||||
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())
|
||||
Self::new_from_span(message, &identifier.span)
|
||||
}
|
||||
|
||||
///
|
||||
@ -128,7 +169,7 @@ impl FrameError {
|
||||
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())
|
||||
Self::new_from_span(message, &identifier.span)
|
||||
}
|
||||
|
||||
///
|
||||
@ -137,7 +178,7 @@ impl FrameError {
|
||||
pub fn undefined_function(identifier: &Identifier) -> Self {
|
||||
let message = format!("The function `{}` is not defined.", identifier);
|
||||
|
||||
Self::new_from_span(message, identifier.span.to_owned())
|
||||
Self::new_from_span(message, &identifier.span)
|
||||
}
|
||||
|
||||
///
|
||||
@ -146,7 +187,7 @@ impl FrameError {
|
||||
pub fn undefined_variable(identifier: &Identifier) -> Self {
|
||||
let message = format!("The variable `{}` is not defined.", identifier);
|
||||
|
||||
Self::new_from_span(message, identifier.span.to_owned())
|
||||
Self::new_from_span(message, &identifier.span)
|
||||
}
|
||||
|
||||
///
|
||||
@ -155,7 +196,7 @@ impl FrameError {
|
||||
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.to_owned())
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
///
|
||||
@ -167,6 +208,6 @@ impl FrameError {
|
||||
expected, actual
|
||||
);
|
||||
|
||||
Self::new_from_span(message, span.to_owned())
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
}
|
||||
|
3
dynamic-check/tests/arrays/empty_array.leo
Normal file
3
dynamic-check/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
dynamic-check/tests/arrays/invalid_array_access.leo
Normal file
5
dynamic-check/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
dynamic-check/tests/arrays/invalid_spread.leo
Normal file
5
dynamic-check/tests/arrays/invalid_spread.leo
Normal file
@ -0,0 +1,5 @@
|
||||
function main() {
|
||||
let a: u8 = 1;
|
||||
|
||||
let b = [...a];
|
||||
}
|
44
dynamic-check/tests/arrays/mod.rs
Normal file
44
dynamic-check/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::TestDynamicCheck;
|
||||
|
||||
#[test]
|
||||
fn test_empty_array() {
|
||||
let bytes = include_bytes!("empty_array.leo");
|
||||
|
||||
let check = TestDynamicCheck::new(bytes);
|
||||
|
||||
check.expect_create_error();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_invalid_array_access() {
|
||||
let bytes = include_bytes!("invalid_array_access.leo");
|
||||
|
||||
let check = TestDynamicCheck::new(bytes);
|
||||
|
||||
check.expect_create_error();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_invalid_spread() {
|
||||
let bytes = include_bytes!("invalid_spread.leo");
|
||||
|
||||
let check = TestDynamicCheck::new(bytes);
|
||||
|
||||
check.expect_create_error();
|
||||
}
|
@ -13,6 +13,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/>.
|
||||
|
||||
pub mod arrays;
|
||||
pub mod tuples;
|
||||
pub mod variables;
|
||||
|
||||
use leo_ast::LeoAst;
|
||||
|
5
dynamic-check/tests/tuples/invalid_tuple_access.leo
Normal file
5
dynamic-check/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
dynamic-check/tests/tuples/mod.rs
Normal file
25
dynamic-check/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::TestDynamicCheck;
|
||||
|
||||
#[test]
|
||||
fn test_invalid_tuple_access() {
|
||||
let bytes = include_bytes!("invalid_tuple_access.leo");
|
||||
let check = TestDynamicCheck::new(bytes);
|
||||
|
||||
check.expect_create_error();
|
||||
}
|
Loading…
Reference in New Issue
Block a user