Merge branch 'asg-asg' of github.com:AleoHQ/leo into asg-clippy

This commit is contained in:
collin 2021-01-25 15:46:37 -05:00
commit 899d237ea3
13 changed files with 148 additions and 78 deletions

View File

@ -178,6 +178,10 @@ impl ConstInt {
const_int_map!(value_negate, x, x.checked_neg()?); const_int_map!(value_negate, x, x.checked_neg()?);
const_int_op!(to_usize, Option<usize>, x, (*x).try_into().ok());
const_int_op!(to_string, String, x, (*x).to_string());
const_int_bimap!(value_add, x, y, x.checked_add(*y)?); const_int_bimap!(value_add, x, y, x.checked_add(*y)?);
const_int_bimap!(value_sub, x, y, x.checked_sub(*y)?); const_int_bimap!(value_sub, x, y, x.checked_sub(*y)?);

View File

@ -148,6 +148,23 @@ impl AsgConvertError {
Self::new_from_span(format!("failed to index into non-array '{}'", name), span) Self::new_from_span(format!("failed to index into non-array '{}'", name), span)
} }
pub fn invalid_assign_index(name: &str, num: &str, span: &Span) -> Self {
Self::new_from_span(
format!("failed to index array with invalid integer '{}'[{}]", name, num),
span,
)
}
pub fn invalid_backwards_assignment(name: &str, left: usize, right: usize, span: &Span) -> Self {
Self::new_from_span(
format!(
"failed to index array range for assignment with left > right '{}'[{}..{}]",
name, left, right
),
span,
)
}
pub fn index_into_non_tuple(name: &str, span: &Span) -> Self { pub fn index_into_non_tuple(name: &str, span: &Span) -> Self {
Self::new_from_span(format!("failed to index into non-tuple '{}'", name), span) Self::new_from_span(format!("failed to index into non-tuple '{}'", name), span)
} }
@ -186,6 +203,10 @@ impl AsgConvertError {
) )
} }
pub fn unexpected_nonconst(span: &Span) -> Self {
Self::new_from_span("expected const, found non-const value".to_string(), span)
}
pub fn unresolved_reference(name: &str, span: &Span) -> Self { pub fn unresolved_reference(name: &str, span: &Span) -> Self {
Self::new_from_span(format!("failed to resolve variable reference '{}'", name), span) Self::new_from_span(format!("failed to resolve variable reference '{}'", name), span)
} }

View File

@ -14,19 +14,9 @@
// 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::{ use leo_ast::IntegerType;
AsgConvertError,
ConstInt, use crate::{AsgConvertError, ConstValue, Expression, ExpressionNode, FromAst, Node, PartialType, Scope, Span, Type};
ConstValue,
Expression,
ExpressionNode,
FromAst,
Node,
PartialType,
Scope,
Span,
Type,
};
use std::{ use std::{
cell::RefCell, cell::RefCell,
sync::{Arc, Weak}, sync::{Arc, Weak},
@ -76,13 +66,13 @@ impl ExpressionNode for ArrayAccessExpression {
_ => return None, _ => return None,
}; };
let const_index = match self.index.const_value()? { let const_index = match self.index.const_value()? {
ConstValue::Int(ConstInt::U32(x)) => x, ConstValue::Int(x) => x.to_usize()?,
_ => return None, _ => return None,
}; };
if const_index as usize >= array.len() { if const_index >= array.len() {
return None; return None;
} }
Some(array.remove(const_index as usize)) Some(array.remove(const_index))
} }
} }
@ -115,7 +105,7 @@ impl FromAst<leo_ast::ArrayAccessExpression> for ArrayAccessExpression {
index: Arc::<Expression>::from_ast( index: Arc::<Expression>::from_ast(
scope, scope,
&*value.index, &*value.index,
Some(Type::Integer(leo_ast::IntegerType::U32).partial()), Some(PartialType::Integer(None, Some(IntegerType::U32))),
)?, )?,
}) })
} }

