add new dynamic check errors and tests for tuples and arrays

This commit is contained in:
collin 2020-10-26 19:13:37 -07:00
parent d3125a0f9f
commit c4a7e36623
9 changed files with 157 additions and 22 deletions

View File

@ -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.

View File

@ -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)
}
}

View File

@ -0,0 +1,3 @@
function main() {
let a = [1u8; 0]; // Empty arrays are illegal in Leo programs since arrays cannot be resized.
}

View 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.
}

View File

@ -0,0 +1,5 @@
function main() {
let a: u8 = 1;
let b = [...a];
}

View 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();
}

View File

@ -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;

View 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.
}

View 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();
}