From 2bd3a194fb5448c9918acc2baf8c57a004e307ec Mon Sep 17 00:00:00 2001 From: Protryon Date: Mon, 25 Jan 2021 10:26:13 -0800 Subject: [PATCH 1/4] allow non-u32 in various const places --- asg/src/const_value.rs | 4 +++ asg/src/error/mod.rs | 17 ++++++++++ asg/src/expression/array_access.rs | 24 ++++---------- asg/src/expression/array_range_access.rs | 42 +++++++++--------------- asg/src/expression/binary.rs | 6 ++-- asg/src/expression/constant.rs | 23 +++++++------ asg/src/statement/assign.rs | 21 +++++++++--- asg/src/statement/iteration.rs | 5 +-- asg/src/type_.rs | 13 +++++++- asg/tests/pass/array/mod.rs | 6 ++++ asg/tests/pass/array/slice_i8.leo | 6 ++++ asg/tests/pass/form_ast.rs | 6 ++-- 12 files changed, 106 insertions(+), 67 deletions(-) create mode 100644 asg/tests/pass/array/slice_i8.leo diff --git a/asg/src/const_value.rs b/asg/src/const_value.rs index c1cfc5e6f9..2bef75f218 100644 --- a/asg/src/const_value.rs +++ b/asg/src/const_value.rs @@ -178,6 +178,10 @@ impl ConstInt { const_int_map!(value_negate, x, x.checked_neg()?); + const_int_op!(to_usize, Option, 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)?); diff --git a/asg/src/error/mod.rs b/asg/src/error/mod.rs index f08e379569..ae488fb942 100644 --- a/asg/src/error/mod.rs +++ b/asg/src/error/mod.rs @@ -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) } diff --git a/asg/src/expression/array_access.rs b/asg/src/expression/array_access.rs index 305e80f006..80fa19c2d1 100644 --- a/asg/src/expression/array_access.rs +++ b/asg/src/expression/array_access.rs @@ -14,19 +14,9 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -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 for ArrayAccessExpression { index: Arc::::from_ast( scope, &*value.index, - Some(Type::Integer(leo_ast::IntegerType::U32).partial()), + Some(PartialType::Integer(None, Some(IntegerType::U32))), )?, }) } diff --git a/asg/src/expression/array_range_access.rs b/asg/src/expression/array_range_access.rs index 80716ecf8f..648bd18eaf 100644 --- a/asg/src/expression/array_range_access.rs +++ b/asg/src/expression/array_range_access.rs @@ -14,19 +14,7 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -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 for ArrayRangeAccessExpression left: value .left .as_deref() - .map(|left| Arc::::from_ast(scope, left, Some(Type::Integer(IntegerType::U32).partial()))) + .map(|left| { + Arc::::from_ast(scope, left, Some(PartialType::Integer(None, Some(IntegerType::U32)))) + }) .transpose()?, right: value .right .as_deref() - .map(|right| Arc::::from_ast(scope, right, Some(Type::Integer(IntegerType::U32).partial()))) + .map(|right| { + Arc::::from_ast(scope, right, Some(PartialType::Integer(None, Some(IntegerType::U32)))) + }) .transpose()?, }) } diff --git a/asg/src/expression/binary.rs b/asg/src/expression/binary.rs index f3cb8eb112..21637b121a 100644 --- a/asg/src/expression/binary.rs +++ b/asg/src/expression/binary.rs @@ -127,7 +127,7 @@ impl FromAst 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 for BinaryExpression { } None => None, }, - } - .map(Type::partial); + }; // left let (left, right) = match Arc::::from_ast(scope, &*value.left, expected_type.clone()) { @@ -172,6 +171,7 @@ impl FromAst for BinaryExpression { }; let left_type = left.get_type(); + #[allow(clippy::unused_unit)] match class { BinaryOperationClass::Numeric => match left_type { Some(Type::Integer(_)) => (), diff --git a/asg/src/expression/constant.rs b/asg/src/expression/constant.rs index 28336cd11c..fb7c937097 100644 --- a/asg/src/expression/constant.rs +++ b/asg/src/expression/constant.rs @@ -154,19 +154,21 @@ impl FromAst 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 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( diff --git a/asg/src/statement/assign.rs b/asg/src/statement/assign.rs index 91eaf2919e..7a18f45ff9 100644 --- a/asg/src/statement/assign.rs +++ b/asg/src/statement/assign.rs @@ -97,7 +97,7 @@ impl FromAst for Arc { 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 for Arc { .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 for Arc { AssignAccess::ArrayIndex(Arc::::from_ast( scope, index, - Some(Type::Integer(IntegerType::U32).into()), + Some(PartialType::Integer(None, Some(IntegerType::U32))), )?) } AstAssigneeAccess::Tuple(index, _) => { diff --git a/asg/src/statement/iteration.rs b/asg/src/statement/iteration.rs index 7ad1e155a2..f41c4a7e82 100644 --- a/asg/src/statement/iteration.rs +++ b/asg/src/statement/iteration.rs @@ -14,6 +14,8 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . +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 for Arc { statement: &leo_ast::IterationStatement, _expected_type: Option, ) -> Result, 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::::from_ast(scope, &statement.start, expected_index_type.clone())?; let stop = Arc::::from_ast(scope, &statement.stop, expected_index_type)?; let variable = Arc::new(RefCell::new(InnerVariable { diff --git a/asg/src/type_.rs b/asg/src/type_.rs index c18184f3ba..058613d92e 100644 --- a/asg/src/type_.rs +++ b/asg/src/type_.rs @@ -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, Option), // specific, context-specific Array(Option>, Option), Tuple(Vec>), } @@ -81,6 +82,7 @@ impl Into> for PartialType { fn into(self) -> Option { 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 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)?; diff --git a/asg/tests/pass/array/mod.rs b/asg/tests/pass/array/mod.rs index 4087723ae5..d8778641aa 100644 --- a/asg/tests/pass/array/mod.rs +++ b/asg/tests/pass/array/mod.rs @@ -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"); diff --git a/asg/tests/pass/array/slice_i8.leo b/asg/tests/pass/array/slice_i8.leo new file mode 100644 index 0000000000..bc3d884cc6 --- /dev/null +++ b/asg/tests/pass/array/slice_i8.leo @@ -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]); +} diff --git a/asg/tests/pass/form_ast.rs b/asg/tests/pass/form_ast.rs index 354c8cfbff..58f00119fb 100644 --- a/asg/tests/pass/form_ast.rs +++ b/asg/tests/pass/form_ast.rs @@ -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!(); } From e4f899782abf7819c8b80f06e9806915fc89ac71 Mon Sep 17 00:00:00 2001 From: Protryon Date: Mon, 25 Jan 2021 10:38:22 -0800 Subject: [PATCH 2/4] reformat type display --- asg/src/type_.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/asg/src/type_.rs b/asg/src/type_.rs index 058613d92e..50f142fa6e 100644 --- a/asg/src/type_.rs +++ b/asg/src/type_.rs @@ -170,7 +170,7 @@ impl fmt::Display for Type { Type::Field => write!(f, "field"), Type::Group => write!(f, "group"), 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) => { write!(f, "(")?; for (i, sub_type) in sub_types.iter().enumerate() { @@ -194,12 +194,13 @@ impl fmt::Display for PartialType { PartialType::Integer(_, Some(sub_type)) => write!(f, "<{}>", sub_type), PartialType::Integer(_, _) => write!(f, "integer"), PartialType::Array(sub_type, len) => { + write!(f, "[")?; if let Some(sub_type) = sub_type { write!(f, "{}", *sub_type)?; } else { write!(f, "?")?; } - write!(f, "[")?; + write!(f, "; ")?; if let Some(len) = len { write!(f, "{}", len)?; } else { From 786afeecdecab0fc5af96f587f4063d392d4c96e Mon Sep 17 00:00:00 2001 From: Protryon Date: Mon, 25 Jan 2021 10:40:19 -0800 Subject: [PATCH 3/4] boolean -> bool --- asg/src/type_.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/asg/src/type_.rs b/asg/src/type_.rs index 50f142fa6e..3f136386d6 100644 --- a/asg/src/type_.rs +++ b/asg/src/type_.rs @@ -166,7 +166,7 @@ impl fmt::Display for Type { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Type::Address => write!(f, "address"), - Type::Boolean => write!(f, "boolean"), + Type::Boolean => write!(f, "bool"), Type::Field => write!(f, "field"), Type::Group => write!(f, "group"), Type::Integer(sub_type) => sub_type.fmt(f), From 7c216bd07d5b6ae23cd577d23476c6bc797ac8a6 Mon Sep 17 00:00:00 2001 From: Protryon Date: Mon, 25 Jan 2021 11:01:28 -0800 Subject: [PATCH 4/4] fix integer contextual inference --- asg/src/error/mod.rs | 4 +++ asg/src/expression/array_range_access.rs | 45 ++++++++++++++++-------- asg/src/type_.rs | 8 ++--- asg/tests/pass/array/index_u8.leo | 5 +++ asg/tests/pass/array/mod.rs | 6 ++++ 5 files changed, 49 insertions(+), 19 deletions(-) create mode 100644 asg/tests/pass/array/index_u8.leo diff --git a/asg/src/error/mod.rs b/asg/src/error/mod.rs index ae488fb942..e459e52b02 100644 --- a/asg/src/error/mod.rs +++ b/asg/src/error/mod.rs @@ -203,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 { Self::new_from_span(format!("failed to resolve variable reference '{}'", name), span) } diff --git a/asg/src/expression/array_range_access.rs b/asg/src/expression/array_range_access.rs index 648bd18eaf..8bd5c80f2d 100644 --- a/asg/src/expression/array_range_access.rs +++ b/asg/src/expression/array_range_access.rs @@ -133,24 +133,41 @@ impl FromAst for ArrayRangeAccessExpression )); } } + let left = value + .left + .as_deref() + .map(|left| { + Arc::::from_ast(scope, left, Some(PartialType::Integer(None, Some(IntegerType::U32)))) + }) + .transpose()?; + let right = value + .right + .as_deref() + .map(|right| { + Arc::::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 { parent: RefCell::new(None), span: Some(value.span.clone()), array, - left: value - .left - .as_deref() - .map(|left| { - Arc::::from_ast(scope, left, Some(PartialType::Integer(None, Some(IntegerType::U32)))) - }) - .transpose()?, - right: value - .right - .as_deref() - .map(|right| { - Arc::::from_ast(scope, right, Some(PartialType::Integer(None, Some(IntegerType::U32)))) - }) - .transpose()?, + left, + right, }) } } diff --git a/asg/src/type_.rs b/asg/src/type_.rs index 3f136386d6..fa86c6cfaf 100644 --- a/asg/src/type_.rs +++ b/asg/src/type_.rs @@ -102,11 +102,9 @@ 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::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)) => { if let Some(element) = element { if !element.matches(&*other_element) { diff --git a/asg/tests/pass/array/index_u8.leo b/asg/tests/pass/array/index_u8.leo new file mode 100644 index 0000000000..7ad1c6a9ea --- /dev/null +++ b/asg/tests/pass/array/index_u8.leo @@ -0,0 +1,5 @@ +function main() { + let x = 0u8; + let a = [0u8; 4]; + console.assert(a[x] == 0); +} diff --git a/asg/tests/pass/array/mod.rs b/asg/tests/pass/array/mod.rs index d8778641aa..563d4bad61 100644 --- a/asg/tests/pass/array/mod.rs +++ b/asg/tests/pass/array/mod.rs @@ -102,6 +102,12 @@ fn test_slice() { 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");