Files
sx/issues/0162-comptime-run-returning-optional-aggregate.md
agra ff9e448f8c fix: optional-chain getter/field correctness from 0160 adversarial review
Five adversarial reviews of the issue-0160 fix surfaced three more bugs in the
touched optional-chain / optional-coercion code; all fixed here:

1. A COLD generic-instance getter through `?.` (`?*Vec(i64)` `.getter`, never
   called directly first) panicked with "unresolved type reached LLVM emission":
   a cold instance method is absent from resolveFuncByName, so the getter's
   return type resolved to .unresolved → a ?unresolved merge type. lowerOptionalChain
   and getterReturnTypeOnDeref now warm the monomorph (ensureGenericInstanceMethodLowered)
   before querying its return type. (The 0907 test passed only by luck — List(i64)
   is warmed by stdlib use; 0907 now also exercises a cold user generic.)

2. A real-field read through a `?*T` chain (`op?.field`, op: ?*T) reinterpreted
   the pointer bits as the field (silent garbage) — the some-branch real-field
   path didn't load through the pointer. It now derefs `?*T` before the field
   access. (Pre-existing — the else-branch predates 0160 — but it's the same
   function and a silent miscompile, so fixed here.)

3. `?[]T = array` skipped the array→slice promotion (corrupt .len/.ptr): the
   lowerVarDecl optional arm wrapped the raw array. It now coerces the value to
   the optional's child type (array→slice) before wrapping.

Regression examples 0906/0907 extended to cover all three. Distinct PRE-EXISTING
bugs the reviews surfaced in untouched subsystems are filed as issues 0161
(struct-literal vs scalar), 0162 (#run returning an optional aggregate), 0163
(untagged-union payload-binding match).
2026-06-22 18:55:41 +03:00

41 lines
1.7 KiB
Markdown

# 0162 — `#run` returning an optional aggregate fails the comptime VM reg→value bridge
## 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.