// E6a (attempt-2) regression — RECURSIVE top-level enum/union via per-decl nominal // identity. Three single-author shapes that reference a not-yet-interned name in a // `*Name` field: // * `Node` — a SELF-referential UNION (linked cells: `next: *Node`). // * `Tree` — a SELF-referential ENUM/tagged-union (`branch: *Tree`). // * `A`/`B` — a MUTUALLY-referential union pair (`A` holds `*B`, `B` holds `*A`). // // Pre-fix (eed2f99) the new per-decl register path built each enum/union body // through the STATELESS `type_bridge` BEFORE a matching nominal slot existed, so a // `*Name` field forward-created a STRUCT stub under `Name`; `internNamedTypeDecl` // then refreshed that struct stub as an enum/union and tripped the kind-stability // assert in `types.zig` `updatePreservingKey` — a hard panic (the corpus had no // recursive enum/union, so the gate missed it). The fix adopts the forward struct // stub IN PLACE (re-key to the real enum/union kind), mirroring how a self-ref // struct adopts its own forward stub — so `*Node`/`*Tree`/`*B`/`*A` resolve to the // genuine 8-byte-pointer nominal types and the recursive walks read through. #import "modules/std.sx"; Node :: union { next: *Node; value: s32; } Tree :: enum { leaf: s32; branch: *Tree; } A :: union { b: *B; tag: s32; } B :: union { a: *A; val: s32; } main :: () -> s32 { // Self-ref union: two-hop walk to the tail cell's value. n2 : Node = ---; n2.value = 7; n1 : Node = ---; n1.next = @n2; n0 : Node = ---; n0.next = @n1; // Self-ref enum: a branch whose payload pointer derefs to a leaf. leaf_node : Tree = .leaf(42); root : Tree = .branch(@leaf_node); // Mutual-ref pair: reach B's value through A's `*B`. bv : B = ---; bv.val = 99; av : A = ---; av.b = @bv; print("union={} enum={} mutual={}\n", n0.next.*.next.*.value, root.branch.*.leaf, av.b.*.val); 0 }