From aa73e73013dd96c6359ff898230c8771625d6927 Mon Sep 17 00:00:00 2001 From: Hojun-Cho Date: Thu, 21 May 2026 19:08:02 +0900 Subject: [PATCH] selfhost/cmd/wcc: stamp N_DOT struct/pseudo/tuple in exprtype (A.6.1.5b) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Port cstage cmd/wcc/check.c:833-866 stamp cases to exprtype's N_DOT arm. Three sub-cases append to the A.6.1.5a basetn-walk block, all pure type_ annotations — none mutate e.kind: - Pseudo-fields .len / .cap / .ptr on slice / str / array (cstage L833-842). `len` and `cap` stamp i32; `ptr` synthesises an N_TPTR over the element (u8 for str, bu.lhs else). - Struct field walk on N_TSTRUCT (cstage L843-849) — match N_TFIELD by name, return f.lhs and stamp. - Tuple positional access `t.0`, `t.1`, … on N_TTUPLE (cstage L850-866). fldnumidx (cgenutil SSoT for decimal-only parsing) yields the index; walk bu.list .next idx times. Two divergences from cstage, documented inline: - Wwstage carries str as N_TNAME("str") (no dedicated N_TSTR); the pseudo-field guard tests the trio shape directly. - Wwstage falls through to nil on struct/tuple miss instead of erroring (lenient policy per scruttype L656). Cumulative N_DOT arm now ~162 LOC, under Rob's 250-LOC tripwire. No new helpers; fldnumidx reused. #56 mod.fn() parser-rep stays parked. Phase 1 A.6 step 5b of ~8 — closes Hare's access_field surface (ref/hare/hare/ast/expr.ha:7-38). Cgenutil's paired walker still derives the same shapes; A.6.3 collapses those onto these stamps. Verified 132/132 incl. 995_self_rebuild byte-identity. --- selfhost/cmd/w6c/main.combined.ww | 58 ++++++++++++++++++++++++++++ selfhost/cmd/wcc/check.ww | 58 ++++++++++++++++++++++++++++ selfhost/cmd/wwdump/main.combined.ww | 58 ++++++++++++++++++++++++++++ 3 files changed, 174 insertions(+) diff --git a/selfhost/cmd/w6c/main.combined.ww b/selfhost/cmd/w6c/main.combined.ww index d8d77fce..9b4b8b04 100644 --- a/selfhost/cmd/w6c/main.combined.ww +++ b/selfhost/cmd/w6c/main.combined.ww @@ -8638,6 +8638,64 @@ fn exprtype(c: *checker, e: *node, hint: *node) *node = { m = m.next; }; }; }; + // A.6.1.5b stamp cases — mirror cstage check.c:833-866. Pure + // type-AST stamps; never rewrite e.kind. Lenient on misses + // (cstage errors); falls through to nil under scruttype L656. + // + // Pseudo-fields .len/.cap/.ptr on slice/str/array. Cstage + // L833-842. `str` lives as N_TNAME("str") in wwstage — no + // dedicated N_TSTR kind — so test the trio shape here. + if (bu != nil) { + let isstr: bool = (bu.kind == nkind.N_TNAME) && streq(bu.str, "str"); + if (bu.kind == nkind.N_TSLICE || bu.kind == nkind.N_TARRAY || isstr) { + if (streq(e.str, "len")) { + let tn: *node = mktname(c, "i32"); + e.type_ = tinfofornode(c, tn): *void; + return tn; + }; + if (streq(e.str, "cap")) { + let tn: *node = mktname(c, "i32"); + e.type_ = tinfofornode(c, tn): *void; + return tn; + }; + if (streq(e.str, "ptr")) { + let elem: *node = bu.lhs; + if (isstr) { elem = mktname(c, "u8"); }; + let pp: *node = newnode(nkind.N_TPTR, "", 0, 0); + pp.lhs = elem; + e.type_ = tinfofornode(c, pp): *void; + return pp; + }; + }; + }; + // Struct field walk. Cstage L843-849 errors on missing field. + if (bu != nil) { if (bu.kind == nkind.N_TSTRUCT) { + let f: *node = bu.list; + for (f != nil) { + if (f.kind == nkind.N_TFIELD) { if (streq(f.str, e.str)) { + e.type_ = tinfofornode(c, f.lhs): *void; + return f.lhs; + }; }; + f = f.next; + }; + }; }; + // Tuple positional access `t.0`, `t.1`, …. Cstage L850-866 + // errors on non-numeric / out-of-range; wwstage falls + // through. fldnumidx (cgenutil) returns -1 on non-digit. + if (bu != nil) { if (bu.kind == nkind.N_TTUPLE) { + let idx: i32 = fldnumidx(e.str); + if (idx >= 0) { + let p: *node = bu.list; + for (idx > 0 && p != nil) { + p = p.next; + idx -= 1; + }; + if (p != nil) { + e.type_ = tinfofornode(c, p): *void; + return p; + }; + }; + }; }; }; return nil; }; diff --git a/selfhost/cmd/wcc/check.ww b/selfhost/cmd/wcc/check.ww index 479613ee..85905dc3 100644 --- a/selfhost/cmd/wcc/check.ww +++ b/selfhost/cmd/wcc/check.ww @@ -1706,6 +1706,64 @@ fn exprtype(c: *checker, e: *node, hint: *node) *node = { m = m.next; }; }; }; + // A.6.1.5b stamp cases — mirror cstage check.c:833-866. Pure + // type-AST stamps; never rewrite e.kind. Lenient on misses + // (cstage errors); falls through to nil under scruttype L656. + // + // Pseudo-fields .len/.cap/.ptr on slice/str/array. Cstage + // L833-842. `str` lives as N_TNAME("str") in wwstage — no + // dedicated N_TSTR kind — so test the trio shape here. + if (bu != nil) { + let isstr: bool = (bu.kind == nkind.N_TNAME) && streq(bu.str, "str"); + if (bu.kind == nkind.N_TSLICE || bu.kind == nkind.N_TARRAY || isstr) { + if (streq(e.str, "len")) { + let tn: *node = mktname(c, "i32"); + e.type_ = tinfofornode(c, tn): *void; + return tn; + }; + if (streq(e.str, "cap")) { + let tn: *node = mktname(c, "i32"); + e.type_ = tinfofornode(c, tn): *void; + return tn; + }; + if (streq(e.str, "ptr")) { + let elem: *node = bu.lhs; + if (isstr) { elem = mktname(c, "u8"); }; + let pp: *node = newnode(nkind.N_TPTR, "", 0, 0); + pp.lhs = elem; + e.type_ = tinfofornode(c, pp): *void; + return pp; + }; + }; + }; + // Struct field walk. Cstage L843-849 errors on missing field. + if (bu != nil) { if (bu.kind == nkind.N_TSTRUCT) { + let f: *node = bu.list; + for (f != nil) { + if (f.kind == nkind.N_TFIELD) { if (streq(f.str, e.str)) { + e.type_ = tinfofornode(c, f.lhs): *void; + return f.lhs; + }; }; + f = f.next; + }; + }; }; + // Tuple positional access `t.0`, `t.1`, …. Cstage L850-866 + // errors on non-numeric / out-of-range; wwstage falls + // through. fldnumidx (cgenutil) returns -1 on non-digit. + if (bu != nil) { if (bu.kind == nkind.N_TTUPLE) { + let idx: i32 = fldnumidx(e.str); + if (idx >= 0) { + let p: *node = bu.list; + for (idx > 0 && p != nil) { + p = p.next; + idx -= 1; + }; + if (p != nil) { + e.type_ = tinfofornode(c, p): *void; + return p; + }; + }; + }; }; }; return nil; }; diff --git a/selfhost/cmd/wwdump/main.combined.ww b/selfhost/cmd/wwdump/main.combined.ww index bb9cb5db..30d6691d 100644 --- a/selfhost/cmd/wwdump/main.combined.ww +++ b/selfhost/cmd/wwdump/main.combined.ww @@ -8638,6 +8638,64 @@ fn exprtype(c: *checker, e: *node, hint: *node) *node = { m = m.next; }; }; }; + // A.6.1.5b stamp cases — mirror cstage check.c:833-866. Pure + // type-AST stamps; never rewrite e.kind. Lenient on misses + // (cstage errors); falls through to nil under scruttype L656. + // + // Pseudo-fields .len/.cap/.ptr on slice/str/array. Cstage + // L833-842. `str` lives as N_TNAME("str") in wwstage — no + // dedicated N_TSTR kind — so test the trio shape here. + if (bu != nil) { + let isstr: bool = (bu.kind == nkind.N_TNAME) && streq(bu.str, "str"); + if (bu.kind == nkind.N_TSLICE || bu.kind == nkind.N_TARRAY || isstr) { + if (streq(e.str, "len")) { + let tn: *node = mktname(c, "i32"); + e.type_ = tinfofornode(c, tn): *void; + return tn; + }; + if (streq(e.str, "cap")) { + let tn: *node = mktname(c, "i32"); + e.type_ = tinfofornode(c, tn): *void; + return tn; + }; + if (streq(e.str, "ptr")) { + let elem: *node = bu.lhs; + if (isstr) { elem = mktname(c, "u8"); }; + let pp: *node = newnode(nkind.N_TPTR, "", 0, 0); + pp.lhs = elem; + e.type_ = tinfofornode(c, pp): *void; + return pp; + }; + }; + }; + // Struct field walk. Cstage L843-849 errors on missing field. + if (bu != nil) { if (bu.kind == nkind.N_TSTRUCT) { + let f: *node = bu.list; + for (f != nil) { + if (f.kind == nkind.N_TFIELD) { if (streq(f.str, e.str)) { + e.type_ = tinfofornode(c, f.lhs): *void; + return f.lhs; + }; }; + f = f.next; + }; + }; }; + // Tuple positional access `t.0`, `t.1`, …. Cstage L850-866 + // errors on non-numeric / out-of-range; wwstage falls + // through. fldnumidx (cgenutil) returns -1 on non-digit. + if (bu != nil) { if (bu.kind == nkind.N_TTUPLE) { + let idx: i32 = fldnumidx(e.str); + if (idx >= 0) { + let p: *node = bu.list; + for (idx > 0 && p != nil) { + p = p.next; + idx -= 1; + }; + if (p != nil) { + e.type_ = tinfofornode(c, p): *void; + return p; + }; + }; + }; }; }; return nil; };