Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow staticarrays to be constructed with no arguments #281

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions src/puya/awst_build/eb/arc4/static_array.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from puya.awst_build.eb._utils import constant_bool_and_error
from puya.awst_build.eb.arc4._base import _ARC4ArrayExpressionBuilder
from puya.awst_build.eb.arc4._utils import no_literal_items
from puya.awst_build.eb.factories import builder_for_instance
from puya.awst_build.eb.factories import builder_for_instance, builder_for_type
from puya.awst_build.eb.interface import InstanceBuilder, NodeBuilder, StaticSizedCollectionBuilder
from puya.awst_build.eb.uint64 import UInt64ExpressionBuilder
from puya.errors import CodeError
Expand Down Expand Up @@ -72,7 +72,16 @@ def call(
) -> InstanceBuilder:
typ = self.produces()
no_literal_items(typ, location)
n_args = expect.exactly_n_args_of_type_else_dummy(args, typ.items, location, self._size)

if self._size > 0 and len(args) == 0:
n_args: Sequence[InstanceBuilder] = [
builder_for_type(typ.items, location).call([], [], [], location)
for _ in range(self._size)
]
else:
n_args = expect.exactly_n_args_of_type_else_dummy(
args, typ.items, location, self._size
)
wtype = typ.wtype
assert isinstance(wtype, wtypes.ARC4StaticArray)
return StaticArrayExpressionBuilder(
Expand Down
51 changes: 51 additions & 0 deletions test_cases/static_arrays_no_args/contract.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import typing

from algopy import Contract, Application, Asset, Account
from algopy.arc4 import (
Address,
Byte,
DynamicArray,
StaticArray,
UInt32,
UInt8,
Struct,
String,
Bool,
)

AddressArray: typing.TypeAlias = StaticArray[Address, typing.Literal[2]]


class TestStruct(Struct):
b_val: Bool
u_val: UInt8
s_val_1: String
s_val_2: String


class TestContract(Contract):

def approval_program(self) -> bool:
assert StaticArray[Byte, typing.Literal[1]]() == StaticArray(Byte())
assert AddressArray() == AddressArray(Address(), Address())

assert StaticArray[AddressArray, typing.Literal[3]]() == StaticArray(
AddressArray(), AddressArray(), AddressArray()
)
(a, b, c) = Application(), Asset(), Account()

assert StaticArray[UInt32, typing.Literal[1]]() == StaticArray(UInt32())

assert StaticArray[DynamicArray[AddressArray], typing.Literal[1]]() == StaticArray(
DynamicArray[AddressArray]()
)
# TODO: The following should either work, or fail gracefully
# x = StaticArray[TestStruct, typing.Literal[4]]()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I presume it's possible to add a default ctor to the arc4.Structs but it maybe doesn't make much sense. Is it better to just error when attempting to construct a static array of struct without any values?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It wouldn't jive with the datalcass vibe - not unless the class had default values for all fields (which we don't support yet)

# assert StaticArray[TestContract, typing.Literal[4]]() == StaticArray(
# TestStruct(), TestStruct(), TestStruct(), TestStruct()
# )

return True

def clear_state_program(self) -> bool:
return True
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Op // Stack (out) Source code Source line

#pragma version 10

// test_cases.static_arrays_no_args.contract.TestContract.approval_program() -> uint64:
main_block@0:
int 1 // 1 True static_arrays_no_args/contract.py:48
return // return True static_arrays_no_args/contract.py:48

Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#pragma version 10

test_cases.static_arrays_no_args.contract.TestContract.approval_program:
// static_arrays_no_args/contract.py:48
// return True
int 1
return
9 changes: 9 additions & 0 deletions test_cases/static_arrays_no_args/out/TestContract.clear.mir
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Op // Stack (out) Source code Source line

#pragma version 10

// test_cases.static_arrays_no_args.contract.TestContract.clear_state_program() -> uint64:
main_block@0:
int 1 // 1 True static_arrays_no_args/contract.py:51
return // return True static_arrays_no_args/contract.py:51

7 changes: 7 additions & 0 deletions test_cases/static_arrays_no_args/out/TestContract.clear.teal
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#pragma version 10

test_cases.static_arrays_no_args.contract.TestContract.clear_state_program:
// static_arrays_no_args/contract.py:51
// return True
int 1
return
10 changes: 10 additions & 0 deletions test_cases/static_arrays_no_args/out/TestContract.destructured.ir
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
contract test_cases.static_arrays_no_args.contract.TestContract:
program approval:
subroutine test_cases.static_arrays_no_args.contract.TestContract.approval_program() -> bool:
block@0: // L28
return 1u

program clear-state:
subroutine test_cases.static_arrays_no_args.contract.TestContract.clear_state_program() -> bool:
block@0: // L50
return 1u
96 changes: 96 additions & 0 deletions test_cases/static_arrays_no_args/out/TestContract.ssa.ir
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
contract test_cases.static_arrays_no_args.contract.TestContract:
program approval:
subroutine test_cases.static_arrays_no_args.contract.TestContract.approval_program() -> bool:
block@0: // L28
let result%0#0: bytes = (concat 0x 0x00)
let array_data%0#0: bytes = (concat 0x result%0#0)
let result%1#0: bytes = (concat 0x 0x00)
let array_data%1#0: bytes = (concat 0x result%1#0)
let tmp%0#0: bool = (== array_data%0#0 array_data%1#0)
(assert tmp%0#0)
let tmp%1#0: bytes = (global ZeroAddress)
let tmp%2#0: bytes = (global ZeroAddress)
let result%2#0: bytes = (concat 0x tmp%1#0)
let result%3#0: bytes = (concat result%2#0 tmp%2#0)
let array_data%2#0: bytes = (concat 0x result%3#0)
let tmp%3#0: bytes = (global ZeroAddress)
let tmp%4#0: bytes = (global ZeroAddress)
let result%4#0: bytes = (concat 0x tmp%3#0)
let result%5#0: bytes = (concat result%4#0 tmp%4#0)
let array_data%3#0: bytes = (concat 0x result%5#0)
let tmp%5#0: bool = (== array_data%2#0 array_data%3#0)
(assert tmp%5#0)
let tmp%6#0: bytes = (global ZeroAddress)
let tmp%7#0: bytes = (global ZeroAddress)
let result%6#0: bytes = (concat 0x tmp%6#0)
let result%7#0: bytes = (concat result%6#0 tmp%7#0)
let array_data%4#0: bytes = (concat 0x result%7#0)
let tmp%8#0: bytes = (global ZeroAddress)
let tmp%9#0: bytes = (global ZeroAddress)
let result%8#0: bytes = (concat 0x tmp%8#0)
let result%9#0: bytes = (concat result%8#0 tmp%9#0)
let array_data%5#0: bytes = (concat 0x result%9#0)
let tmp%10#0: bytes = (global ZeroAddress)
let tmp%11#0: bytes = (global ZeroAddress)
let result%10#0: bytes = (concat 0x tmp%10#0)
let result%11#0: bytes = (concat result%10#0 tmp%11#0)
let array_data%6#0: bytes = (concat 0x result%11#0)
let result%12#0: bytes = (concat 0x array_data%4#0)
let result%13#0: bytes = (concat result%12#0 array_data%5#0)
let result%14#0: bytes = (concat result%13#0 array_data%6#0)
let array_data%7#0: bytes = (concat 0x result%14#0)
let tmp%12#0: bytes = (global ZeroAddress)
let tmp%13#0: bytes = (global ZeroAddress)
let result%15#0: bytes = (concat 0x tmp%12#0)
let result%16#0: bytes = (concat result%15#0 tmp%13#0)
let array_data%8#0: bytes = (concat 0x result%16#0)
let tmp%14#0: bytes = (global ZeroAddress)
let tmp%15#0: bytes = (global ZeroAddress)
let result%17#0: bytes = (concat 0x tmp%14#0)
let result%18#0: bytes = (concat result%17#0 tmp%15#0)
let array_data%9#0: bytes = (concat 0x result%18#0)
let tmp%16#0: bytes = (global ZeroAddress)
let tmp%17#0: bytes = (global ZeroAddress)
let result%19#0: bytes = (concat 0x tmp%16#0)
let result%20#0: bytes = (concat result%19#0 tmp%17#0)
let array_data%10#0: bytes = (concat 0x result%20#0)
let result%21#0: bytes = (concat 0x array_data%8#0)
let result%22#0: bytes = (concat result%21#0 array_data%9#0)
let result%23#0: bytes = (concat result%22#0 array_data%10#0)
let array_data%11#0: bytes = (concat 0x result%23#0)
let tmp%18#0: bool = (== array_data%7#0 array_data%11#0)
(assert tmp%18#0)
let tmp%19#0: bytes = (global ZeroAddress)
let a#0: uint64 = 0u
let b#0: uint64 = 0u
let c#0: bytes = tmp%19#0
let result%24#0: bytes = (concat 0x 0x00000000)
let array_data%12#0: bytes = (concat 0x result%24#0)
let result%25#0: bytes = (concat 0x 0x00000000)
let array_data%13#0: bytes = (concat 0x result%25#0)
let tmp%20#0: bool = (== array_data%12#0 array_data%13#0)
(assert tmp%20#0)
let array_data%14#0: bytes = (concat 0x0000 0x)
let as_bytes%0#0: bytes = (itob 2u)
let next_item_head%0#0: bytes = ((extract 6 2) as_bytes%0#0)
let result%26#0: bytes = (concat 0x next_item_head%0#0)
let next_item_len%0#0: uint64 = (len array_data%14#0)
let tail_offset%0#0: uint64 = (+ 2u next_item_len%0#0)
let result%27#0: bytes = (concat result%26#0 array_data%14#0)
let array_data%15#0: bytes = (concat 0x result%27#0)
let array_data%16#0: bytes = (concat 0x0000 0x)
let as_bytes%1#0: bytes = (itob 2u)
let next_item_head%1#0: bytes = ((extract 6 2) as_bytes%1#0)
let result%28#0: bytes = (concat 0x next_item_head%1#0)
let next_item_len%1#0: uint64 = (len array_data%16#0)
let tail_offset%1#0: uint64 = (+ 2u next_item_len%1#0)
let result%29#0: bytes = (concat result%28#0 array_data%16#0)
let array_data%17#0: bytes = (concat 0x result%29#0)
let tmp%21#0: bool = (== array_data%15#0 array_data%17#0)
(assert tmp%21#0)
return 1u

program clear-state:
subroutine test_cases.static_arrays_no_args.contract.TestContract.clear_state_program() -> bool:
block@0: // L50
return 1u
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
contract test_cases.static_arrays_no_args.contract.TestContract:
program approval:
subroutine test_cases.static_arrays_no_args.contract.TestContract.approval_program() -> bool:
block@0: // L28
let result%0#0: bytes = 0x00
let array_data%0#0: bytes = result%0#0
let result%1#0: bytes = 0x00
let array_data%1#0: bytes = result%1#0
let tmp%0#0: bool = (== array_data%0#0 array_data%1#0)
(assert tmp%0#0)
let tmp%1#0: bytes = (global ZeroAddress)
let tmp%2#0: bytes = (global ZeroAddress)
let result%2#0: bytes = tmp%1#0
let result%3#0: bytes = (concat result%2#0 tmp%2#0)
let array_data%2#0: bytes = result%3#0
let tmp%3#0: bytes = (global ZeroAddress)
let tmp%4#0: bytes = (global ZeroAddress)
let result%4#0: bytes = tmp%3#0
let result%5#0: bytes = (concat result%4#0 tmp%4#0)
let array_data%3#0: bytes = result%5#0
let tmp%5#0: bool = (== array_data%2#0 array_data%3#0)
(assert tmp%5#0)
let tmp%6#0: bytes = (global ZeroAddress)
let tmp%7#0: bytes = (global ZeroAddress)
let result%6#0: bytes = tmp%6#0
let result%7#0: bytes = (concat result%6#0 tmp%7#0)
let array_data%4#0: bytes = result%7#0
let tmp%8#0: bytes = (global ZeroAddress)
let tmp%9#0: bytes = (global ZeroAddress)
let result%8#0: bytes = tmp%8#0
let result%9#0: bytes = (concat result%8#0 tmp%9#0)
let array_data%5#0: bytes = result%9#0
let tmp%10#0: bytes = (global ZeroAddress)
let tmp%11#0: bytes = (global ZeroAddress)
let result%10#0: bytes = tmp%10#0
let result%11#0: bytes = (concat result%10#0 tmp%11#0)
let array_data%6#0: bytes = result%11#0
let result%12#0: bytes = array_data%4#0
let result%13#0: bytes = (concat result%12#0 array_data%5#0)
let result%14#0: bytes = (concat result%13#0 array_data%6#0)
let array_data%7#0: bytes = result%14#0
let tmp%12#0: bytes = (global ZeroAddress)
let tmp%13#0: bytes = (global ZeroAddress)
let result%15#0: bytes = tmp%12#0
let result%16#0: bytes = (concat result%15#0 tmp%13#0)
let array_data%8#0: bytes = result%16#0
let tmp%14#0: bytes = (global ZeroAddress)
let tmp%15#0: bytes = (global ZeroAddress)
let result%17#0: bytes = tmp%14#0
let result%18#0: bytes = (concat result%17#0 tmp%15#0)
let array_data%9#0: bytes = result%18#0
let tmp%16#0: bytes = (global ZeroAddress)
let tmp%17#0: bytes = (global ZeroAddress)
let result%19#0: bytes = tmp%16#0
let result%20#0: bytes = (concat result%19#0 tmp%17#0)
let array_data%10#0: bytes = result%20#0
let result%21#0: bytes = array_data%8#0
let result%22#0: bytes = (concat result%21#0 array_data%9#0)
let result%23#0: bytes = (concat result%22#0 array_data%10#0)
let array_data%11#0: bytes = result%23#0
let tmp%18#0: bool = (== array_data%7#0 array_data%11#0)
(assert tmp%18#0)
let result%24#0: bytes = 0x00000000
let array_data%12#0: bytes = result%24#0
let result%25#0: bytes = 0x00000000
let array_data%13#0: bytes = result%25#0
let tmp%20#0: bool = (== array_data%12#0 array_data%13#0)
(assert tmp%20#0)
let array_data%14#0: bytes = 0x0000
let next_item_head%0#0: bytes = 0x0002
let result%26#0: bytes = next_item_head%0#0
let next_item_len%0#0: uint64 = (len array_data%14#0)
let result%27#0: bytes = (concat result%26#0 array_data%14#0)
let array_data%15#0: bytes = result%27#0
let array_data%16#0: bytes = 0x0000
let next_item_head%1#0: bytes = 0x0002
let result%28#0: bytes = next_item_head%1#0
let next_item_len%1#0: uint64 = (len array_data%16#0)
let result%29#0: bytes = (concat result%28#0 array_data%16#0)
let array_data%17#0: bytes = result%29#0
let tmp%21#0: bool = (== array_data%15#0 array_data%17#0)
(assert tmp%21#0)
return 1u

program clear-state:
subroutine test_cases.static_arrays_no_args.contract.TestContract.clear_state_program() -> bool:
block@0: // L50
return 1u
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
contract test_cases.static_arrays_no_args.contract.TestContract:
program approval:
subroutine test_cases.static_arrays_no_args.contract.TestContract.approval_program() -> bool:
block@0: // L28
let tmp%0#0: bool = 1u
(assert tmp%0#0)
let result%3#0: bytes = AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
let result%5#0: bytes = AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
let tmp%5#0: bool = (== result%3#0 result%5#0)
(assert tmp%5#0)
let result%7#0: bytes = AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
let result%9#0: bytes = AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
let result%11#0: bytes = AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
let result%13#0: bytes = (concat result%7#0 result%9#0)
let result%14#0: bytes = (concat result%13#0 result%11#0)
let result%16#0: bytes = AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
let result%18#0: bytes = AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
let result%20#0: bytes = AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
let result%22#0: bytes = (concat result%16#0 result%18#0)
let result%23#0: bytes = (concat result%22#0 result%20#0)
let tmp%18#0: bool = (== result%14#0 result%23#0)
(assert tmp%18#0)
let tmp%20#0: bool = 1u
(assert tmp%20#0)
let result%27#0: bytes = 0x00020000
let result%29#0: bytes = 0x00020000
let tmp%21#0: bool = (== result%27#0 result%29#0)
(assert tmp%21#0)
return 1u

program clear-state:
subroutine test_cases.static_arrays_no_args.contract.TestContract.clear_state_program() -> bool:
block@0: // L50
return 1u
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
contract test_cases.static_arrays_no_args.contract.TestContract:
program approval:
subroutine test_cases.static_arrays_no_args.contract.TestContract.approval_program() -> bool:
block@0: // L28
let tmp%5#0: bool = 1u
(assert tmp%5#0)
let result%13#0: bytes = AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA===
let result%14#0: bytes = (concat result%13#0 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=)
let result%22#0: bytes = AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA===
let result%23#0: bytes = (concat result%22#0 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=)
let tmp%18#0: bool = (== result%14#0 result%23#0)
(assert tmp%18#0)
let tmp%21#0: bool = 1u
(assert tmp%21#0)
return 1u

program clear-state:
subroutine test_cases.static_arrays_no_args.contract.TestContract.clear_state_program() -> bool:
block@0: // L50
return 1u
Loading
Loading