do not compare array dimensions in type inference

This commit is contained in:
collin 2020-11-06 13:26:47 -08:00
parent 6f3a235c76
commit 1daf6c9831
5 changed files with 60 additions and 174 deletions

View File

@ -14,7 +14,6 @@
// You should have received a copy of the GNU General Public License // 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/>. // 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 leo_ast::{Error as FormattedError, Identifier, Span};
use std::path::Path; use std::path::Path;
@ -43,60 +42,6 @@ impl TypeError {
TypeError::Error(FormattedError::new_from_span(message, span)) 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. /// The `Self` keyword was used outside of a circuit.
/// ///

View File

@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License // 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/>. // along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{SymbolTable, TypeError, TypeVariable}; 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 serde::{Deserialize, Serialize};
use std::{ use std::{
@ -33,7 +33,7 @@ pub enum Type {
IntegerType(IntegerType), IntegerType(IntegerType),
// Data type wrappers // Data type wrappers
Array(Box<Type>, ArrayDimensions), Array(Box<Type>),
Tuple(Vec<Type>), Tuple(Vec<Type>),
// User defined types // User defined types
@ -58,10 +58,10 @@ impl Type {
UnresolvedType::Group => Type::Group, UnresolvedType::Group => Type::Group,
UnresolvedType::IntegerType(integer) => Type::IntegerType(integer), UnresolvedType::IntegerType(integer) => Type::IntegerType(integer),
UnresolvedType::Array(type_, dimensions) => { UnresolvedType::Array(type_, _) => {
let array_type = Type::new(table, *type_, span)?; let array_type = Type::new(table, *type_, span)?;
Type::Array(Box::new(array_type), dimensions) Type::Array(Box::new(array_type))
} }
UnresolvedType::Tuple(types) => { UnresolvedType::Tuple(types) => {
let tuple_types = types let tuple_types = types
@ -100,9 +100,9 @@ impl Type {
span: Span, span: Span,
) -> Result<Self, TypeError> { ) -> Result<Self, TypeError> {
Ok(match type_ { Ok(match type_ {
UnresolvedType::Array(type_, dimensions) => { UnresolvedType::Array(type_, _) => {
let array_type = Type::new_from_circuit(table, *type_, circuit_name, span)?; 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) => { UnresolvedType::Tuple(types) => {
let tuple_types = 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. /// Returns a list of signed integer types.
pub const fn signed_integer_types() -> [Type; 5] { pub const fn signed_integer_types() -> [Type; 5] {
[ [
@ -254,7 +187,7 @@ impl Type {
*self = type_.to_owned() *self = type_.to_owned()
} }
} }
Type::Array(self_type, _) => { Type::Array(self_type) => {
self_type.substitute(variable, type_); self_type.substitute(variable, type_);
} }
Type::Tuple(types) => types Type::Tuple(types) => types
@ -274,7 +207,7 @@ impl fmt::Display for Type {
Type::Group => write!(f, "group"), Type::Group => write!(f, "group"),
Type::IntegerType(integer_type) => write!(f, "{}", integer_type), 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) => { Type::Tuple(tuple) => {
let tuple_string = tuple.iter().map(|x| x.to_string()).collect::<Vec<_>>().join(", "); 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::Group, Type::Group) => true,
(Type::IntegerType(integer_type1), Type::IntegerType(integer_type2)) => integer_type1.eq(integer_type2), (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. // Get both array element types before comparison.
let array1_element = get_array_element_type(array1); let array1_element = get_array_element_type(array1);
let array2_element = get_array_element_type(array2); 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_`. /// If the given `type_` is any other type, return the `type_`.
/// ///
pub fn get_array_element_type(type_: &Type) -> &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) get_array_element_type(element_type)
} else { } else {
type_ type_

View File

@ -17,7 +17,6 @@
use crate::TypeAssertionError; use crate::TypeAssertionError;
use leo_ast::Span; use leo_ast::Span;
use leo_symbol_table::{get_array_element_type, Type, TypeVariable}; use leo_symbol_table::{get_array_element_type, Type, TypeVariable};
use std::borrow::Cow;
/// A type variable -> type pair. /// A type variable -> type pair.
pub struct TypeVariablePair(TypeVariable, Type); pub struct TypeVariablePair(TypeVariable, Type);
@ -88,9 +87,7 @@ impl TypeVariablePairs {
match (left, right) { match (left, right) {
(Type::TypeVariable(variable), type_) => Ok(self.push(variable, type_)), (Type::TypeVariable(variable), type_) => Ok(self.push(variable, type_)),
(type_, Type::TypeVariable(variable)) => Ok(self.push(variable, type_)), (type_, Type::TypeVariable(variable)) => Ok(self.push(variable, type_)),
(Type::Array(left_type, _), Type::Array(right_type, _)) => { (Type::Array(left_type), Type::Array(right_type)) => self.push_pairs_array(*left_type, *right_type, span),
self.push_pairs_array(*left_type, *right_type, span)
}
(Type::Tuple(left_types), Type::Tuple(right_types)) => { (Type::Tuple(left_types), Type::Tuple(right_types)) => {
self.push_pairs_tuple(left_types.into_iter(), right_types.into_iter(), span) self.push_pairs_tuple(left_types.into_iter(), right_types.into_iter(), span)
} }

View File

@ -112,6 +112,15 @@ impl FrameError {
Self::new_from_span(message, span) 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 `::`. /// Attempted to call non-static member using `::`.
/// ///

View File

@ -26,6 +26,7 @@ use leo_ast::{
Function, Function,
Identifier, Identifier,
IntegerType, IntegerType,
PositiveNumber,
RangeOrExpression, RangeOrExpression,
Span, Span,
SpreadOrExpression, SpreadOrExpression,
@ -372,7 +373,7 @@ impl Frame {
for access in &assignee.accesses { for access in &assignee.accesses {
let access_type = match access { let access_type = match access {
AssigneeAccess::Array(r_or_e) => self.parse_array_access(type_, r_or_e, span), 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), AssigneeAccess::Member(identifier) => self.parse_circuit_member_access(type_, identifier, span),
}?; }?;
@ -549,13 +550,18 @@ impl Frame {
// Arrays // Arrays
Expression::ArrayInline(expressions, span) => self.parse_array(expressions, span), 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) => { Expression::ArrayAccess(array_w_index, span) => {
self.parse_expression_array_access(&array_w_index.0, &array_w_index.1, span) self.parse_expression_array_access(&array_w_index.0, &array_w_index.1, span)
} }
// Tuples // Tuples
Expression::Tuple(expressions, span) => self.parse_tuple(expressions, span), 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 // Circuits
Expression::Circuit(identifier, members, span) => self.parse_circuit(identifier, members, span), Expression::Circuit(identifier, members, span) => self.parse_circuit(identifier, members, span),
@ -737,7 +743,7 @@ impl Frame {
fn parse_expression_tuple_access( fn parse_expression_tuple_access(
&mut self, &mut self,
expression: &Expression, expression: &Expression,
index: usize, index: &PositiveNumber,
span: &Span, span: &Span,
) -> Result<Type, FrameError> { ) -> Result<Type, FrameError> {
// Parse the tuple expression which could be a variable with type tuple. // 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. /// 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. // Check the type is a tuple.
let mut elements = match type_ { let mut elements = match type_ {
Type::Tuple(elements) => elements, Type::Tuple(elements) => elements,
type_ => return Err(FrameError::tuple_access(&type_, span)), 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) Ok(element_type)
} }
@ -768,12 +780,11 @@ impl Frame {
fn parse_array(&mut self, expressions: &[SpreadOrExpression], span: &Span) -> Result<Type, FrameError> { fn parse_array(&mut self, expressions: &[SpreadOrExpression], span: &Span) -> Result<Type, FrameError> {
// Store array element type. // Store array element type.
let mut element_type = None; let mut element_type = None;
let mut count = 0usize;
// Parse all array elements. // Parse all array elements.
for expression in expressions { for expression in expressions {
// Get the type and count of elements in each spread or expression. // 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. // Assert that array element types are the same.
if let Some(prev_type) = element_type { if let Some(prev_type) = element_type {
@ -782,9 +793,6 @@ impl Frame {
// Update array element type. // Update array element type.
element_type = Some(type_); element_type = Some(type_);
// Update number of array elements.
count += element_count;
} }
// Return an error for empty arrays. // Return an error for empty arrays.
@ -793,43 +801,37 @@ impl Frame {
None => return Err(FrameError::empty_array(span)), 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. /// Returns the type and count of elements in a spread or expression.
/// ///
fn parse_spread_or_expression( fn parse_spread_or_expression(&mut self, s_or_e: &SpreadOrExpression, span: &Span) -> Result<Type, FrameError> {
&mut self, match s_or_e {
s_or_e: &SpreadOrExpression,
span: &Span,
) -> Result<(Type, usize), FrameError> {
Ok(match s_or_e {
SpreadOrExpression::Spread(expression) => { SpreadOrExpression::Spread(expression) => {
// Parse the type of the spread array expression. // Parse the type of the spread array expression.
let array_type = self.parse_expression(expression)?; let array_type = self.parse_expression(expression)?;
// Check that the type is an array. // Check that the type is an array.
let (element_type, mut dimensions) = match array_type { match array_type {
Type::Array(element_type, dimensions) => (element_type, dimensions), Type::Array(element_type) => Ok(Type::Array(element_type)),
type_ => return Err(FrameError::invalid_spread(type_, span)), type_ => 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)
} }
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> { fn parse_array_access(&mut self, type_: Type, r_or_e: &RangeOrExpression, span: &Span) -> Result<Type, FrameError> {
// Check the type is an array. // Check the type is an array.
let (element_type, _dimensions) = match type_ { let element_type = match type_ {
Type::Array(type_, dimensions) => (type_, dimensions), Type::Array(type_) => type_,
type_ => return Err(FrameError::array_access(&type_, span)), type_ => return Err(FrameError::array_access(&type_, span)),
}; };