From 0e1ab38586d0f2d38aaac28c97f4c1e596eea047 Mon Sep 17 00:00:00 2001 From: Hojun-Cho Date: Thu, 21 May 2026 19:53:31 +0900 Subject: [PATCH] selfhost/cmd/wcc: stamp e.type_ for N_ARRLIT (A.6.1.7) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Port head-only of cstage cmd/wcc/check.c:1198-1211 to exprtype's new N_ARRLIT arm: - Walk e.list, skip the N_FIELD repeat marker (lib/ww/parse/ expr.ww:100-107). - First non-skipped element via recursive exprtype → elt. - Count non-skipped elements. - Empty list → mktname("i32") per cstage L1209. - Synthesize N_TARRAY{lhs=elt, rhs=INTLIT{uval=count}}, stamp tinfofornode, return. One documented divergence from cstage: the inline type_default lift (cstage L1206 — untyped_int → i32 etc) is skipped. Wwstage uniformly returns the AST-level untyped name and defers defaulting to the assignability sink; the N_INTLIT arm (check.ww:1388-1392) and alloc-value-form (check.ww:1509) follow the same shape, so defaulting here would be the outlier. No cgen consumer reads e.type_ on N_ARRLIT today (verified via grep of cgen*.ww); A.6.3 will move the default to the read site or hoist a typedefault helper — out of α scope. α scope per Drew (ref/hare/hare/ast/expr.ha:215-218 — Hare's array_literal is the uniform `{expand, values}` shape, no named/anonymous split, so head-only is the natural cadence). No hint plumbing, no unify check on mixed-type elements (cstage uses first-element-wins). Phase 1 A.6 step 7 of ~8 — closes the A.6.1 per-kind stamp series. A.6.2 next: post-checker assertion that every expression node has type_ set + fail-suite gap sweep. Verified 132/132 incl. 995_self_rebuild byte-identity. --- selfhost/cmd/w6c/main.combined.ww | 41 ++++++++++++++++++++++++++++ selfhost/cmd/wcc/check.ww | 41 ++++++++++++++++++++++++++++ selfhost/cmd/wwdump/main.combined.ww | 41 ++++++++++++++++++++++++++++ 3 files changed, 123 insertions(+) diff --git a/selfhost/cmd/w6c/main.combined.ww b/selfhost/cmd/w6c/main.combined.ww index abe37332..8ced2192 100644 --- a/selfhost/cmd/w6c/main.combined.ww +++ b/selfhost/cmd/w6c/main.combined.ww @@ -8728,6 +8728,47 @@ fn exprtype(c: *checker, e: *node, hint: *node) *node = { e.type_ = tinfofornode(c, e.lhs): *void; return e.lhs; }; + if (k == nkind.N_ARRLIT) { + // A.6.1.7 — head-only stamp of the array-lit's overall type. + // Mirror cstage cmd/wcc/check.c:1198-1211: walk elements, + // skip the `...` repeat sentinel (parse/expr.ww:101-105), + // first-element-wins for the elem type, count non-skipped + // elements, synthesize an N_TARRAY{elt, INTLIT count}. Empty + // list defaults to `[0]i32` per cstage L1209. Per-element + // stamps still fire via the post-order dispatch at L460-489 + // (N_ARRLIT is in the kind list since A.6.0); the re-walk in + // the loop below is tinfocache-idempotent (L467). + // + // Documented cstage divergence: cstage L1206 applies + // type_default to lift untyped_int → i32 etc; wwstage stamps + // the raw exprtype result, matching the alloc-value-form + // precedent at L1509. Consumers default-type via the declared + // `let` slot until A.6.3 lands. Mixed-type elements follow + // cstage first-element-wins; no unify check (future scope). + let elt: *node = nil; + let count: u64 = 0u64; + let it: *node = e.list; + for (it != nil) { + let skip: bool = false; + if (it.kind == nkind.N_FIELD) { + if (streq(it.str, "...")) { skip = true; }; + }; + if (!skip) { + let t: *node = exprtype(c, it, nil); + if (elt == nil) { elt = t; }; + count += 1u64; + }; + it = it.next; + }; + if (elt == nil) { elt = mktname(c, "i32"); }; + let arr: *node = newnode(nkind.N_TARRAY, "", 0, 0); + arr.lhs = elt; + let cn: *node = newnode(nkind.N_INTLIT, "", 0, 0); + cn.uval = count; + arr.rhs = cn; + e.type_ = tinfofornode(c, arr): *void; + return arr; + }; if (k == nkind.N_TRYPROP) { // success unwrap: the success-variant type of operand's // tagged union. diff --git a/selfhost/cmd/wcc/check.ww b/selfhost/cmd/wcc/check.ww index 16632b52..9194d9d3 100644 --- a/selfhost/cmd/wcc/check.ww +++ b/selfhost/cmd/wcc/check.ww @@ -1796,6 +1796,47 @@ fn exprtype(c: *checker, e: *node, hint: *node) *node = { e.type_ = tinfofornode(c, e.lhs): *void; return e.lhs; }; + if (k == nkind.N_ARRLIT) { + // A.6.1.7 — head-only stamp of the array-lit's overall type. + // Mirror cstage cmd/wcc/check.c:1198-1211: walk elements, + // skip the `...` repeat sentinel (parse/expr.ww:101-105), + // first-element-wins for the elem type, count non-skipped + // elements, synthesize an N_TARRAY{elt, INTLIT count}. Empty + // list defaults to `[0]i32` per cstage L1209. Per-element + // stamps still fire via the post-order dispatch at L460-489 + // (N_ARRLIT is in the kind list since A.6.0); the re-walk in + // the loop below is tinfocache-idempotent (L467). + // + // Documented cstage divergence: cstage L1206 applies + // type_default to lift untyped_int → i32 etc; wwstage stamps + // the raw exprtype result, matching the alloc-value-form + // precedent at L1509. Consumers default-type via the declared + // `let` slot until A.6.3 lands. Mixed-type elements follow + // cstage first-element-wins; no unify check (future scope). + let elt: *node = nil; + let count: u64 = 0u64; + let it: *node = e.list; + for (it != nil) { + let skip: bool = false; + if (it.kind == nkind.N_FIELD) { + if (streq(it.str, "...")) { skip = true; }; + }; + if (!skip) { + let t: *node = exprtype(c, it, nil); + if (elt == nil) { elt = t; }; + count += 1u64; + }; + it = it.next; + }; + if (elt == nil) { elt = mktname(c, "i32"); }; + let arr: *node = newnode(nkind.N_TARRAY, "", 0, 0); + arr.lhs = elt; + let cn: *node = newnode(nkind.N_INTLIT, "", 0, 0); + cn.uval = count; + arr.rhs = cn; + e.type_ = tinfofornode(c, arr): *void; + return arr; + }; if (k == nkind.N_TRYPROP) { // success unwrap: the success-variant type of operand's // tagged union. diff --git a/selfhost/cmd/wwdump/main.combined.ww b/selfhost/cmd/wwdump/main.combined.ww index 93db3948..2174c258 100644 --- a/selfhost/cmd/wwdump/main.combined.ww +++ b/selfhost/cmd/wwdump/main.combined.ww @@ -8728,6 +8728,47 @@ fn exprtype(c: *checker, e: *node, hint: *node) *node = { e.type_ = tinfofornode(c, e.lhs): *void; return e.lhs; }; + if (k == nkind.N_ARRLIT) { + // A.6.1.7 — head-only stamp of the array-lit's overall type. + // Mirror cstage cmd/wcc/check.c:1198-1211: walk elements, + // skip the `...` repeat sentinel (parse/expr.ww:101-105), + // first-element-wins for the elem type, count non-skipped + // elements, synthesize an N_TARRAY{elt, INTLIT count}. Empty + // list defaults to `[0]i32` per cstage L1209. Per-element + // stamps still fire via the post-order dispatch at L460-489 + // (N_ARRLIT is in the kind list since A.6.0); the re-walk in + // the loop below is tinfocache-idempotent (L467). + // + // Documented cstage divergence: cstage L1206 applies + // type_default to lift untyped_int → i32 etc; wwstage stamps + // the raw exprtype result, matching the alloc-value-form + // precedent at L1509. Consumers default-type via the declared + // `let` slot until A.6.3 lands. Mixed-type elements follow + // cstage first-element-wins; no unify check (future scope). + let elt: *node = nil; + let count: u64 = 0u64; + let it: *node = e.list; + for (it != nil) { + let skip: bool = false; + if (it.kind == nkind.N_FIELD) { + if (streq(it.str, "...")) { skip = true; }; + }; + if (!skip) { + let t: *node = exprtype(c, it, nil); + if (elt == nil) { elt = t; }; + count += 1u64; + }; + it = it.next; + }; + if (elt == nil) { elt = mktname(c, "i32"); }; + let arr: *node = newnode(nkind.N_TARRAY, "", 0, 0); + arr.lhs = elt; + let cn: *node = newnode(nkind.N_INTLIT, "", 0, 0); + cn.uval = count; + arr.rhs = cn; + e.type_ = tinfofornode(c, arr): *void; + return arr; + }; if (k == nkind.N_TRYPROP) { // success unwrap: the success-variant type of operand's // tagged union.