hyperledger / solang

Solidity Compiler for Solana and Polkadot
https://solang.readthedocs.io/
Apache License 2.0
1.25k stars 210 forks source link

Cannot push to array in a struct #1491

Open LucasSte opened 1 year ago

LucasSte commented 1 year ago

This contract:

contract Foo {
    struct My {
        bytes bb;
    }
    function bar() public pure returns (uint32) {
        My s;
        s.bb.push(2);
        return s.bb.length;
    }
}

causes this error:

thread 'main' panicked at 'not an array', src/sema/types.rs:1415:18
Shiva953 commented 1 year ago

bb declared with bytes is a dynamic byte array and it doesn't have a push method like arrays in some other programming languages. To do that, you gotta manage the length of the array manually and use memory allocation functions.

  1. Declare s as a memory variable. This would allow you to modify data(array in this case) inside of the bar function as it is declared as pure. It aligns with the function's read-only nature and preventing errors related to modifying storage in a read-only context.
  2. Initialize the bytes array s.bb using new bytes(0).
pragma solidity ^0.8.0;

contract Foo {
    struct My {
        bytes bb;
    }

    function bar() public pure returns (uint256) {
        My memory s; //declare s as a memory variable
        s.bb = new bytes(0); // Initialize the bytes array
        s.bb.push(0x02);

        return s.bb.length;
    }
}
LucasSte commented 1 year ago

Thanks @Shiva953, you are right. solc does not allow us to push to a bytes array that is not in memory. The bug, however, still exists. The compiler must not panic because we are trying to build incorrect code. It should raise an error.

Shiva953 commented 1 year ago

yeah sire, that's a solidity compiler limitation and I honestly don't have the slightest of the clues about anything related to compilers

seanyoung commented 1 year ago

Solang does support push/pop on memory arrays, even if solc does not. However, it should not panic.