What you did
bend main.bend -o /tmp/bend-boxing-repro
What happened
The command above compiled the original test harness; the harness and allocation probe are omitted here for brevity. repro.bend below is the reduced function to inspect, not a standalone executable.
Calling rebox with a fresh singleton containing Scalar, then fully consuming the result, leaks 16 bytes per call. The same test with Pair does not leak. Expected: neither variant accumulates unreachable allocations.
Measured in-use bytes over four iterations: Scalar 1072 → 1088 → 1104 → 1120; Pair 1056 → 1056 → 1056 → 1056. These measurements subtract allocator free-list storage, so this is not RSS growth or allocator retention.
In the generated C, the original two-word list cell is reused when boxing Pair, but neither reused nor freed when boxing Scalar. Both branches allocate a new output list cell, leaving the original 16 bytes orphaned in the Scalar case.
Likely cause: val_box/ctr_build share mutable spare-node bookkeeping across mutually exclusive branches.
The file
repro.bend
import Base
type Value is Data:
Scalar{number: U32}
Pair{left: Nat, right: Nat}
def rebox(values: List<&2, Value>) -> List<&2, Value>:
match values:
case Nil{}:
Nil{}
case value <> tail:
value <> tail
bend --version
bend 2.0.24
Obtained with bend version; bend --version reports an unknown option.
uname -sm
Linux x86_64
clang --version (the first line)
clang version 22.1.8
What you did
bend main.bend -o /tmp/bend-boxing-repro
What happened
The command above compiled the original test harness; the harness and allocation probe are omitted here for brevity. repro.bend below is the reduced function to inspect, not a standalone executable.
Calling rebox with a fresh singleton containing Scalar, then fully consuming the result, leaks 16 bytes per call. The same test with Pair does not leak. Expected: neither variant accumulates unreachable allocations.
Measured in-use bytes over four iterations: Scalar 1072 → 1088 → 1104 → 1120; Pair 1056 → 1056 → 1056 → 1056. These measurements subtract allocator free-list storage, so this is not RSS growth or allocator retention.
In the generated C, the original two-word list cell is reused when boxing Pair, but neither reused nor freed when boxing Scalar. Both branches allocate a new output list cell, leaving the original 16 bytes orphaned in the Scalar case.
Likely cause: val_box/ctr_build share mutable spare-node bookkeeping across mutually exclusive branches.
The file
repro.bend
bend --version
bend 2.0.24
Obtained with bend version; bend --version reports an unknown option.
uname -sm
Linux x86_64
clang --version (the first line)
clang version 22.1.8