Files
sx/issues/0117-pointer-to-array-index-unresolved-panic.md
agra 82d6b8da0e fix(0117): pointer-to-array indexing auto-derefs
A '*[N]T' receiver in an index expression reached LLVM emission with an
unresolved element type and tripped the panic sentinel — no read or
write spelling worked. ptrToArrayElem on Lowering recognises the shape;
the index READ path GEPs the pointee array through the pointer value
and loads the element; the write / compound-assign / lvalue /
addr-of-element paths and the expression typer resolve the element type
through the same helper (their GEP machinery already handled a pointer
base). Kept out of getElementType so slice paths don't half-accept a
raw pointer base.

Regression: examples/0176 (read, write, compound, element ptr + deref).
2026-06-11 12:15:45 +03:00

2.8 KiB

0117 — indexing through a pointer-to-array panics at LLVM emission

RESOLVED (2026-06-11). ptrToArrayElem on Lowering recognises the *[N]T receiver; the index READ path GEPs the pointee array through the pointer value and loads the element; the WRITE / compound-assign / lvalue / addr-of-element paths and the expression typer resolve the element type through the same helper (their GEP machinery already handled a pointer base). Postfix deref (p.*) was always the deref spelling — the issue's (*p)[2] note was a wrong-syntax red herring. Regression test: examples/0176-types-pointer-to-array-index.sx (read, write, compound, element pointer + deref).

Symptom. Indexing through a *[N]T pointer is neither lowered nor diagnosed: the index expression reaches the LLVM emitter with the .unresolved type sentinel and trips the panic tripwire.

  • Observed: panic: unresolved type reached LLVM emission (src/backend/llvm/types.zig:175, via emitIndexGet).
  • Expected: either p[2] auto-derefs the pointer-to-array (load the pointer, GEP into the array — mirroring the field-access auto-deref on struct pointers), or a clean diagnostic if indexing through *[N]T is out of spec. Never an emit-time panic.

Pre-existing — reproduces on plain locals with no module-level features involved (found while pinning @K reads for PLAN-CONST-AGG step 1; the same panic fires for @<var-decl global array> and @<array const>).

Also note: the explicit-deref spelling (*p)[2] does not parse as a deref — it lowers as unknown_expr ("unresolved 'unknown_expr'"), so there is no working spelling for reading an element through a pointer-to-array.

Reproduction

#import "modules/std.sx";

main :: () {
    k : [4]s64 = .[11, 22, 33, 44];
    p := @k;                 // *[4]s64
    print("{}\n", p[2]);     // expected 33; panics at emission today
}

Investigation prompt

emitIndexGet receives an index_get whose result type is .unresolved — the lowering of index_expr over a receiver of pointer-to-array type produces no deref. Suspected area: the index lowering in src/ir/lower/expr.zig (lowerIndexExpr or equivalent — find the index_expr arm) and its typing twin in src/ir/expr_typer.zig: both handle array / slice / many-pointer receivers but not pointer → array. The fix likely mirrors the struct-pointer auto-deref: when the receiver type is .pointer whose pointee is .array, load the pointer value and index the pointee array (element type = pointee element), in BOTH the typer and the lowering. Check the assignment-target path too (p[1] = v through a pointer-to-array).

Verification: the repro above prints 33; add a pin under examples/01xx-types-… covering read AND write-through (p[1] = 5; print k[1] → 5 for a mutable local). Suite + zig build test stay green.