Add an .optional arm to regToValue in comptime_vm.zig: read the
has_value flag at offset sizeof(child), bridge the payload recursively
into a { payload, i1=true } aggregate when set, yield .null_val (zero
{T,i1}) when clear or the bare null sentinel. Matching serialize arm in
serializeAggregateValue (emit_llvm.zig). Pointer/?Closure/?Protocol-child
optionals and array-payload aggregates bail loudly, not silently.
Regression: examples/comptime/0643-comptime-run-optional-aggregate.sx
(present ?T, present ?i64, null ?i64). Verified by 3 adversarial reviews.
53 lines
2.6 KiB
Markdown
53 lines
2.6 KiB
Markdown
# 0162 — `#run` returning an optional aggregate fails the comptime VM reg→value bridge
|
|
|
|
> **RESOLVED.** Root cause: the comptime VM's `regToValue` bridge
|
|
> (`src/ir/comptime_vm.zig`) had no `.optional` arm, so any OPTIONAL-typed
|
|
> `#run` result hit the `"aggregate shape not bridged yet"` bail. Fix: added an
|
|
> `.optional` arm that reads the has_value flag (at offset `sizeof(child)`),
|
|
> bridges the payload recursively into a `{ payload, i1=true }` aggregate when
|
|
> set, and yields `.null_val` (→ zero `{T, i1}`) when clear or the bare null
|
|
> sentinel; plus a matching serialize arm in `serializeAggregateValue`
|
|
> (`src/ir/emit_llvm.zig`). Pointer/`?Closure`/`?Protocol`-child optionals and
|
|
> array-payload aggregates bail loudly (out of scope, not silent). Regression
|
|
> test: `examples/comptime/0643-comptime-run-optional-aggregate.sx` (present
|
|
> `?T`, present `?i64`, null `?i64`). Verified by 3 adversarial reviews.
|
|
|
|
## Symptom
|
|
|
|
A `#run` (or comptime const init) whose function returns an OPTIONAL value
|
|
(`?T`, `?i64`, any optional) fails comptime evaluation with:
|
|
|
|
`error: comptime init of 'X' failed: reg→value: aggregate shape not bridged yet`
|
|
|
|
A non-optional return of the same type works. This is a pre-existing limitation
|
|
in the comptime VM's register→value bridge for optional-typed results; it is
|
|
orthogonal to issue 0160 (it reproduces for a value-init optional with no struct
|
|
literal anywhere, and for a scalar optional `?i64`).
|
|
|
|
## Reproduction
|
|
|
|
```sx
|
|
#import "modules/std.sx";
|
|
T :: struct { a: i64 = 0; }
|
|
mk :: () -> ?T { t : T = .{ a = 7 }; return t; }
|
|
mk2 :: () -> ?i64 { return 5; }
|
|
|
|
X :: #run mk(); // error: reg→value: aggregate shape not bridged yet
|
|
Y :: #run mk2(); // same class of failure
|
|
main :: () { print("ok\n"); }
|
|
```
|
|
Baseline that WORKS: `Z :: #run (() -> T { return .{ a = 7 }; })();` (non-optional).
|
|
|
|
## Investigation prompt
|
|
|
|
`src/ir/comptime_vm.zig` — the reg→value bridge (search "aggregate shape not
|
|
bridged" / `regToValue`) handles scalars/structs/slices but bails on an
|
|
OPTIONAL-typed result. An optional is `{payload, has_value}` (or a pointer for
|
|
`?*T` / a sentinel for `?Closure`); the bridge needs to read the has_value flag
|
|
and, when set, bridge the payload as its child type (recursively), producing a
|
|
`Value` optional — and a null optional when clear. Add the `.optional` arm to
|
|
the reg→value bridge (mirror the value→reg direction, which already builds
|
|
optionals — see `makeStringList`/`writeField` optional handling). Verify with
|
|
the repro (expect `X`/`Y` to evaluate, `main` prints ok). Add a
|
|
`examples/comptime/06xx-...` regression.
|