fix(ir): vector lane store resolves lane element type [F0.5]

Writing a Vector lane (`v.x = …`, `.y/.z/.w` + colour aliases) panicked
with "unresolved type reached LLVM emission". The store path had no
vector branch: a `.field_access` target on a Vector fell through to
struct-field lookup, matched nothing, left `field_ty = .unresolved`, and
built a `ptrTo(.unresolved)` that tripped the LLVM emission guard. The
read path resolved the lane fine — the two had diverged (issue-0083
two-resolver class).

Extract a shared `Lowering.vectorLaneIndex` resolver and route BOTH paths
through it. The read path (`lowerFieldAccessOnType`) delegates to it,
dropping its silent `else 0` fallback. A new vector branch in
`lowerAssignment` GEPs a typed pointer to the lane (`structGepTyped`) and
stores via `storeOrCompound` (plain + compound). `emitStructGep` now
addresses a vector base type with a `[0, lane]` GEP. A non-lane field now
reports field-not-found on both paths instead of silent-lane-0 / panic.

Regression: examples/1506-vectors-lane-store.sx (panicked pre-fix, now
reads back written values) + a vectorLaneIndex unit test. Resolves issue
0086; spec documents element assignment.
This commit is contained in:
agra
2026-06-05 01:32:35 +03:00
parent 3f279dea6b
commit a7ee179577
9 changed files with 168 additions and 4 deletions

View File

@@ -1,5 +1,35 @@
# 0086 — writing to a Vector lane (`v.x = …`) panics with "unresolved type reached LLVM emission"
> **RESOLVED** (F0.5).
>
> **Root cause.** The vector-lane STORE path had no vector branch. In
> `Lowering.lowerAssignment` (`src/ir/lower.zig`) a `.field_access` target on a
> `Vector` fell through to the struct-field lookup, where no field matched a
> lane name, so `field_ty` stayed `.unresolved`. The store then built a
> `ptrTo(.unresolved)` whose pointee reached LLVM in `emitStore`
> (`src/backend/llvm/ops.zig`) → `toLLVMTypeInfo` `.unresolved` tripwire panic.
> The READ path resolved the lane fine; the two paths had diverged (issue-0083
> two-resolver class).
>
> **Fix (per file).**
> - `src/ir/lower.zig` — extracted a shared `Lowering.vectorLaneIndex(field)`
> resolver (`.x/.y/.z/.w` + colour aliases `.r/.g/.b/.a` → lane 0..3, `null`
> otherwise). The READ path (`lowerFieldAccessOnType`) now delegates to it
> (dropping its silent `else 0` fallback), and a new vector branch in
> `lowerAssignment` uses the SAME resolver to `structGepTyped` a typed pointer
> to the lane and `storeOrCompound` with the vector element type (plain and
> compound assignment). A non-lane field now reports a field-not-found error on
> both paths instead of silently reading lane 0 / panicking.
> - `src/backend/llvm/ops.zig` — `emitStructGep` now addresses a vector
> `base_type` with a `[0, lane]` `GEP2`, yielding a pointer to the lane element
> for the scalar store.
>
> **Regression test.** `examples/1506-vectors-lane-store.sx` — `.[…]`-init and
> `= ---`-init writes, every lane of a 4-lane vector, colour aliases, and a
> compound lane assignment, reading each value back. Unit test
> `src/ir/lower.test.zig` pins the `vectorLaneIndex` contract.
## Symptom
Assigning to a component of a `Vector` local — `v.x = 1.0` (also `.y` / `.z` /
`.w`) — aborts the compiler with the internal panic: