allow non-u32 in various const places

This commit is contained in:
Protryon 2021-01-25 10:26:13 -08:00
parent 958777f633
commit 2bd3a194fb
12 changed files with 106 additions and 67 deletions

View File

@ -178,6 +178,10 @@ impl ConstInt {
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_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)
}
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 {
Self::new_from_span(format!("failed to index into non-tuple '{}'", name), span)
}

View File

@ -14,19 +14,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/>.
use crate::{
AsgConvertError,
ConstInt,
ConstValue,
Expression,
ExpressionNode,
FromAst,
Node,
PartialType,
Scope,
Span,
Type,
};
use leo_ast::IntegerType;
use crate::{AsgConvertError, ConstValue, Expression, ExpressionNode, FromAst, Node, PartialType, Scope, Span, Type};
use std::{
cell::RefCell,
sync::{Arc, Weak},
@ -76,13 +66,13 @@ impl ExpressionNode for ArrayAccessExpression {
_ => return None,
};
let const_index = match self.index.const_value()? {
ConstValue::Int(ConstInt::U32(x)) => x,
ConstValue::Int(x) => x.to_usize()?,
_ => return None,
};
if const_index as usize >= array.len() {
if const_index >= array.len() {
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(
scope,
&*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
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{
AsgConvertError,
ConstInt,
ConstValue,
Expression,
ExpressionNode,
FromAst,
Node,
PartialType,
Scope,
Span,
Type,
};
use crate::{AsgConvertError, ConstValue, Expression, ExpressionNode, FromAst, Node, PartialType, Scope, Span, Type};
use leo_ast::IntegerType;
use std::{
cell::RefCell,
@ -73,20 +61,20 @@ impl ExpressionNode for ArrayRangeAccessExpression {
_ => return None,
};
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,
_ => return None,
};
let const_right = match self.right.as_ref().map(|x| x.const_value()) {
Some(Some(ConstValue::Int(ConstInt::U32(x)))) => x,
None => array_len as u32,
Some(Some(ConstValue::Int(x))) => x.to_usize()?,
None => array_len,
_ => return None,
};
if const_left > const_right || const_right as usize > array_len {
if const_left > const_right || const_right > array_len {
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 {
@ -99,22 +87,20 @@ impl ExpressionNode for ArrayRangeAccessExpression {
_ => return None,
};
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,
_ => return None,
};
let const_right = match self.right.as_ref().map(|x| x.const_value()) {
Some(Some(ConstValue::Int(ConstInt::U32(x)))) => x,
None => array.len() as u32,
Some(Some(ConstValue::Int(x))) => x.to_usize()?,
None => array.len(),
_ => return None,
};
if const_left > const_right || const_right as usize > array.len() {
return None;
}
Some(ConstValue::Array(
array.drain(const_left as usize..const_right as usize).collect(),
))
Some(ConstValue::Array(array.drain(const_left..const_right).collect()))
}
}
@ -154,12 +140,16 @@ impl FromAst<leo_ast::ArrayRangeAccessExpression> for ArrayRangeAccessExpression
left: value
.left
.as_deref()
.map(|left| Arc::<Expression>::from_ast(scope, left, Some(Type::Integer(IntegerType::U32).partial())))
.map(|left| {
Arc::<Expression>::from_ast(scope, left, Some(PartialType::Integer(None, Some(IntegerType::U32))))
})
.transpose()?,
right: value
.right
.as_deref()
.map(|right| Arc::<Expression>::from_ast(scope, right, Some(Type::Integer(IntegerType::U32).partial())))
.map(|right| {
Arc::<Expression>::from_ast(scope, right, Some(PartialType::Integer(None, Some(IntegerType::U32))))
})
.transpose()?,
})
}

View File

@ -127,7 +127,7 @@ impl FromAst<leo_ast::BinaryExpression> for BinaryExpression {
}
},
BinaryOperationClass::Numeric => match expected_type {
Some(PartialType::Type(x @ Type::Integer(_))) => Some(x),
Some(x @ PartialType::Integer(_, _)) => Some(x),
Some(x) => {
return Err(AsgConvertError::unexpected_type(
&x.to_string(),
@ -137,8 +137,7 @@ impl FromAst<leo_ast::BinaryExpression> for BinaryExpression {
}
None => None,
},
}
.map(Type::partial);
};
// left
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();
#[allow(clippy::unused_unit)]
match class {
BinaryOperationClass::Numeric => match left_type {
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)),
Some(Type::Integer(int_type)) => Constant {
parent: RefCell::new(None),
span: Some(span.clone()),
value: ConstValue::Int(ConstInt::parse(&int_type, value, span)?),
},
Some(Type::Field) => Constant {
Some(PartialType::Integer(Some(sub_type), _)) | Some(PartialType::Integer(None, Some(sub_type))) => {
Constant {
parent: RefCell::new(None),
span: Some(span.clone()),
value: ConstValue::Int(ConstInt::parse(&sub_type, value, span)?),
}
}
Some(PartialType::Type(Type::Field)) => Constant {
parent: RefCell::new(None),
span: Some(span.clone()),
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),
span: Some(span.clone()),
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)),
},
Integer(int_type, value, span) => {
match expected_type.map(PartialType::full).flatten() {
Some(Type::Integer(sub_type)) if &sub_type == int_type => (),
match expected_type {
Some(PartialType::Integer(Some(sub_type), _)) if &sub_type == int_type => (),
Some(PartialType::Integer(None, Some(_))) => (),
None => (),
Some(x) => {
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() {
target_accesses.push(match access {
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
.as_ref()
.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)?)))),
) {
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!(),
};
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!(),
};
if right > left {
if right >= left {
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(
scope,
index,
Some(Type::Integer(IntegerType::U32).into()),
Some(PartialType::Integer(None, Some(IntegerType::U32))),
)?)
}
AstAssigneeAccess::Tuple(index, _) => {

View File

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

View File

@ -44,7 +44,8 @@ pub enum WeakType {
#[derive(Clone, PartialEq)]
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>),
Tuple(Vec<Option<PartialType>>),
}
@ -81,6 +82,7 @@ impl Into<Option<Type>> for PartialType {
fn into(self) -> Option<Type> {
match self {
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::Tuple(sub_types) => Some(Type::Tuple(
sub_types
@ -100,6 +102,11 @@ impl PartialType {
pub fn matches(&self, other: &Type) -> bool {
match (self, other) {
(PartialType::Type(t), other) => t.is_assignable_from(other),
(PartialType::Integer(self_sub_type, self_contextual_type), Type::Integer(sub_type)) => self_sub_type
.as_ref()
.or_else(|| self_contextual_type.as_ref())
.map(|x| x == sub_type)
.unwrap_or(true),
(PartialType::Array(element, len), Type::Array(other_element, other_len)) => {
if let Some(element) = element {
if !element.matches(&*other_element) {
@ -133,6 +140,7 @@ impl PartialType {
impl Into<PartialType> for Type {
fn into(self) -> PartialType {
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::Tuple(sub_types) => PartialType::Tuple(sub_types.into_iter().map(Into::into).map(Some).collect()),
x => PartialType::Type(x),
@ -182,6 +190,9 @@ impl fmt::Display for PartialType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
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) => {
if let Some(sub_type) = sub_type {
write!(f, "{}", *sub_type)?;

View File

@ -102,6 +102,12 @@ fn test_slice() {
load_asg(program_string).unwrap();
}
#[test]
fn test_slice_i8() {
let program_string = include_str!("slice_i8.leo");
load_asg(program_string).unwrap();
}
#[test]
fn test_slice_lower() {
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 reformed_ast = leo_asg::reform_ast(&asg);
println!("{}", reformed_ast);
panic!();
// panic!();
}
#[test]
@ -47,7 +47,7 @@ fn test_function_rename() {
let asg = load_asg(program_string).unwrap();
let reformed_ast = leo_asg::reform_ast(&asg);
println!("{}", reformed_ast);
panic!();
// panic!();
}
#[test]
@ -84,5 +84,5 @@ fn test_imports() {
let asg = crate::load_asg_imports(program_string, &mut imports).unwrap();
let reformed_ast = leo_asg::reform_ast(&asg);
println!("{}", serde_json::to_string(&reformed_ast).unwrap());
panic!();
// panic!();
}