Skip to content

Commit 471714f

Browse files
authored
Allow using complex type as array element type (argotorg#734)
1 parent d7df92b commit 471714f

30 files changed

Lines changed: 528 additions & 226 deletions

crates/abi/src/types.rs

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -59,16 +59,15 @@ impl AbiType {
5959
pub fn header_size(&self) -> usize {
6060
match self {
6161
Self::UInt(_) | Self::Int(_) | Self::Address | Self::Bool | Self::Function => 32,
62-
Self::Array { elem_ty, len } => elem_ty.header_size() * len,
63-
Self::Tuple(fields) => {
64-
if self.is_static() {
65-
fields
66-
.iter()
67-
.fold(0, |acc, field| field.ty.header_size() + acc)
68-
} else {
69-
32
70-
}
71-
}
62+
63+
Self::Array { elem_ty, len } if elem_ty.is_static() => elem_ty.header_size() * len,
64+
Self::Array { .. } => 32,
65+
66+
Self::Tuple(fields) if self.is_static() => fields
67+
.iter()
68+
.fold(0, |acc, field| field.ty.header_size() + acc),
69+
Self::Tuple(_) => 32,
70+
7271
Self::Bytes | Self::String => 32,
7372
}
7473
}

crates/analyzer/src/namespace/types.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ pub const U256: Base = Base::Numeric(Integer::U256);
9595
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
9696
pub struct Array {
9797
pub size: usize,
98-
pub inner: Base,
98+
pub inner: Box<Type>,
9999
}
100100

101101
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
@@ -217,7 +217,7 @@ impl GenericType {
217217
GenericType::Array => vec![
218218
GenericParam {
219219
name: "element type".into(),
220-
kind: GenericParamKind::PrimitiveType,
220+
kind: GenericParamKind::AnyType,
221221
},
222222
GenericParam {
223223
name: "size".into(),
@@ -246,7 +246,7 @@ impl GenericType {
246246
GenericType::Array => match args {
247247
[GenericArg::Type(element), GenericArg::Int(size)] => Some(Type::Array(Array {
248248
size: *size,
249-
inner: element.as_primitive()?,
249+
inner: Box::new(element.clone()),
250250
})),
251251
_ => None,
252252
},

crates/analyzer/src/operations.rs

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ fn index_array(array: Array, index: Type) -> Result<Type, IndexingError> {
2424
return Err(IndexingError::WrongIndexType);
2525
}
2626

27-
Ok(Type::Base(array.inner))
27+
Ok(array.inner.as_ref().clone())
2828
}
2929

3030
fn index_map(map: Map, index: Type) -> Result<Type, IndexingError> {
@@ -125,13 +125,16 @@ mod tests {
125125
use crate::operations;
126126
use rstest::rstest;
127127

128-
const U256_ARRAY_TYPE: Type = Type::Array(Array {
129-
inner: U256,
130-
size: 100,
131-
});
132128
const U256_TYPE: Type = Type::Base(U256);
133129
const BOOL_TYPE: Type = Type::Base(Base::Bool);
134130

131+
fn u256_array_type() -> Type {
132+
Type::Array(Array {
133+
inner: Box::new(U256.into()),
134+
size: 100,
135+
})
136+
}
137+
135138
fn u256_bool_map() -> Type {
136139
Type::Map(Map {
137140
key: U256,
@@ -143,7 +146,7 @@ mod tests {
143146
value,
144147
index,
145148
expected,
146-
case(U256_ARRAY_TYPE, U256_TYPE, U256_TYPE),
149+
case(u256_array_type(), U256_TYPE, U256_TYPE),
147150
case(u256_bool_map(), U256_TYPE, BOOL_TYPE)
148151
)]
149152
fn basic_index(value: Type, index: Type, expected: Type) {
@@ -154,9 +157,9 @@ mod tests {
154157
#[rstest(
155158
value,
156159
index,
157-
case(U256_ARRAY_TYPE, BOOL_TYPE),
160+
case(u256_array_type(), BOOL_TYPE),
158161
case(u256_bool_map(), BOOL_TYPE),
159-
case(u256_bool_map(), U256_ARRAY_TYPE)
162+
case(u256_bool_map(), u256_array_type())
160163
)]
161164
fn type_error_index(value: Type, index: Type) {
162165
let actual = operations::index(value, index).expect_err("didn't fail");

crates/analyzer/src/traversal/expressions.rs

Lines changed: 25 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ pub fn expr_list(
6363
return Ok(ExpressionAttributes {
6464
typ: Type::Array(Array {
6565
size: 0,
66-
inner: expected_type.map_or(Base::Unit, |arr| arr.inner),
66+
inner: expected_type.map_or(Box::new(Base::Unit.into()), |arr| arr.inner.clone()),
6767
}),
6868
location: Location::Memory,
6969
move_location: None,
@@ -73,9 +73,8 @@ pub fn expr_list(
7373

7474
let inner_type = if let Some(expected) = expected_type {
7575
for elt in elts {
76-
let element_attributes =
77-
assignable_expr(context, elt, Some(&Type::Base(expected.inner)))?;
78-
if element_attributes.typ != Type::Base(expected.inner) {
76+
let element_attributes = assignable_expr(context, elt, Some(&expected.inner))?;
77+
if &element_attributes.typ != expected.inner.as_ref() {
7978
context.type_error(
8079
"type mismatch",
8180
elt.span,
@@ -84,11 +83,11 @@ pub fn expr_list(
8483
);
8584
}
8685
}
87-
expected.inner
86+
expected.inner.clone()
8887
} else {
8988
let first_attr = assignable_expr(context, &elts[0], None)?;
9089
let inner = match first_attr.typ {
91-
Type::Base(base) => base,
90+
Type::Base(base) => base.into(),
9291
_ => {
9392
return Err(FatalError::new(context.error(
9493
"arrays can only hold primitive types",
@@ -119,7 +118,7 @@ pub fn expr_list(
119118
);
120119
}
121120
}
122-
inner
121+
Box::new(inner)
123122
};
124123

125124
// TODO: Right now we are only supporting Base type arrays
@@ -1011,25 +1010,23 @@ fn expr_call_builtin_function(
10111010
expect_no_label_on_arg(context, args, 0);
10121011

10131012
if let Some(arg_typ) = argument_attributes.first().map(|attr| &attr.typ) {
1014-
if !matches!(
1015-
arg_typ,
1016-
Type::Array(Array {
1017-
inner: Base::Numeric(Integer::U8),
1018-
..
1019-
})
1020-
) {
1021-
context.fancy_error(
1022-
&format!(
1023-
"`{}` can not be used as an argument to `{}`",
1024-
arg_typ,
1025-
function.as_ref(),
1026-
),
1027-
vec![Label::primary(args.span, "wrong type")],
1028-
vec![format!(
1029-
"Note: `{}` expects a byte array argument",
1030-
function.as_ref()
1031-
)],
1032-
);
1013+
match arg_typ {
1014+
Type::Array(Array { inner, .. })
1015+
if inner.as_ref() == &Type::Base(Base::Numeric(Integer::U8)) => {}
1016+
_ => {
1017+
context.fancy_error(
1018+
&format!(
1019+
"`{}` can not be used as an argument to `{}`",
1020+
arg_typ,
1021+
function.as_ref(),
1022+
),
1023+
vec![Label::primary(args.span, "wrong type")],
1024+
vec![format!(
1025+
"Note: `{}` expects a byte array argument",
1026+
function.as_ref()
1027+
)],
1028+
);
1029+
}
10331030
}
10341031
};
10351032
ExpressionAttributes::new(Type::Base(U256), Location::Value)
@@ -1509,7 +1506,7 @@ fn expr_call_builtin_value_method(
15091506
Ok((
15101507
ExpressionAttributes::new(
15111508
Type::Array(Array {
1512-
inner: Base::Numeric(Integer::U8),
1509+
inner: Box::new(Base::Numeric(Integer::U8).into()),
15131510
size: struct_.id.fields(context.db()).len() * 32,
15141511
}),
15151512
Location::Memory,
@@ -1531,7 +1528,7 @@ fn expr_call_builtin_value_method(
15311528
Ok((
15321529
ExpressionAttributes::new(
15331530
Type::Array(Array {
1534-
inner: Base::Numeric(Integer::U8),
1531+
inner: Box::new(Base::Numeric(Integer::U8).into()),
15351532
size: tuple.items.len() * 32,
15361533
}),
15371534
Location::Memory,

crates/analyzer/src/traversal/functions.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ fn for_loop(scope: &mut BlockScope, stmt: &Node<fe::FuncStmt>) -> Result<(), Fat
4747
// Make sure iter is in the function scope & it should be an array.
4848
let iter_type = expressions::assignable_expr(scope, iter, None)?.typ;
4949
let target_type = if let Type::Array(array) = iter_type {
50-
Type::Base(array.inner)
50+
array.inner
5151
} else {
5252
return Err(FatalError::new(scope.type_error(
5353
"invalid `for` loop iterator type",
@@ -57,11 +57,18 @@ fn for_loop(scope: &mut BlockScope, stmt: &Node<fe::FuncStmt>) -> Result<(), Fat
5757
)));
5858
};
5959

60-
scope.root.map_variable_type(target, target_type.clone());
60+
scope
61+
.root
62+
.map_variable_type(target, target_type.as_ref().clone());
6163

6264
let mut body_scope = scope.new_child(BlockScopeType::Loop);
6365
// add_var emits a msg on err; we can ignore the Result.
64-
let _ = body_scope.add_var(&target.kind, target_type, false, target.span);
66+
let _ = body_scope.add_var(
67+
&target.kind,
68+
target_type.as_ref().clone(),
69+
false,
70+
target.span,
71+
);
6572

6673
// Traverse the statements within the `for loop` body scope.
6774
traverse_statements(&mut body_scope, body)

crates/analyzer/tests/errors.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,6 @@ macro_rules! test_stmt {
9696
};
9797
}
9898

99-
test_stmt! { array_non_primitive, "let x: Array<(u8, u8), 10>" }
10099
test_stmt! { array_mixed_types, "let x: Array<u16, 3> = [1, address(0), \"hi\"]" }
101100
test_stmt! { array_size_mismatch, "let x: Array<u8, 3> = []\nlet y: Array<u8, 3> = [1, 2]" }
102101
test_stmt! { array_constructor_call, "u8[3]([1, 2, 3])" }

0 commit comments

Comments
 (0)