Skip to content

int[] + int + int[] compiles but is lowered as byte concatenation and fails at runtime #56

@michaelsutton

Description

@michaelsutton

int[] + int + int[] currently compiles, but the generated script does not preserve int[] element boundaries. At runtime, the middle int is coerced to a single byte and concatenated into the serialized int[] blob, so later int[] indexing reads the wrong 8-byte chunks.

Minimal repro

contract Arrays() {
    entrypoint function main() {
        int[] left = [1, 2];
        int middle = 3;
        int[] right = [4, 5];
        int[5] mixed = left + middle + right;

        require(mixed[0] == 1);
        require(mixed[1] == 2);
        require(mixed[2] == 3); // fails here
        require(mixed[3] == 4);
        require(mixed[4] == 5);
    }
}

Observed behavior
The contract compiles, but execution fails on require(mixed[2] == 3).

Expected behavior
One of these should happen:

  1. int[] + int + int[] is supported and lowers by serializing the scalar int as an 8-byte int element before concatenation.
  2. The compiler rejects this expression as unsupported/type-invalid.

Root cause
BinaryOp::Add currently switches to concat mode whenever either side is considered “bytes-like”. int[] is treated as bytes-like because is_bytes_type() falls back to is_array_type(type_name). In concat mode, non-bytes operands are coerced with OP_NUM2BIN(1), so the scalar int is inserted as a 1-byte payload instead of an 8-byte int element.

This means:

  • left + middle becomes byte concat
  • middle is encoded as 1 byte
  • later int[] indexing still assumes 8-byte element boundaries

Notes

  • int[] + int[] works.
  • The issue is specifically with mixing int[] concatenation and scalar int.
  • byte[] + byte currently works, but for type-system consistency it may also be better to disallow mixing array and scalar operands unless the scalar is explicitly cast to the array element encoding (byte[1], byte[8], etc.). That would make concat semantics uniform across byte[] and int[] instead of relying on implicit scalar coercions for some element types but not others.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions