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:
@@ -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 = {
|
||||
|
||||
@@ -6515,6 +6515,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 {
|
||||
@@ -6544,6 +6555,7 @@ type tctx = struct {
|
||||
tyuntypedrune: *tinfo,
|
||||
tyuntypedbool: *tinfo,
|
||||
tyuntypednil: *tinfo,
|
||||
tinfocache: *tinfocacheent,
|
||||
};
|
||||
|
||||
// ---- constructors -----------------------------------------------------
|
||||
@@ -6640,6 +6652,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 = {
|
||||
@@ -7825,6 +7859,81 @@ fn foldtointlit(c: *checker, n: *node, v: i64) void = {
|
||||
n.tsuffix = empty;
|
||||
};
|
||||
|
||||
// #61 audit §1.8 — A.1 infrastructure: resolve a type-expression AST
|
||||
// node to its *tinfo. Mirrors cstage's resolve_type (cmd/wcc/check.c)
|
||||
// which produces ty_* singletons / arena-allocated composites from a
|
||||
// Node*. Cache lives in c.tc (typ.ww) so the same shape can be reused
|
||||
// across modules within one check pass. Rob+Drew convergence
|
||||
// 2026-05-20: cgen will graduate to read sizes from here in A.2+; A.1
|
||||
// just lays the helper and exercises it on N_INTLIT.
|
||||
//
|
||||
// Coverage today (A.1):
|
||||
// - N_TNAME primitive (i32, str, untyped_int, ...) -> tctx singleton
|
||||
// - N_TNAME alias -> recurse through resolvealias
|
||||
// - N_TPTR / N_TSLICE / N_TCHAN / N_TBANG -> structural recurse
|
||||
// Other shapes (TARRAY/TSTRUCT/TFN/TTAGGED/TTUPLE/TENUM) return nil
|
||||
// for now; A.2+ extends as cgen-site graduation demands them.
|
||||
fn tinfofornode(c: *checker, n: *node) *tinfo = {
|
||||
if (n == nil) { return nil; };
|
||||
let cached: *tinfo = tinfocachelookup(c.tc, n);
|
||||
if (cached != nil) { return cached; };
|
||||
let r: *tinfo = nil;
|
||||
let k: nkind = n.kind;
|
||||
if (k == nkind.N_TNAME) {
|
||||
let nm: str = n.str;
|
||||
if (streq(nm, "void")) { r = c.tc.tyvoid; };
|
||||
if (streq(nm, "bool")) { r = c.tc.tybool; };
|
||||
if (streq(nm, "rune")) { r = c.tc.tyrune; };
|
||||
if (streq(nm, "i8")) { r = c.tc.tyi8; };
|
||||
if (streq(nm, "i16")) { r = c.tc.tyi16; };
|
||||
if (streq(nm, "i32")) { r = c.tc.tyi32; };
|
||||
if (streq(nm, "i64")) { r = c.tc.tyi64; };
|
||||
if (streq(nm, "u8")) { r = c.tc.tyu8; };
|
||||
if (streq(nm, "u16")) { r = c.tc.tyu16; };
|
||||
if (streq(nm, "u32")) { r = c.tc.tyu32; };
|
||||
if (streq(nm, "u64")) { r = c.tc.tyu64; };
|
||||
if (streq(nm, "int")) { r = c.tc.tyint; };
|
||||
if (streq(nm, "uint")) { r = c.tc.tyuint; };
|
||||
if (streq(nm, "uintptr")) { r = c.tc.tyuintptr; };
|
||||
if (streq(nm, "f32")) { r = c.tc.tyf32; };
|
||||
if (streq(nm, "f64")) { r = c.tc.tyf64; };
|
||||
if (streq(nm, "str")) { r = c.tc.tystr; };
|
||||
if (streq(nm, "never")) { r = c.tc.tynever; };
|
||||
if (streq(nm, "untyped_int")) { r = c.tc.tyuntypedint; };
|
||||
if (streq(nm, "untyped_float")) { r = c.tc.tyuntypedfloat; };
|
||||
if (streq(nm, "untyped_str")) { r = c.tc.tyuntypedstr; };
|
||||
if (streq(nm, "untyped_rune")) { r = c.tc.tyuntypedrune; };
|
||||
if (streq(nm, "untyped_bool")) { r = c.tc.tyuntypedbool; };
|
||||
if (streq(nm, "untyped_nil")) { r = c.tc.tyuntypednil; };
|
||||
if (r == nil) {
|
||||
// Alias / user-defined name: resolve via scope and recurse.
|
||||
// Mirrors astsize's TNAME fallback so the helpers stay in
|
||||
// lockstep until A.2 collapses each cgen size-walker onto
|
||||
// tinfo.size directly.
|
||||
let body: *node = resolvealias(c, n);
|
||||
if (body != nil && body != n) {
|
||||
r = tinfofornode(c, body);
|
||||
};
|
||||
};
|
||||
} else { if (k == nkind.N_TBANG) {
|
||||
// #61 audit §1.8: `!T` propagates the inner shape; cstage's
|
||||
// resolve_type sets ty->iserror on the wrapper but no wwstage
|
||||
// cgen reader consumes it yet, so A.1 drops the flag and
|
||||
// returns the inner tinfo unchanged. Mirrors typeeqast's
|
||||
// unwrapbang pre-walk; graduate alongside the first cgen
|
||||
// site that needs iserror discrimination.
|
||||
r = tinfofornode(c, n.lhs);
|
||||
} else { if (k == nkind.N_TPTR) {
|
||||
r = typeptr(c.a, tinfofornode(c, n.lhs));
|
||||
} else { if (k == nkind.N_TSLICE) {
|
||||
r = typeslice(c.a, tinfofornode(c, n.lhs));
|
||||
} else { if (k == nkind.N_TCHAN) {
|
||||
r = typechan(c.a, tinfofornode(c, n.lhs));
|
||||
};};};};};
|
||||
if (r != nil) { tinfocachebind(c.tc, n, r); };
|
||||
return r;
|
||||
};
|
||||
|
||||
// exprtype — best-effort type-AST inference for an expression
|
||||
// node. Handles literals, identifiers, calls, and casts; returns
|
||||
// nil for shapes we don't statically know (binary ops, struct
|
||||
@@ -7832,7 +7941,16 @@ fn foldtointlit(c: *checker, n: *node, v: i64) void = {
|
||||
fn exprtype(c: *checker, e: *node) *node = {
|
||||
if (e == nil) { return nil; };
|
||||
let k: nkind = e.kind;
|
||||
if (k == nkind.N_INTLIT) { return mktname(c, "untyped_int"); };
|
||||
if (k == nkind.N_INTLIT) {
|
||||
let tn: *node = mktname(c, "untyped_int");
|
||||
// #61 audit §1.8 — A.1 single population site. Cgen still
|
||||
// reads sizes through primtypesize/slotsize today; A.2+
|
||||
// graduates each walker family to read e.type_ instead,
|
||||
// ending the size-walker cascade (Rob+Drew convergence
|
||||
// 2026-05-20). Don't extend population to other arms in A.1.
|
||||
e.type_ = tinfofornode(c, tn): *void;
|
||||
return tn;
|
||||
};
|
||||
if (k == nkind.N_FLOATLIT) { return mktname(c, "untyped_float"); };
|
||||
if (k == nkind.N_STRLIT) { return mktname(c, "str"); };
|
||||
if (k == nkind.N_RUNELIT) { return mktname(c, "rune"); };
|
||||
|
||||
@@ -831,6 +831,81 @@ fn foldtointlit(c: *checker, n: *node, v: i64) void = {
|
||||
n.tsuffix = empty;
|
||||
};
|
||||
|
||||
// #61 audit §1.8 — A.1 infrastructure: resolve a type-expression AST
|
||||
// node to its *tinfo. Mirrors cstage's resolve_type (cmd/wcc/check.c)
|
||||
// which produces ty_* singletons / arena-allocated composites from a
|
||||
// Node*. Cache lives in c.tc (typ.ww) so the same shape can be reused
|
||||
// across modules within one check pass. Rob+Drew convergence
|
||||
// 2026-05-20: cgen will graduate to read sizes from here in A.2+; A.1
|
||||
// just lays the helper and exercises it on N_INTLIT.
|
||||
//
|
||||
// Coverage today (A.1):
|
||||
// - N_TNAME primitive (i32, str, untyped_int, ...) -> tctx singleton
|
||||
// - N_TNAME alias -> recurse through resolvealias
|
||||
// - N_TPTR / N_TSLICE / N_TCHAN / N_TBANG -> structural recurse
|
||||
// Other shapes (TARRAY/TSTRUCT/TFN/TTAGGED/TTUPLE/TENUM) return nil
|
||||
// for now; A.2+ extends as cgen-site graduation demands them.
|
||||
fn tinfofornode(c: *checker, n: *node) *tinfo = {
|
||||
if (n == nil) { return nil; };
|
||||
let cached: *tinfo = tinfocachelookup(c.tc, n);
|
||||
if (cached != nil) { return cached; };
|
||||
let r: *tinfo = nil;
|
||||
let k: nkind = n.kind;
|
||||
if (k == nkind.N_TNAME) {
|
||||
let nm: str = n.str;
|
||||
if (streq(nm, "void")) { r = c.tc.tyvoid; };
|
||||
if (streq(nm, "bool")) { r = c.tc.tybool; };
|
||||
if (streq(nm, "rune")) { r = c.tc.tyrune; };
|
||||
if (streq(nm, "i8")) { r = c.tc.tyi8; };
|
||||
if (streq(nm, "i16")) { r = c.tc.tyi16; };
|
||||
if (streq(nm, "i32")) { r = c.tc.tyi32; };
|
||||
if (streq(nm, "i64")) { r = c.tc.tyi64; };
|
||||
if (streq(nm, "u8")) { r = c.tc.tyu8; };
|
||||
if (streq(nm, "u16")) { r = c.tc.tyu16; };
|
||||
if (streq(nm, "u32")) { r = c.tc.tyu32; };
|
||||
if (streq(nm, "u64")) { r = c.tc.tyu64; };
|
||||
if (streq(nm, "int")) { r = c.tc.tyint; };
|
||||
if (streq(nm, "uint")) { r = c.tc.tyuint; };
|
||||
if (streq(nm, "uintptr")) { r = c.tc.tyuintptr; };
|
||||
if (streq(nm, "f32")) { r = c.tc.tyf32; };
|
||||
if (streq(nm, "f64")) { r = c.tc.tyf64; };
|
||||
if (streq(nm, "str")) { r = c.tc.tystr; };
|
||||
if (streq(nm, "never")) { r = c.tc.tynever; };
|
||||
if (streq(nm, "untyped_int")) { r = c.tc.tyuntypedint; };
|
||||
if (streq(nm, "untyped_float")) { r = c.tc.tyuntypedfloat; };
|
||||
if (streq(nm, "untyped_str")) { r = c.tc.tyuntypedstr; };
|
||||
if (streq(nm, "untyped_rune")) { r = c.tc.tyuntypedrune; };
|
||||
if (streq(nm, "untyped_bool")) { r = c.tc.tyuntypedbool; };
|
||||
if (streq(nm, "untyped_nil")) { r = c.tc.tyuntypednil; };
|
||||
if (r == nil) {
|
||||
// Alias / user-defined name: resolve via scope and recurse.
|
||||
// Mirrors astsize's TNAME fallback so the helpers stay in
|
||||
// lockstep until A.2 collapses each cgen size-walker onto
|
||||
// tinfo.size directly.
|
||||
let body: *node = resolvealias(c, n);
|
||||
if (body != nil && body != n) {
|
||||
r = tinfofornode(c, body);
|
||||
};
|
||||
};
|
||||
} else { if (k == nkind.N_TBANG) {
|
||||
// #61 audit §1.8: `!T` propagates the inner shape; cstage's
|
||||
// resolve_type sets ty->iserror on the wrapper but no wwstage
|
||||
// cgen reader consumes it yet, so A.1 drops the flag and
|
||||
// returns the inner tinfo unchanged. Mirrors typeeqast's
|
||||
// unwrapbang pre-walk; graduate alongside the first cgen
|
||||
// site that needs iserror discrimination.
|
||||
r = tinfofornode(c, n.lhs);
|
||||
} else { if (k == nkind.N_TPTR) {
|
||||
r = typeptr(c.a, tinfofornode(c, n.lhs));
|
||||
} else { if (k == nkind.N_TSLICE) {
|
||||
r = typeslice(c.a, tinfofornode(c, n.lhs));
|
||||
} else { if (k == nkind.N_TCHAN) {
|
||||
r = typechan(c.a, tinfofornode(c, n.lhs));
|
||||
};};};};};
|
||||
if (r != nil) { tinfocachebind(c.tc, n, r); };
|
||||
return r;
|
||||
};
|
||||
|
||||
// exprtype — best-effort type-AST inference for an expression
|
||||
// node. Handles literals, identifiers, calls, and casts; returns
|
||||
// nil for shapes we don't statically know (binary ops, struct
|
||||
@@ -838,7 +913,16 @@ fn foldtointlit(c: *checker, n: *node, v: i64) void = {
|
||||
fn exprtype(c: *checker, e: *node) *node = {
|
||||
if (e == nil) { return nil; };
|
||||
let k: nkind = e.kind;
|
||||
if (k == nkind.N_INTLIT) { return mktname(c, "untyped_int"); };
|
||||
if (k == nkind.N_INTLIT) {
|
||||
let tn: *node = mktname(c, "untyped_int");
|
||||
// #61 audit §1.8 — A.1 single population site. Cgen still
|
||||
// reads sizes through primtypesize/slotsize today; A.2+
|
||||
// graduates each walker family to read e.type_ instead,
|
||||
// ending the size-walker cascade (Rob+Drew convergence
|
||||
// 2026-05-20). Don't extend population to other arms in A.1.
|
||||
e.type_ = tinfofornode(c, tn): *void;
|
||||
return tn;
|
||||
};
|
||||
if (k == nkind.N_FLOATLIT) { return mktname(c, "untyped_float"); };
|
||||
if (k == nkind.N_STRLIT) { return mktname(c, "str"); };
|
||||
if (k == nkind.N_RUNELIT) { return mktname(c, "rune"); };
|
||||
|
||||
@@ -6515,6 +6515,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 {
|
||||
@@ -6544,6 +6555,7 @@ type tctx = struct {
|
||||
tyuntypedrune: *tinfo,
|
||||
tyuntypedbool: *tinfo,
|
||||
tyuntypednil: *tinfo,
|
||||
tinfocache: *tinfocacheent,
|
||||
};
|
||||
|
||||
// ---- constructors -----------------------------------------------------
|
||||
@@ -6640,6 +6652,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 = {
|
||||
@@ -7825,6 +7859,81 @@ fn foldtointlit(c: *checker, n: *node, v: i64) void = {
|
||||
n.tsuffix = empty;
|
||||
};
|
||||
|
||||
// #61 audit §1.8 — A.1 infrastructure: resolve a type-expression AST
|
||||
// node to its *tinfo. Mirrors cstage's resolve_type (cmd/wcc/check.c)
|
||||
// which produces ty_* singletons / arena-allocated composites from a
|
||||
// Node*. Cache lives in c.tc (typ.ww) so the same shape can be reused
|
||||
// across modules within one check pass. Rob+Drew convergence
|
||||
// 2026-05-20: cgen will graduate to read sizes from here in A.2+; A.1
|
||||
// just lays the helper and exercises it on N_INTLIT.
|
||||
//
|
||||
// Coverage today (A.1):
|
||||
// - N_TNAME primitive (i32, str, untyped_int, ...) -> tctx singleton
|
||||
// - N_TNAME alias -> recurse through resolvealias
|
||||
// - N_TPTR / N_TSLICE / N_TCHAN / N_TBANG -> structural recurse
|
||||
// Other shapes (TARRAY/TSTRUCT/TFN/TTAGGED/TTUPLE/TENUM) return nil
|
||||
// for now; A.2+ extends as cgen-site graduation demands them.
|
||||
fn tinfofornode(c: *checker, n: *node) *tinfo = {
|
||||
if (n == nil) { return nil; };
|
||||
let cached: *tinfo = tinfocachelookup(c.tc, n);
|
||||
if (cached != nil) { return cached; };
|
||||
let r: *tinfo = nil;
|
||||
let k: nkind = n.kind;
|
||||
if (k == nkind.N_TNAME) {
|
||||
let nm: str = n.str;
|
||||
if (streq(nm, "void")) { r = c.tc.tyvoid; };
|
||||
if (streq(nm, "bool")) { r = c.tc.tybool; };
|
||||
if (streq(nm, "rune")) { r = c.tc.tyrune; };
|
||||
if (streq(nm, "i8")) { r = c.tc.tyi8; };
|
||||
if (streq(nm, "i16")) { r = c.tc.tyi16; };
|
||||
if (streq(nm, "i32")) { r = c.tc.tyi32; };
|
||||
if (streq(nm, "i64")) { r = c.tc.tyi64; };
|
||||
if (streq(nm, "u8")) { r = c.tc.tyu8; };
|
||||
if (streq(nm, "u16")) { r = c.tc.tyu16; };
|
||||
if (streq(nm, "u32")) { r = c.tc.tyu32; };
|
||||
if (streq(nm, "u64")) { r = c.tc.tyu64; };
|
||||
if (streq(nm, "int")) { r = c.tc.tyint; };
|
||||
if (streq(nm, "uint")) { r = c.tc.tyuint; };
|
||||
if (streq(nm, "uintptr")) { r = c.tc.tyuintptr; };
|
||||
if (streq(nm, "f32")) { r = c.tc.tyf32; };
|
||||
if (streq(nm, "f64")) { r = c.tc.tyf64; };
|
||||
if (streq(nm, "str")) { r = c.tc.tystr; };
|
||||
if (streq(nm, "never")) { r = c.tc.tynever; };
|
||||
if (streq(nm, "untyped_int")) { r = c.tc.tyuntypedint; };
|
||||
if (streq(nm, "untyped_float")) { r = c.tc.tyuntypedfloat; };
|
||||
if (streq(nm, "untyped_str")) { r = c.tc.tyuntypedstr; };
|
||||
if (streq(nm, "untyped_rune")) { r = c.tc.tyuntypedrune; };
|
||||
if (streq(nm, "untyped_bool")) { r = c.tc.tyuntypedbool; };
|
||||
if (streq(nm, "untyped_nil")) { r = c.tc.tyuntypednil; };
|
||||
if (r == nil) {
|
||||
// Alias / user-defined name: resolve via scope and recurse.
|
||||
// Mirrors astsize's TNAME fallback so the helpers stay in
|
||||
// lockstep until A.2 collapses each cgen size-walker onto
|
||||
// tinfo.size directly.
|
||||
let body: *node = resolvealias(c, n);
|
||||
if (body != nil && body != n) {
|
||||
r = tinfofornode(c, body);
|
||||
};
|
||||
};
|
||||
} else { if (k == nkind.N_TBANG) {
|
||||
// #61 audit §1.8: `!T` propagates the inner shape; cstage's
|
||||
// resolve_type sets ty->iserror on the wrapper but no wwstage
|
||||
// cgen reader consumes it yet, so A.1 drops the flag and
|
||||
// returns the inner tinfo unchanged. Mirrors typeeqast's
|
||||
// unwrapbang pre-walk; graduate alongside the first cgen
|
||||
// site that needs iserror discrimination.
|
||||
r = tinfofornode(c, n.lhs);
|
||||
} else { if (k == nkind.N_TPTR) {
|
||||
r = typeptr(c.a, tinfofornode(c, n.lhs));
|
||||
} else { if (k == nkind.N_TSLICE) {
|
||||
r = typeslice(c.a, tinfofornode(c, n.lhs));
|
||||
} else { if (k == nkind.N_TCHAN) {
|
||||
r = typechan(c.a, tinfofornode(c, n.lhs));
|
||||
};};};};};
|
||||
if (r != nil) { tinfocachebind(c.tc, n, r); };
|
||||
return r;
|
||||
};
|
||||
|
||||
// exprtype — best-effort type-AST inference for an expression
|
||||
// node. Handles literals, identifiers, calls, and casts; returns
|
||||
// nil for shapes we don't statically know (binary ops, struct
|
||||
@@ -7832,7 +7941,16 @@ fn foldtointlit(c: *checker, n: *node, v: i64) void = {
|
||||
fn exprtype(c: *checker, e: *node) *node = {
|
||||
if (e == nil) { return nil; };
|
||||
let k: nkind = e.kind;
|
||||
if (k == nkind.N_INTLIT) { return mktname(c, "untyped_int"); };
|
||||
if (k == nkind.N_INTLIT) {
|
||||
let tn: *node = mktname(c, "untyped_int");
|
||||
// #61 audit §1.8 — A.1 single population site. Cgen still
|
||||
// reads sizes through primtypesize/slotsize today; A.2+
|
||||
// graduates each walker family to read e.type_ instead,
|
||||
// ending the size-walker cascade (Rob+Drew convergence
|
||||
// 2026-05-20). Don't extend population to other arms in A.1.
|
||||
e.type_ = tinfofornode(c, tn): *void;
|
||||
return tn;
|
||||
};
|
||||
if (k == nkind.N_FLOATLIT) { return mktname(c, "untyped_float"); };
|
||||
if (k == nkind.N_STRLIT) { return mktname(c, "str"); };
|
||||
if (k == nkind.N_RUNELIT) { return mktname(c, "rune"); };
|
||||
|
||||
Reference in New Issue
Block a user