View File

@ -14,19 +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::{ use crate::{AsgConvertError, ConstValue, Expression, ExpressionNode, FromAst, Node, PartialType, Scope, Span, Type};
AsgConvertError,
ConstInt,
ConstValue,
Expression,
ExpressionNode,
FromAst,
Node,
PartialType,
Scope,
Span,
Type,
};
use leo_ast::IntegerType; use leo_ast::IntegerType;
use std::{ use std::{
cell::RefCell, cell::RefCell,
@ -73,20 +61,20 @@ impl ExpressionNode for ArrayRangeAccessExpression {
_ => return None, _ => return None,
}; };
let const_left = match self.left.as_ref().map(|x| x.const_value()) { let const_left = match self.left.as_ref().map(|x| x.const_value()) {
Some(Some(ConstValue::Int(ConstInt::U32(x)))) => x, Some(Some(ConstValue::Int(x))) => x.to_usize()?,
None => 0, None => 0,
_ => return None, _ => return None,
}; };
let const_right = match self.right.as_ref().map(|x| x.const_value()) { let const_right = match self.right.as_ref().map(|x| x.const_value()) {
Some(Some(ConstValue::Int(ConstInt::U32(x)))) => x, Some(Some(ConstValue::Int(x))) => x.to_usize()?,
None => array_len as u32, None => array_len,
_ => return None, _ => return None,
}; };
if const_left > const_right || const_right as usize > array_len { if const_left > const_right || const_right > array_len {
return None; return None;
} }
Some(Type::Array(element, (const_right - const_left) as usize)) Some(Type::Array(element, const_right - const_left))
} }
fn is_mut_ref(&self) -> bool { fn is_mut_ref(&self) -> bool {
@ -99,22 +87,20 @@ impl ExpressionNode for ArrayRangeAccessExpression {
_ => return None, _ => return None,
}; };
let const_left = match self.left.as_ref().map(|x| x.const_value()) { let const_left = match self.left.as_ref().map(|x| x.const_value()) {
Some(Some(ConstValue::Int(ConstInt::U32(x)))) => x, Some(Some(ConstValue::Int(x))) => x.to_usize()?,
None => 0, None => 0,
_ => return None, _ => return None,
}; };
let const_right = match self.right.as_ref().map(|x| x.const_value()) { let const_right = match self.right.as_ref().map(|x| x.const_value()) {
Some(Some(ConstValue::Int(ConstInt::U32(x)))) => x, Some(Some(ConstValue::Int(x))) => x.to_usize()?,
None => array.len() as u32, None => array.len(),
_ => return None, _ => return None,
}; };
if const_left > const_right || const_right as usize > array.len() { if const_left > const_right || const_right as usize > array.len() {
return None; return None;
} }
Some(ConstValue::Array( Some(ConstValue::Array(array.drain(const_left..const_right).collect()))
array.drain(const_left as usize..const_right as usize).collect(),
))
} }
} }
@ -147,20 +133,41 @@ impl FromAst<leo_ast::ArrayRangeAccessExpression> for ArrayRangeAccessExpression
)); ));
} }
} }
let left = value
.left
.as_deref()
.map(|left| {
Arc::<Expression>::from_ast(scope, left, Some(PartialType::Integer(None, Some(IntegerType::U32))))
})
.transpose()?;
let right = value
.right
.as_deref()
.map(|right| {
Arc::<Expression>::from_ast(scope, right, Some(PartialType::Integer(None, Some(IntegerType::U32))))
})
.transpose()?;
if let Some(left) = left.as_ref() {
if left.const_value().is_none() {
return Err(AsgConvertError::unexpected_nonconst(
&left.span().cloned().unwrap_or_default(),
));
}
}
if let Some(right) = right.as_ref() {
if right.const_value().is_none() {
return Err(AsgConvertError::unexpected_nonconst(
&right.span().cloned().unwrap_or_default(),
));
}
}
Ok(ArrayRangeAccessExpression { Ok(ArrayRangeAccessExpression {
parent: RefCell::new(None), parent: RefCell::new(None),
span: Some(value.span.clone()), span: Some(value.span.clone()),
array, array,
left: value left,
.left right,
.as_deref()
.map(|left| Arc::<Expression>::from_ast(scope, left, Some(Type::Integer(IntegerType::U32).partial())))
.transpose()?,
right: value
.right
.as_deref()
.map(|right| Arc::<Expression>::from_ast(scope, right, Some(Type::Integer(IntegerType::U32).partial())))
.transpose()?,
}) })
} }
} }

