0173: resolveArrayLiteralType gained no arm for [N]T/[]T heads, so a
([2]?i64).[...] head lost its ?i64 element type and a bare null reached
LLVM as const_null(.unresolved). Route structural heads through
resolveTypeWithBindings; validate an undefined element name in the head
via UnknownTypeChecker (semantic_diagnostics.zig) instead of a silent
empty-struct stub (no-silent-fallback).
0174: positional .{...} against a TUPLE target now coerces each element
to TupleInfo.fields[i] (was neither struct nor array, so uncoerced).
0175: a positional struct literal with a bare-variable element was
misclassified as a named shorthand (parser puns .{x} -> x=x), zeroing
the fields. has_names now consults the struct definition to reclassify a
punned non-field name as positional; positional coercion uses the
lowered value's real getRefType.
Regressions: optionals/0914, types/0199, types/0200, diagnostics/1196.
Verified by 4 adversarial reviews; suite 784/0. Filed adjacent bug 0176
(protocol-typed struct field method call aborts).
4.1 KiB
0173 — (T).[ ... ] typed array-literal with a null element panics (unresolved type at LLVM emission)
RESOLVED.
resolveArrayLiteralTypehad no arm for anarray_type_expr/slice_type_exprhead, so a([2]?i64).[...]head fell toelse => .unresolved— the?i64element type was lost and a barenullelement reached LLVM asconst_null(.unresolved). Fix (src/ir/lower/expr.zig): route structural heads throughresolveTypeWithBindings(recurses into the element). To honor the no-silent-fallback rule, an UNDEFINED element name in the head is now validated byUnknownTypeChecker(src/ir/semantic_diagnostics.zig— wiredal.type_exprintowalkBodyTypes), emittingunknown type '<name>'instead of a silent empty-struct stub. Regression:examples/optionals/0914-optionals-typed-array-literal-null-element.sx+examples/diagnostics/1196-diagnostics-array-literal-head-unknown-type.sx. Verified by 4 adversarial reviews.
Symptom
An explicit-type array literal of the (T).[ elems ] form (the .[...]
array_literal AST node, NOT the .{ ... } positional struct literal) whose
element type is an optional and one of whose elements is the bare null
literal reaches LLVM emission with an .unresolved type and panics:
thread … panic: unresolved type reached LLVM emission — a type resolution
failure was not diagnosed/aborted
src/backend/llvm/types.zig:196 toLLVMTypeInfo (.unresolved arm)
src/backend/llvm/ops.zig:120 emitConstNull (instruction.ty == .unresolved)
Observed: hard panic (exit 134).
Expected: the null element lowers to a null ?i64, the literal builds a
[2]?i64, and arr[1] ?? -1 prints 7.
Reproduction
#import "modules/std.sx";
main :: () {
arr := ([2]?i64).[ null, 7 ]; // typed `.[...]` form with a null element
print("{}\n", arr[1] ?? -1); // expected: 7
}
Notes:
- The equivalent positional form works (fixed under issue 0168):
arr : [2]?i64 = .{ null, 7 };correctly prints7. - The
.[...]form works fine when no element isnull((i64).[10,20],([2]?i64).[ 1, 7 ]), and nested slices via.[...](rows : [][]i64 = .[ .[1,2], .[3,4,5] ]) also work. The panic is specific to anullelement under the typed.[...]array-literal path. - Pre-existing: reproduces on clean HEAD (commit
2ea25e84, before the 0168 fix). Independent of issue 0168.
Investigation prompt
lowerArrayLiteral (src/ir/lower/expr.zig, the .[...] array_literal
node, NOT lowerStructLiteral) resolves the literal's element type from
al.type_expr via resolveArrayLiteralType. For ([2]?i64).[ ... ] the
element type should resolve to ?i64, and each element is lowered with
target_type = elem_ty. A bare null element lowers via the null_literal
path, which produces a const_null whose type is .unresolved — the
target_type (?i64) is apparently not being consulted when lowering the bare
null element inside the .[...] form (whereas it IS in the .{ ... }
positional / scalar-assignment paths, which wrap correctly).
Likely fix area: the null_literal lowering in src/ir/lower/expr.zig (search
for .null_literal / constNull) — it must honor self.target_type (the
optional element/dest type) so null becomes const_null(?i64) rather than
const_null(.unresolved). Alternatively, the per-element coercion in
lowerArrayLiteral (around the elem_ty != .unresolved coercion added for
0168) could coerce the .unresolved-typed null to elem_ty — but the cleaner
fix is for the bare null to resolve its type from target_type at lowering
time (matching how x : ?i64 = null already works).
Per the no-silent-fallback rule: do NOT default the unresolved null to a
guessed type; resolve it from the contextual target_type, and if that is
itself unresolved, emit a diagnostic rather than letting .unresolved reach
LLVM emission.
Verify: the repro above prints 7. Also check ([3]?i64).[ null, null, 5 ]
and a struct-payload ([2]?Pt).[ null, .{x=1,y=2} ]. Add an
examples/optionals/09xx-typed-array-literal-null.sx regression.