lib/ww/typ + selfhost/cmd/wcc/check: tinfo-on-node infrastructure (Phase A.1)

Foundation for audit §1.8 — wwstage cgen recomputes type sizes at every
site instead of reading n.type_ like cstage does (cmd/wcc/check.c sets
n->type via cexpr; cgen reads n->type->size). The scattered literals
this session has been chasing (#43, #60, etc.) are the symptom; this
chain is the cure.

A.1 is infrastructure only — no cgen-site graduation yet. Subsequent
A.2+ sub-commits collapse each walker family (slotsize, elemsize,
fieldsize, isstrtype, istaggedtype, ...) onto n.type_ reads.

lib/ww/typ.ww:
- tinfocacheent struct (key, val, cnext) — sea-of-stars per rule 12.
- tinfocache: *tinfocacheent field on tctx (now 25 fields).
- tinfocachelookup / tinfocachebind — head-prepend linked-list ops.

selfhost/cmd/wcc/check.ww:
- tinfofornode(c, n) *tinfo — covers N_TNAME primitive (singleton
  lookup), N_TNAME alias (recurse via resolvealias), N_TBANG
  (unwrap+recurse, iserror dropped — graduate alongside the first
  cgen reader that needs it), N_TPTR/N_TSLICE/N_TCHAN (recurse on
  sub, call typeptr/typeslice/typechan).
- exprtype N_INTLIT arm now sets e.type_ = tinfofornode(c, tn). Only
  population site in this commit; every other arm unchanged.

Empirically verified via temp probe that tinfofornode is reached and
returns non-nil on `let x: i32 = 42;`. Strict scope: zero cgen reads
of n.type_; primtypesize/slotsize/etc. still drive size queries.

131/131 + 994 + 995 byte-identical to caa72f2.
This commit is contained in:
2026-05-20 10:40:12 +09:00
parent caa72f2365
commit 93ac65ba0a
4 changed files with 357 additions and 3 deletions

View File

@@ -89,6 +89,17 @@ type tinfo = struct {
under: *tinfo,
};
// #61 audit §1.8 / Rob+Drew convergence 2026-05-20: memoizes
// tinfofornode lookups keyed by AST pointer. Linked-list shape mirrors
// other wwstage-side caches (cgen.aliases, cgen.structs) — sea-of-stars
// over hash-table cleverness, and Sym/Scope already pay the FNV cost
// for the resolver pass.
type tinfocacheent = struct {
key: *node,
val: *tinfo,
cnext: *tinfocacheent,
};
// ---- tctx — the box of primitive types -------------------------------
type tctx = struct {
@@ -118,6 +129,7 @@ type tctx = struct {
tyuntypedrune: *tinfo,
tyuntypedbool: *tinfo,
tyuntypednil: *tinfo,
tinfocache: *tinfocacheent,
};
// ---- constructors -----------------------------------------------------
@@ -214,6 +226,28 @@ export fn typenamed(a: *arena, name: str, under: *tinfo) *tinfo = {
return t;
};
// #61 audit §1.8 — A.1 infrastructure: tinfocache lookup/bind. Keyed
// by AST node-pointer so two different N_TNAME("i32") nodes get
// independent entries that both resolve to c.tyi32. Used by
// tinfofornode in check.ww; cgen still reads sizes via primtypesize
// until A.2+ graduates each walker family.
export fn tinfocachelookup(c: *tctx, key: *node) *tinfo = {
let e: *tinfocacheent = c.tinfocache;
for (e != nil) {
if (e.key == key) { return e.val; };
e = e.cnext;
};
return nil;
};
export fn tinfocachebind(c: *tctx, key: *node, val: *tinfo) void = {
let e: *tinfocacheent = amalloc(c.a, 32u64): *tinfocacheent;
e.key = key;
e.val = val;
e.cnext = c.tinfocache;
c.tinfocache = e;
};
// ---- predicates -------------------------------------------------------
export fn typeisint(t: *tinfo) bool = {