mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-12-25 03:04:13 +03:00
do not compare array dimensions in type inference
This commit is contained in:
parent
6f3a235c76
commit
1daf6c9831
@ -14,7 +14,6 @@
|
||||
// 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::Type;
|
||||
use leo_ast::{Error as FormattedError, Identifier, Span};
|
||||
|
||||
use std::path::Path;
|
||||
@ -43,60 +42,6 @@ impl TypeError {
|
||||
TypeError::Error(FormattedError::new_from_span(message, span))
|
||||
}
|
||||
|
||||
///
|
||||
/// Expected an array type from the given expression.
|
||||
///
|
||||
pub fn invalid_array(actual: &Type, span: Span) -> Self {
|
||||
let message = format!("Expected array type, found type `{}`.", actual);
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
///
|
||||
/// Expected a circuit type from the given expression.
|
||||
///
|
||||
pub fn invalid_circuit(actual: &Type, span: Span) -> Self {
|
||||
let message = format!("Expected circuit type, found type `{}`.", actual);
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
///
|
||||
/// Expected a function type from the given expression.
|
||||
///
|
||||
pub fn invalid_function(actual: &Type, span: Span) -> Self {
|
||||
let message = format!("Expected function type, found type `{}`.", actual);
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
///
|
||||
/// Expected an integer type from the given expression.
|
||||
///
|
||||
pub fn invalid_integer(actual: &Type, span: Span) -> Self {
|
||||
let message = format!("Expected integer type, found type `{}`.", actual);
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
///
|
||||
/// Expected a tuple type from the given expression.
|
||||
///
|
||||
pub fn invalid_tuple(actual: &Type, span: Span) -> Self {
|
||||
let message = format!("Expected tuple type, found type `{}`.", actual);
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
///
|
||||
/// The value of the expression does not match the given explicit type.
|
||||
///
|
||||
pub fn mismatched_types(expected: &Type, actual: &Type, span: Span) -> Self {
|
||||
let message = format!("Expected type `{}`, found type `{}`.", expected, actual);
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
///
|
||||
/// The `Self` keyword was used outside of a circuit.
|
||||
///
|
||||
|
@ -14,7 +14,7 @@
|
||||
// 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::{SymbolTable, TypeError, TypeVariable};
|
||||
use leo_ast::{ArrayDimensions, Identifier, IntegerType, Span, Type as UnresolvedType};
|
||||
use leo_ast::{Identifier, IntegerType, Span, Type as UnresolvedType};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{
|
||||
@ -33,7 +33,7 @@ pub enum Type {
|
||||
IntegerType(IntegerType),
|
||||
|
||||
// Data type wrappers
|
||||
Array(Box<Type>, ArrayDimensions),
|
||||
Array(Box<Type>),
|
||||
Tuple(Vec<Type>),
|
||||
|
||||
// User defined types
|
||||
@ -58,10 +58,10 @@ impl Type {
|
||||
UnresolvedType::Group => Type::Group,
|
||||
UnresolvedType::IntegerType(integer) => Type::IntegerType(integer),
|
||||
|
||||
UnresolvedType::Array(type_, dimensions) => {
|
||||
UnresolvedType::Array(type_, _) => {
|
||||
let array_type = Type::new(table, *type_, span)?;
|
||||
|
||||
Type::Array(Box::new(array_type), dimensions)
|
||||
Type::Array(Box::new(array_type))
|
||||
}
|
||||
UnresolvedType::Tuple(types) => {
|
||||
let tuple_types = types
|
||||
@ -100,9 +100,9 @@ impl Type {
|
||||
span: Span,
|
||||
) -> Result<Self, TypeError> {
|
||||
Ok(match type_ {
|
||||
UnresolvedType::Array(type_, dimensions) => {
|
||||
UnresolvedType::Array(type_, _) => {
|
||||
let array_type = Type::new_from_circuit(table, *type_, circuit_name, span)?;
|
||||
Type::Array(Box::new(array_type), dimensions)
|
||||
Type::Array(Box::new(array_type))
|
||||
}
|
||||
UnresolvedType::Tuple(types) => {
|
||||
let tuple_types = types
|
||||
@ -118,73 +118,6 @@ impl Type {
|
||||
})
|
||||
}
|
||||
|
||||
///
|
||||
/// Returns `Ok` if the given expected type is `Some` and expected type == actual type.
|
||||
///
|
||||
pub fn check_type(expected_option: &Option<Self>, actual: &Type, span: Span) -> Result<(), TypeError> {
|
||||
if let Some(expected) = expected_option {
|
||||
if expected.ne(actual) {
|
||||
return Err(TypeError::mismatched_types(expected, actual, span));
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
///
|
||||
/// Returns `Ok` if self is an expected integer type `Type::IntegerType`.
|
||||
///
|
||||
pub fn check_type_integer(&self, span: Span) -> Result<(), TypeError> {
|
||||
match self {
|
||||
Type::IntegerType(_) => Ok(()),
|
||||
// Throw mismatched type error
|
||||
type_ => Err(TypeError::invalid_integer(type_, span)),
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Returns array element type and dimensions if self is an expected array type `Type::Array`.
|
||||
///
|
||||
pub fn get_type_array(&self, span: Span) -> Result<(&Type, &ArrayDimensions), TypeError> {
|
||||
match self {
|
||||
Type::Array(element_type, dimensions) => Ok((element_type, dimensions)),
|
||||
// Throw mismatched type error
|
||||
type_ => Err(TypeError::invalid_array(type_, span)),
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Returns tuple element types if self is an expected tuple type `Type::Tuple`.
|
||||
///
|
||||
pub fn get_type_tuple(&self, span: Span) -> Result<&Vec<Type>, TypeError> {
|
||||
match self {
|
||||
Type::Tuple(types) => Ok(types),
|
||||
// Throw mismatched type error
|
||||
type_ => Err(TypeError::invalid_tuple(type_, span)),
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Returns circuit identifier if self is an expected circuit type `Type::Circuit`.
|
||||
///
|
||||
pub fn get_type_circuit(&self, span: Span) -> Result<&Identifier, TypeError> {
|
||||
match self {
|
||||
Type::Circuit(identifier) => Ok(identifier),
|
||||
// Throw mismatched type error
|
||||
type_ => Err(TypeError::invalid_circuit(type_, span)),
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Returns function identifier if self is an expected function type `Type::Function`.
|
||||
///
|
||||
pub fn get_type_function(&self, span: Span) -> Result<&Identifier, TypeError> {
|
||||
match self {
|
||||
Type::Function(identifier) => Ok(identifier),
|
||||
// Throw mismatched type error
|
||||
type_ => Err(TypeError::invalid_function(type_, span)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a list of signed integer types.
|
||||
pub const fn signed_integer_types() -> [Type; 5] {
|
||||
[
|
||||
@ -254,7 +187,7 @@ impl Type {
|
||||
*self = type_.to_owned()
|
||||
}
|
||||
}
|
||||
Type::Array(self_type, _) => {
|
||||
Type::Array(self_type) => {
|
||||
self_type.substitute(variable, type_);
|
||||
}
|
||||
Type::Tuple(types) => types
|
||||
@ -274,7 +207,7 @@ impl fmt::Display for Type {
|
||||
Type::Group => write!(f, "group"),
|
||||
Type::IntegerType(integer_type) => write!(f, "{}", integer_type),
|
||||
|
||||
Type::Array(type_, dimensions) => write!(f, "[{}; {}]", *type_, dimensions),
|
||||
Type::Array(type_) => write!(f, "[{}]", *type_),
|
||||
Type::Tuple(tuple) => {
|
||||
let tuple_string = tuple.iter().map(|x| x.to_string()).collect::<Vec<_>>().join(", ");
|
||||
|
||||
@ -297,7 +230,7 @@ impl PartialEq for Type {
|
||||
(Type::Group, Type::Group) => true,
|
||||
(Type::IntegerType(integer_type1), Type::IntegerType(integer_type2)) => integer_type1.eq(integer_type2),
|
||||
|
||||
(Type::Array(array1, _), Type::Array(array2, _)) => {
|
||||
(Type::Array(array1), Type::Array(array2)) => {
|
||||
// Get both array element types before comparison.
|
||||
let array1_element = get_array_element_type(array1);
|
||||
let array2_element = get_array_element_type(array2);
|
||||
@ -324,7 +257,7 @@ impl Eq for Type {}
|
||||
/// If the given `type_` is any other type, return the `type_`.
|
||||
///
|
||||
pub fn get_array_element_type(type_: &Type) -> &Type {
|
||||
if let Type::Array(element_type, _) = type_ {
|
||||
if let Type::Array(element_type) = type_ {
|
||||
get_array_element_type(element_type)
|
||||
} else {
|
||||
type_
|
||||
|
@ -17,7 +17,6 @@
|
||||
use crate::TypeAssertionError;
|
||||
use leo_ast::Span;
|
||||
use leo_symbol_table::{get_array_element_type, Type, TypeVariable};
|
||||
use std::borrow::Cow;
|
||||
|
||||
/// A type variable -> type pair.
|
||||
pub struct TypeVariablePair(TypeVariable, Type);
|
||||
@ -88,9 +87,7 @@ 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(left_type, _), Type::Array(right_type, _)) => {
|
||||
self.push_pairs_array(*left_type, *right_type, span)
|
||||
}
|
||||
(Type::Array(left_type), Type::Array(right_type)) => self.push_pairs_array(*left_type, *right_type, span),
|
||||
(Type::Tuple(left_types), Type::Tuple(right_types)) => {
|
||||
self.push_pairs_tuple(left_types.into_iter(), right_types.into_iter(), span)
|
||||
}
|
||||
|
@ -112,6 +112,15 @@ impl FrameError {
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
///
|
||||
/// Expected a usize number for the index.
|
||||
///
|
||||
pub fn invalid_index(actual: String, span: &Span) -> Self {
|
||||
let message = format!("Expected constant number for index, found `{}`", actual);
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
///
|
||||
/// Attempted to call non-static member using `::`.
|
||||
///
|
||||
|
@ -26,6 +26,7 @@ use leo_ast::{
|
||||
Function,
|
||||
Identifier,
|
||||
IntegerType,
|
||||
PositiveNumber,
|
||||
RangeOrExpression,
|
||||
Span,
|
||||
SpreadOrExpression,
|
||||
@ -372,7 +373,7 @@ impl Frame {
|
||||
for access in &assignee.accesses {
|
||||
let access_type = match access {
|
||||
AssigneeAccess::Array(r_or_e) => self.parse_array_access(type_, r_or_e, span),
|
||||
AssigneeAccess::Tuple(index) => self.parse_tuple_access(type_, *index, span),
|
||||
AssigneeAccess::Tuple(index, _) => self.parse_tuple_access(type_, &index, span),
|
||||
AssigneeAccess::Member(identifier) => self.parse_circuit_member_access(type_, identifier, span),
|
||||
}?;
|
||||
|
||||
@ -549,13 +550,18 @@ impl Frame {
|
||||
|
||||
// Arrays
|
||||
Expression::ArrayInline(expressions, span) => self.parse_array(expressions, span),
|
||||
Expression::ArrayInitializer(array_w_dimensions, _span) => {
|
||||
self.parse_array_initializer(&array_w_dimensions.0)
|
||||
}
|
||||
Expression::ArrayAccess(array_w_index, span) => {
|
||||
self.parse_expression_array_access(&array_w_index.0, &array_w_index.1, span)
|
||||
}
|
||||
|
||||
// Tuples
|
||||
Expression::Tuple(expressions, span) => self.parse_tuple(expressions, span),
|
||||
Expression::TupleAccess(tuple, index, span) => self.parse_expression_tuple_access(tuple, *index, span),
|
||||
Expression::TupleAccess(tuple_w_index, span) => {
|
||||
self.parse_expression_tuple_access(&tuple_w_index.0, &tuple_w_index.1, span)
|
||||
}
|
||||
|
||||
// Circuits
|
||||
Expression::Circuit(identifier, members, span) => self.parse_circuit(identifier, members, span),
|
||||
@ -737,7 +743,7 @@ impl Frame {
|
||||
fn parse_expression_tuple_access(
|
||||
&mut self,
|
||||
expression: &Expression,
|
||||
index: usize,
|
||||
index: &PositiveNumber,
|
||||
span: &Span,
|
||||
) -> Result<Type, FrameError> {
|
||||
// Parse the tuple expression which could be a variable with type tuple.
|
||||
@ -750,14 +756,20 @@ 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: &PositiveNumber, span: &Span) -> Result<Type, FrameError> {
|
||||
// Check the type is a tuple.
|
||||
let mut elements = match type_ {
|
||||
Type::Tuple(elements) => elements,
|
||||
type_ => return Err(FrameError::tuple_access(&type_, span)),
|
||||
};
|
||||
|
||||
let element_type = elements.swap_remove(index);
|
||||
// Parse index `String` to `usize`.
|
||||
let index_usize = match index.to_string().parse::<usize>() {
|
||||
Ok(index_usize) => index_usize,
|
||||
Err(_) => return Err(FrameError::invalid_index(index.to_string(), span)),
|
||||
};
|
||||
|
||||
let element_type = elements.swap_remove(index_usize);
|
||||
|
||||
Ok(element_type)
|
||||
}
|
||||
@ -768,12 +780,11 @@ impl Frame {
|
||||
fn parse_array(&mut self, expressions: &[SpreadOrExpression], span: &Span) -> Result<Type, FrameError> {
|
||||
// Store array element type.
|
||||
let mut element_type = None;
|
||||
let mut count = 0usize;
|
||||
|
||||
// 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, span)?;
|
||||
let type_ = self.parse_spread_or_expression(expression, span)?;
|
||||
|
||||
// Assert that array element types are the same.
|
||||
if let Some(prev_type) = element_type {
|
||||
@ -782,9 +793,6 @@ impl Frame {
|
||||
|
||||
// Update array element type.
|
||||
element_type = Some(type_);
|
||||
|
||||
// Update number of array elements.
|
||||
count += element_count;
|
||||
}
|
||||
|
||||
// Return an error for empty arrays.
|
||||
@ -793,43 +801,37 @@ impl Frame {
|
||||
None => return Err(FrameError::empty_array(span)),
|
||||
};
|
||||
|
||||
Ok(Type::Array(Box::new(type_), vec![count]))
|
||||
Ok(Type::Array(Box::new(type_)))
|
||||
}
|
||||
|
||||
///
|
||||
/// Returns the type of the array initializer expression.
|
||||
///
|
||||
fn parse_array_initializer(&mut self, array: &Expression) -> Result<Type, FrameError> {
|
||||
// Get element type.
|
||||
let element_type = self.parse_expression(array)?;
|
||||
|
||||
// Return array type.
|
||||
Ok(Type::Array(Box::new(element_type)))
|
||||
}
|
||||
|
||||
///
|
||||
/// Returns the type and count of elements in a spread or expression.
|
||||
///
|
||||
fn parse_spread_or_expression(
|
||||
&mut self,
|
||||
s_or_e: &SpreadOrExpression,
|
||||
span: &Span,
|
||||
) -> Result<(Type, usize), FrameError> {
|
||||
Ok(match s_or_e {
|
||||
fn parse_spread_or_expression(&mut self, s_or_e: &SpreadOrExpression, span: &Span) -> Result<Type, FrameError> {
|
||||
match s_or_e {
|
||||
SpreadOrExpression::Spread(expression) => {
|
||||
// Parse the type of the spread array expression.
|
||||
let array_type = self.parse_expression(expression)?;
|
||||
|
||||
// Check that the type is an array.
|
||||
let (element_type, mut dimensions) = match array_type {
|
||||
Type::Array(element_type, dimensions) => (element_type, dimensions),
|
||||
type_ => return Err(FrameError::invalid_spread(type_, span)),
|
||||
};
|
||||
|
||||
// A spread copies the elements of an array.
|
||||
// If the array has elements of type array, we must return a new array type with proper dimensions.
|
||||
// If the array has elements of any other type, we can return the type and count directly.
|
||||
let count = dimensions.pop().unwrap();
|
||||
|
||||
let type_ = if dimensions.is_empty() {
|
||||
*element_type
|
||||
} else {
|
||||
Type::Array(element_type, dimensions)
|
||||
};
|
||||
|
||||
(type_, count)
|
||||
match array_type {
|
||||
Type::Array(element_type) => Ok(Type::Array(element_type)),
|
||||
type_ => Err(FrameError::invalid_spread(type_, span)),
|
||||
}
|
||||
}
|
||||
SpreadOrExpression::Expression(expression) => (self.parse_expression(expression)?, 1),
|
||||
})
|
||||
SpreadOrExpression::Expression(expression) => self.parse_expression(expression),
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
@ -853,8 +855,8 @@ impl Frame {
|
||||
///
|
||||
fn parse_array_access(&mut self, type_: Type, r_or_e: &RangeOrExpression, span: &Span) -> Result<Type, FrameError> {
|
||||
// Check the type is an array.
|
||||
let (element_type, _dimensions) = match type_ {
|
||||
Type::Array(type_, dimensions) => (type_, dimensions),
|
||||
let element_type = match type_ {
|
||||
Type::Array(type_) => type_,
|
||||
type_ => return Err(FrameError::array_access(&type_, span)),
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user