View File

@ -127,7 +127,7 @@ impl FromAst<leo_ast::BinaryExpression> for BinaryExpression {
} }
}, },
BinaryOperationClass::Numeric => match expected_type { BinaryOperationClass::Numeric => match expected_type {
Some(PartialType::Type(x @ Type::Integer(_))) => Some(x), Some(x @ PartialType::Integer(_, _)) => Some(x),
Some(x) => { Some(x) => {
return Err(AsgConvertError::unexpected_type( return Err(AsgConvertError::unexpected_type(
&x.to_string(), &x.to_string(),
@ -137,8 +137,7 @@ impl FromAst<leo_ast::BinaryExpression> for BinaryExpression {
} }
None => None, None => None,
}, },
} };
.map(Type::partial);
// left // left
let (left, right) = match Arc::<Expression>::from_ast(scope, &*value.left, expected_type.clone()) { let (left, right) = match Arc::<Expression>::from_ast(scope, &*value.left, expected_type.clone()) {
@ -172,6 +171,7 @@ impl FromAst<leo_ast::BinaryExpression> for BinaryExpression {
}; };
let left_type = left.get_type(); let left_type = left.get_type();
#[allow(clippy::unused_unit)]
match class { match class {
BinaryOperationClass::Numeric => match left_type { BinaryOperationClass::Numeric => match left_type {
Some(Type::Integer(_)) => (), Some(Type::Integer(_)) => (),

View File

@ -154,19 +154,21 @@ impl FromAst<leo_ast::ValueExpression> for Constant {
}), }),
} }
} }
Implicit(value, span) => match expected_type.map(PartialType::full).flatten() { Implicit(value, span) => match expected_type {
None => return Err(AsgConvertError::unresolved_type("unknown", span)), None => return Err(AsgConvertError::unresolved_type("unknown", span)),
Some(Type::Integer(int_type)) => Constant { Some(PartialType::Integer(Some(sub_type), _)) | Some(PartialType::Integer(None, Some(sub_type))) => {
parent: RefCell::new(None), Constant {
span: Some(span.clone()), parent: RefCell::new(None),
value: ConstValue::Int(ConstInt::parse(&int_type, value, span)?), span: Some(span.clone()),
}, value: ConstValue::Int(ConstInt::parse(&sub_type, value, span)?),
Some(Type::Field) => Constant { }
}
Some(PartialType::Type(Type::Field)) => Constant {
parent: RefCell::new(None), parent: RefCell::new(None),
span: Some(span.clone()), span: Some(span.clone()),
value: ConstValue::Field(value.parse().map_err(|_| AsgConvertError::invalid_int(&value, span))?), value: ConstValue::Field(value.parse().map_err(|_| AsgConvertError::invalid_int(&value, span))?),
}, },
Some(Type::Address) => Constant { Some(PartialType::Type(Type::Address)) => Constant {
parent: RefCell::new(None), parent: RefCell::new(None),
span: Some(span.clone()), span: Some(span.clone()),
value: ConstValue::Address(value.to_string()), value: ConstValue::Address(value.to_string()),
@ -174,8 +176,9 @@ impl FromAst<leo_ast::ValueExpression> for Constant {
Some(x) => return Err(AsgConvertError::unexpected_type(&x.to_string(), Some("unknown"), span)), Some(x) => return Err(AsgConvertError::unexpected_type(&x.to_string(), Some("unknown"), span)),
}, },
Integer(int_type, value, span) => { Integer(int_type, value, span) => {
match expected_type.map(PartialType::full).flatten() { match expected_type {
Some(Type::Integer(sub_type)) if &sub_type == int_type => (), Some(PartialType::Integer(Some(sub_type), _)) if &sub_type == int_type => (),
Some(PartialType::Integer(None, Some(_))) => (),
None => (), None => (),
Some(x) => { Some(x) => {
return Err(AsgConvertError::unexpected_type( return Err(AsgConvertError::unexpected_type(

View File

@ -97,7 +97,7 @@ impl FromAst<leo_ast::AssignStatement> for Arc<Statement> {
for access in statement.assignee.accesses.iter() { for access in statement.assignee.accesses.iter() {
target_accesses.push(match access { target_accesses.push(match access {
AstAssigneeAccess::ArrayRange(left, right) => { AstAssigneeAccess::ArrayRange(left, right) => {
let index_type = Some(Type::Integer(IntegerType::U32).into()); let index_type = Some(PartialType::Integer(None, Some(IntegerType::U32)));
let left = left let left = left
.as_ref() .as_ref()
.map( .map(
@ -127,15 +127,26 @@ impl FromAst<leo_ast::AssignStatement> for Arc<Statement> {
.unwrap_or_else(|| Some(ConstValue::Int(ConstInt::U32(len.map(|x| x as u32)?)))), .unwrap_or_else(|| Some(ConstValue::Int(ConstInt::U32(len.map(|x| x as u32)?)))),
) { ) {
let left = match left { let left = match left {
ConstValue::Int(ConstInt::U32(x)) => x, ConstValue::Int(x) => x.to_usize().ok_or_else(|| {
AsgConvertError::invalid_assign_index(&name, &x.to_string(), &statement.span)
})?,
_ => unimplemented!(), _ => unimplemented!(),
}; };
let right = match right { let right = match right {
ConstValue::Int(ConstInt::U32(x)) => x, ConstValue::Int(x) => x.to_usize().ok_or_else(|| {
AsgConvertError::invalid_assign_index(&name, &x.to_string(), &statement.span)
})?,
_ => unimplemented!(), _ => unimplemented!(),
}; };
if right > left { if right >= left {
target_type = Some(PartialType::Array(item.clone(), Some((right - left) as usize))) target_type = Some(PartialType::Array(item.clone(), Some((right - left) as usize)))
} else {
return Err(AsgConvertError::invalid_backwards_assignment(
&name,
left,
right,
&statement.span,
));
} }
} }
} }
@ -152,7 +163,7 @@ impl FromAst<leo_ast::AssignStatement> for Arc<Statement> {
AssignAccess::ArrayIndex(Arc::<Expression>::from_ast( AssignAccess::ArrayIndex(Arc::<Expression>::from_ast(
scope, scope,
index, index,
Some(Type::Integer(IntegerType::U32).into()), Some(PartialType::Integer(None, Some(IntegerType::U32))),
)?) )?)
} }
AstAssigneeAccess::Tuple(index, _) => { AstAssigneeAccess::Tuple(index, _) => {

View File

@ -14,6 +14,8 @@
// 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 leo_ast::IntegerType;
use crate::{ use crate::{
AsgConvertError, AsgConvertError,
Expression, Expression,
@ -25,7 +27,6 @@ use crate::{
Scope, Scope,
Span, Span,
Statement, Statement,
Type,
Variable, Variable,
}; };
use std::{ use std::{
@ -54,7 +55,7 @@ impl FromAst<leo_ast::IterationStatement> for Arc<Statement> {
statement: &leo_ast::IterationStatement, statement: &leo_ast::IterationStatement,
_expected_type: Option<PartialType>, _expected_type: Option<PartialType>,
) -> Result<Arc<Statement>, AsgConvertError> { ) -> Result<Arc<Statement>, AsgConvertError> {
let expected_index_type = Some(Type::Integer(leo_ast::IntegerType::U32).into()); let expected_index_type = Some(PartialType::Integer(None, Some(IntegerType::U32)));
let start = Arc::<Expression>::from_ast(scope, &statement.start, expected_index_type.clone())?; let start = Arc::<Expression>::from_ast(scope, &statement.start, expected_index_type.clone())?;
let stop = Arc::<Expression>::from_ast(scope, &statement.stop, expected_index_type)?; let stop = Arc::<Expression>::from_ast(scope, &statement.stop, expected_index_type)?;
let variable = Arc::new(RefCell::new(InnerVariable { let variable = Arc::new(RefCell::new(InnerVariable {

View File

@ -44,7 +44,8 @@ pub enum WeakType {
#[derive(Clone, PartialEq)] #[derive(Clone, PartialEq)]
pub enum PartialType { pub enum PartialType {
Type(Type), // non-array or tuple Type(Type), // non-array or tuple
Integer(Option<IntegerType>, Option<IntegerType>), // specific, context-specific
Array(Option<Box<PartialType>>, Option<usize>), Array(Option<Box<PartialType>>, Option<usize>),
Tuple(Vec<Option<PartialType>>), Tuple(Vec<Option<PartialType>>),
} }
@ -81,6 +82,7 @@ impl Into<Option<Type>> for PartialType {
fn into(self) -> Option<Type> { fn into(self) -> Option<Type> {
match self { match self {
PartialType::Type(t) => Some(t), PartialType::Type(t) => Some(t),
PartialType::Integer(sub_type, contextual_type) => Some(Type::Integer(sub_type.or(contextual_type)?)),
PartialType::Array(element, len) => Some(Type::Array(Box::new((*element?).full()?), len?)), PartialType::Array(element, len) => Some(Type::Array(Box::new((*element?).full()?), len?)),
PartialType::Tuple(sub_types) => Some(Type::Tuple( PartialType::Tuple(sub_types) => Some(Type::Tuple(
sub_types sub_types
@ -100,6 +102,9 @@ impl PartialType {
pub fn matches(&self, other: &Type) -> bool { pub fn matches(&self, other: &Type) -> bool {
match (self, other) { match (self, other) {
(PartialType::Type(t), other) => t.is_assignable_from(other), (PartialType::Type(t), other) => t.is_assignable_from(other),
(PartialType::Integer(self_sub_type, _), Type::Integer(sub_type)) => {
self_sub_type.as_ref().map(|x| x == sub_type).unwrap_or(true)
}
(PartialType::Array(element, len), Type::Array(other_element, other_len)) => { (PartialType::Array(element, len), Type::Array(other_element, other_len)) => {
if let Some(element) = element { if let Some(element) = element {
if !element.matches(&*other_element) { if !element.matches(&*other_element) {
@ -133,6 +138,7 @@ impl PartialType {
impl Into<PartialType> for Type { impl Into<PartialType> for Type {
fn into(self) -> PartialType { fn into(self) -> PartialType {
match self { match self {
Type::Integer(sub_type) => PartialType::Integer(Some(sub_type), None),
Type::Array(element, len) => PartialType::Array(Some(Box::new((*element).into())), Some(len)), Type::Array(element, len) => PartialType::Array(Some(Box::new((*element).into())), Some(len)),
Type::Tuple(sub_types) => PartialType::Tuple(sub_types.into_iter().map(Into::into).map(Some).collect()), Type::Tuple(sub_types) => PartialType::Tuple(sub_types.into_iter().map(Into::into).map(Some).collect()),
x => PartialType::Type(x), x => PartialType::Type(x),
@ -158,11 +164,11 @@ impl fmt::Display for Type {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self { match self {
Type::Address => write!(f, "address"), Type::Address => write!(f, "address"),
Type::Boolean => write!(f, "boolean"), Type::Boolean => write!(f, "bool"),
Type::Field => write!(f, "field"), Type::Field => write!(f, "field"),
Type::Group => write!(f, "group"), Type::Group => write!(f, "group"),
Type::Integer(sub_type) => sub_type.fmt(f), Type::Integer(sub_type) => sub_type.fmt(f),
Type::Array(sub_type, len) => write!(f, "{}[{}]", sub_type, len), Type::Array(sub_type, len) => write!(f, "[{}; {}]", sub_type, len),
Type::Tuple(sub_types) => { Type::Tuple(sub_types) => {
write!(f, "(")?; write!(f, "(")?;
for (i, sub_type) in sub_types.iter().enumerate() { for (i, sub_type) in sub_types.iter().enumerate() {
@ -182,13 +188,17 @@ impl fmt::Display for PartialType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self { match self {
PartialType::Type(t) => t.fmt(f), PartialType::Type(t) => t.fmt(f),
PartialType::Integer(Some(sub_type), _) => write!(f, "{}", sub_type),
PartialType::Integer(_, Some(sub_type)) => write!(f, "<{}>", sub_type),
PartialType::Integer(_, _) => write!(f, "integer"),
PartialType::Array(sub_type, len) => { PartialType::Array(sub_type, len) => {
write!(f, "[")?;
if let Some(sub_type) = sub_type { if let Some(sub_type) = sub_type {
write!(f, "{}", *sub_type)?; write!(f, "{}", *sub_type)?;
} else { } else {
write!(f, "?")?; write!(f, "?")?;
} }
write!(f, "[")?; write!(f, "; ")?;
if let Some(len) = len { if let Some(len) = len {
write!(f, "{}", len)?; write!(f, "{}", len)?;
} else { } else {

View File

@ -0,0 +1,5 @@
function main() {
let x = 0u8;
let a = [0u8; 4];
console.assert(a[x] == 0);
}

View File

@ -102,6 +102,18 @@ fn test_slice() {
load_asg(program_string).unwrap(); load_asg(program_string).unwrap();
} }
#[test]
fn test_index_u8() {
let program_string = include_str!("index_u8.leo");
load_asg(program_string).unwrap();
}
#[test]
fn test_slice_i8() {
let program_string = include_str!("slice_i8.leo");
load_asg(program_string).unwrap();
}
#[test] #[test]
fn test_slice_lower() { fn test_slice_lower() {
let program_string = include_str!("slice_lower.leo"); let program_string = include_str!("slice_lower.leo");

View File

@ -0,0 +1,6 @@
// `{from}..{to}` copies the elements of one array into another exclusively
function main(a: [u8; 3]) {
let b = [1u8; 4];
console.assert(a == b[0u8..3i8]);
}

View File

@ -22,7 +22,7 @@ fn test_basic() {
let asg = load_asg(program_string).unwrap(); let asg = load_asg(program_string).unwrap();
let reformed_ast = leo_asg::reform_ast(&asg); let reformed_ast = leo_asg::reform_ast(&asg);
println!("{}", reformed_ast); println!("{}", reformed_ast);
panic!(); // panic!();
} }
#[test] #[test]
@ -47,7 +47,7 @@ fn test_function_rename() {
let asg = load_asg(program_string).unwrap(); let asg = load_asg(program_string).unwrap();
let reformed_ast = leo_asg::reform_ast(&asg); let reformed_ast = leo_asg::reform_ast(&asg);
println!("{}", reformed_ast); println!("{}", reformed_ast);
panic!(); // panic!();
} }
#[test] #[test]
@ -84,5 +84,5 @@ fn test_imports() {
let asg = crate::load_asg_imports(program_string, &mut imports).unwrap(); let asg = crate::load_asg_imports(program_string, &mut imports).unwrap();
let reformed_ast = leo_asg::reform_ast(&asg); let reformed_ast = leo_asg::reform_ast(&asg);
println!("{}", serde_json::to_string(&reformed_ast).unwrap()); println!("{}", serde_json::to_string(&reformed_ast).unwrap());
panic!(); // panic!();
} }