# 0163 — payload-binding match on a plain untagged `union` panics instead of diagnosing ## Symptom A `match`-style `if x == { case .variant: (v) { ... } }` with a PAYLOAD BINDING `(v)` on a value of a plain UNTAGGED `union` type panics in the LLVM backend instead of producing a diagnostic. An untagged union has no discriminant, so a case-payload binding is not a valid construct and should be rejected at typecheck. - Observed: `thread panic: unresolved type reached LLVM emission` at `src/backend/llvm/types.zig:196`, reached via `emit_llvm.zig:1289` `declareFunction` → `toLLVMType(param.ty)` (exit 134). - Expected: a clean diagnostic (e.g. "cannot bind a payload from an untagged union — use a tagged enum/union with a discriminant"). Surfaced during the issue-0160 review (blast-radius probing). NOT caused by 0160 — the panic path is union-match lowering → `declareFunction`, none of which the 0160 fix touches. Removing the `(v)` binding, or using a tagged `enum` instead, both work. ## Reproduction ```sx #import "modules/std.sx"; Shape :: union { circle: i64; rect: i64; } // plain untagged union (no discriminant) main :: () { s : Shape = .{ circle = 5 }; r := if s == { case .circle: (v) { v } case .rect: (v) { v * 2 } }; // panic print("{}\n", r); } ``` ## Investigation prompt The match/case lowering binds a case payload `(v)` whose type it resolves against the union variant — but a plain `.@"union"` (untagged) has no per-variant discriminant, so the binding's type leaks out as `.unresolved` and reaches `declareFunction`. In the match-arm lowering (grep the case/`match_arm` path in `src/ir/lower/`), reject a payload-binding case when the scrutinee type is an untagged `.@"union"` (only `.tagged_union` / `.@"enum"` payloads are bindable): emit a diagnostic and bail, before any `.unresolved` type is produced. Verify with the repro (expect a clean error, not a panic). Add a diagnostics example.