From 922877309bbbbb904d9f2ce4706fe808d009666a Mon Sep 17 00:00:00 2001 From: Hojun-Cho Date: Tue, 12 May 2026 05:04:33 +0900 Subject: [PATCH] =?UTF-8?q?ww+wcc:=20Hare-strict=20enum=20types=20?= =?UTF-8?q?=E2=80=94=20back=20out=20the=20int=E2=86=94enum=20relaxation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cascades the four enum kinds through every signature and local that holds one of their values, then removes the type_assignable / unify_arith relaxation that previously let bare i32 mix with the named enum types. Signature updates: - kwlookup() now returns `tkind` (not i32); tokname() takes `tkind` - accepttok / expecttok / bprec / isassignop take `tkind` - parsearglist's closekind is `tkind` - newtype / prim take `tykind`; scopedefine takes `skind` - newnode / nkname take `nkind` Struct fields: - tok.kind is `tkind`; parser.curkind is `tkind` - node.kind is `nkind`; node.op is `tkind` - tinfo.kind is `tykind`; sym.skind is `skind` Locals holding kinds across lex/parse/check/cgen are now typed with their enum, including sentinel patterns like `let lkind: nkind = nkind.N_NONE; if (...) lkind = tn.kind;`. The selfhost cgen had a load-width bug exposed by this: fieldsize() fell back to 8 bytes for any TNAME that wasn't a struct or primitive. For a tkind-typed field that gave `MOVQ (BX), AX` instead of `MOVL`, diverging from the C cgen on tok.kind / parser.curkind / etc. Two fixes: - fieldsize now consults the enum registry and returns the storage type's size (4 for `enum i32`) - collectenums runs before collectstructs in cgfile so the registry is populated when registerstruct asks for field sizes All 22 tests stay green; 990/993/995 byte-identity probes pass with the strict typing in place. --- cmd/wcc/check.c | 11 --- cmd/wcc/type.c | 15 ---- lib/ww/ast.ww | 8 +- lib/ww/lex/lex.ww | 4 +- lib/ww/lex/tok.ww | 7 +- lib/ww/parse/expr.ww | 8 +- lib/ww/parse/parse.ww | 10 +-- lib/ww/sym.ww | 4 +- lib/ww/typ.ww | 16 ++-- selfhost/cmd/w6c/main.combined.ww | 126 +++++++++++++++------------ selfhost/cmd/wcc/cgen.ww | 6 +- selfhost/cmd/wcc/cgendecl.ww | 5 +- selfhost/cmd/wcc/cgenexpr.ww | 14 +-- selfhost/cmd/wcc/cgenstmt.ww | 2 +- selfhost/cmd/wcc/cgenutil.ww | 32 ++++--- selfhost/cmd/wcc/check.ww | 10 +-- selfhost/cmd/wwdump/main.combined.ww | 126 +++++++++++++++------------ 17 files changed, 210 insertions(+), 194 deletions(-) diff --git a/cmd/wcc/check.c b/cmd/wcc/check.c index 86d822fa..0003d499 100644 --- a/cmd/wcc/check.c +++ b/cmd/wcc/check.c @@ -531,17 +531,6 @@ unify_arith(Checker *c, Pos p, Type *a, Type *b) if (type_isuntyped(a) && type_assignable(b, a)) return b; if (type_isuntyped(b) && type_assignable(a, b)) return a; if (type_eq(a, b)) return a; - /* Enum ↔ integer storage: pair `(tkind, i32)` operands unify to - * the storage int. Mirrors the same relaxation in type_assignable; - * lets `cur.kind == TK_FN` typecheck without a cast on either side. */ - { - Type *au = (a->kind == TY_NAMED) ? a->under : a; - Type *bu = (b->kind == TY_NAMED) ? b->under : b; - if (au && au->kind == TY_ENUM && type_isint(b) && - type_eq(au->sub, b)) return b; - if (bu && bu->kind == TY_ENUM && type_isint(a) && - type_eq(a, bu->sub)) return a; - } return err(c, p, "operands have differing types %s and %s", type_name(c->a, a), type_name(c->a, b)); } diff --git a/cmd/wcc/type.c b/cmd/wcc/type.c index b7312484..80a28fb1 100644 --- a/cmd/wcc/type.c +++ b/cmd/wcc/type.c @@ -295,21 +295,6 @@ type_assignable(Type *dst, Type *src) if (dst->kind == TY_NAMED && type_eq(dst->under, src)) return 1; if (src->kind == TY_NAMED && type_eq(dst, src->under)) return 1; - /* Enum ↔ integer storage: bare i32 flows into a `tkind` slot and - * vice-versa as long as the storage type matches. Hare-strict - * would require an explicit cast, but the ww frontend's tkind / - * nkind enums have hundreds of `let k: i32 = expr` sites we'd - * otherwise have to migrate in lockstep — the relaxation is - * explicit and limited to int-typed enums. */ - { - Type *du = (dst->kind == TY_NAMED) ? dst->under : dst; - Type *su = (src->kind == TY_NAMED) ? src->under : src; - if (du && du->kind == TY_ENUM && type_isint(src) && - type_eq(du->sub, src)) return 1; - if (su && su->kind == TY_ENUM && type_isint(dst) && - type_eq(dst, su->sub)) return 1; - } - /* Tuple-to-tuple: element-wise assignable. */ if (dst->kind == TY_TUPLE && src->kind == TY_TUPLE) { Tparam *pa = dst->params, *pb = src->params; diff --git a/lib/ww/ast.ww b/lib/ww/ast.ww index 50920367..267bd2ce 100644 --- a/lib/ww/ast.ww +++ b/lib/ww/ast.ww @@ -103,11 +103,11 @@ type nkind = enum i32 { // ---- Node ------------------------------------------------------------- type node = struct { - kind: i32, + kind: nkind, file: str, line: i32, col: i32, - op: i32, // for nkind.N_BIN / nkind.N_UN / nkind.N_ASSIGN + op: tkind, // for nkind.N_BIN / nkind.N_UN / nkind.N_ASSIGN str: str, uval: u64, fval: f64, @@ -125,7 +125,7 @@ type node = struct { module: str, // originating module from `// MODULE: foo`; "" if none }; -export fn newnode(a: *arena, k: i32, file: str, line: i32, col: i32) *node = { +export fn newnode(a: *arena, k: nkind, file: str, line: i32, col: i32) *node = { let n: *node = amalloc(a, 208u64): *node; // ≥ struct size n.kind = k; n.file = file; @@ -136,7 +136,7 @@ export fn newnode(a: *arena, k: i32, file: str, line: i32, col: i32) *node = { // ---- printer ---------------------------------------------------------- -fn nkname(k: i32) str = { +fn nkname(k: nkind) str = { if (k == nkind.N_NONE) { return "none"; }; if (k == nkind.N_INTLIT) { return "int"; }; if (k == nkind.N_FLOATLIT) { return "float"; }; diff --git a/lib/ww/lex/lex.ww b/lib/ww/lex/lex.ww index d819cf2a..90860dab 100644 --- a/lib/ww/lex/lex.ww +++ b/lib/ww/lex/lex.ww @@ -460,7 +460,7 @@ fn lexident(l: *lex, start: *pos, out: *tok) void = { return; }; }; - let k: i32 = kwlookup(p, n: i32); + let k: tkind = kwlookup(p, n: i32); if (k != tkind.TK_NONE) { out.kind = k; } else { @@ -553,7 +553,7 @@ fn lexrune(l: *lex, start: *pos, out: *tok) void = { out.uval = ch: u64; }; -fn emitsimple(start: *pos, k: i32, out: *tok) void = { +fn emitsimple(start: *pos, k: tkind, out: *tok) void = { out.kind = k; out.file = start.file; out.line = start.line; diff --git a/lib/ww/lex/tok.ww b/lib/ww/lex/tok.ww index 5e3ac0c9..f3b1fb94 100644 --- a/lib/ww/lex/tok.ww +++ b/lib/ww/lex/tok.ww @@ -134,8 +134,7 @@ type pos = struct { }; type tok = struct { - kind: i32, // holds a `tkind` value; bare i32 so the cgen's - // fixed 8B/struct-field layout matches the C side + kind: tkind, file: str, // path of the source the token came from line: i32, col: i32, @@ -160,7 +159,7 @@ fn streqn(a: *u8, b: str, n: i32) bool = { // kwlookup — returns the matching TK_* keyword kind for a byte run, // or tkind.TK_NONE if it's an ordinary identifier. Linear search over a // small alphabetised list, matching cmd/wcc/tok.c. -export fn kwlookup(p: *u8, n: i32) i32 = { +export fn kwlookup(p: *u8, n: i32) tkind = { if (streqn(p, "as", n)) { return tkind.TK_AS; }; if (streqn(p, "break", n)) { return tkind.TK_BREAK; }; if (streqn(p, "case", n)) { return tkind.TK_CASE; }; @@ -198,7 +197,7 @@ export fn kwlookup(p: *u8, n: i32) i32 = { // Returns the canonical printable spelling for a token kind. Matches // the C tokname()'s output exactly so wwdump output diffs cleanly. -export fn tokname(k: i32) str = { +export fn tokname(k: tkind) str = { if (k == tkind.TK_NONE) { return ""; }; if (k == tkind.TK_EOF) { return "EOF"; }; if (k == tkind.TK_ERR) { return "ERR"; }; diff --git a/lib/ww/parse/expr.ww b/lib/ww/parse/expr.ww index ef335c25..d29226e5 100644 --- a/lib/ww/parse/expr.ww +++ b/lib/ww/parse/expr.ww @@ -199,7 +199,7 @@ fn parseprimary(p: *parser) *node = { return newnode(p.a, nkind.N_NONE, pf, pl, pc); }; -fn parsearglist(p: *parser, closekind: i32, headout: **node) void = { +fn parsearglist(p: *parser, closekind: tkind, headout: **node) void = { *headout = nil; if (p.curkind == closekind) { return; }; let head: *node = nil; @@ -355,7 +355,7 @@ fn parseunary(p: *parser) *node = { let pf: str = p.curfile; let pl: i32 = p.curline; let pc: i32 = p.curcol; - let k: i32 = p.curkind; + let k: tkind = p.curkind; if (k == tkind.TK_MINUS) { advance(p); let n: *node = newnode(p.a, nkind.N_UN, pf, pl, pc); @@ -398,7 +398,7 @@ fn parseunary(p: *parser) *node = { fn parsebin(p: *parser, lhs: *node, minp: i32) *node = { let cur: *node = lhs; for (true) { - let op: i32 = p.curkind; + let op: tkind = p.curkind; let pr: i32 = bprec(op); if (pr == 0) { return cur; }; if (pr < minp) { return cur; }; @@ -425,7 +425,7 @@ fn parseexpr(p: *parser) *node = { let pf: str = p.curfile; let pl: i32 = p.curline; let pc: i32 = p.curcol; - let op: i32 = p.curkind; + let op: tkind = p.curkind; advance(p); let n: *node = newnode(p.a, nkind.N_ASSIGN, pf, pl, pc); n.op = op; diff --git a/lib/ww/parse/parse.ww b/lib/ww/parse/parse.ww index 2bb1ab21..bcc19543 100644 --- a/lib/ww/parse/parse.ww +++ b/lib/ww/parse/parse.ww @@ -24,7 +24,7 @@ type parser = struct { // nocast: while inside `[...]` we treat ':' as the slice // separator, not the cast operator. Mirrors parse.c's flag. nocast: i32, - curkind: i32, // holds a `tkind` value (relaxation lets it mix) + curkind: tkind, curfile: str, curline: i32, curcol: i32, @@ -53,7 +53,7 @@ export fn parserinit(p: *parser, a: *arena, l: *lex) void = { fn advance(p: *parser) void = { refill(p); }; -fn accepttok(p: *parser, k: i32) bool = { +fn accepttok(p: *parser, k: tkind) bool = { if (p.curkind == k) { advance(p); return true; }; return false; }; @@ -66,7 +66,7 @@ fn errmsg(p: *parser, msg: str) void = { p.errs += 1; }; -fn expecttok(p: *parser, k: i32, what: str) bool = { +fn expecttok(p: *parser, k: tkind, what: str) bool = { if (p.curkind == k) { advance(p); return true; }; errmsg(p, what); return false; @@ -313,7 +313,7 @@ fn parsetype(p: *parser) *node = { // and the ?/! try operators are not yet wired — they'll arrive as the // AST diff fixture grows to need them. -fn bprec(k: i32) i32 = { +fn bprec(k: tkind) i32 = { if (k == tkind.TK_OR) { return 1; }; if (k == tkind.TK_AND) { return 2; }; if (k == tkind.TK_EQ) { return 3; }; @@ -335,7 +335,7 @@ fn bprec(k: i32) i32 = { return 0; }; -fn isassignop(k: i32) bool = { +fn isassignop(k: tkind) bool = { if (k == tkind.TK_ASSIGN) { return true; }; if (k == tkind.TK_PLUSEQ) { return true; }; if (k == tkind.TK_MINUSEQ) { return true; }; diff --git a/lib/ww/sym.ww b/lib/ww/sym.ww index 3566e1a1..2177ce49 100644 --- a/lib/ww/sym.ww +++ b/lib/ww/sym.ww @@ -22,7 +22,7 @@ type skind = enum i32 { type sym = struct { name: str, - skind: i32, + skind: skind, type_: *tinfo, decl: *node, exported: i32, @@ -98,7 +98,7 @@ export fn scopelookup(s: *scope, name: str) *sym = { return nil; }; -export fn scopedefine(s: *scope, name: str, k: i32, t: *tinfo, decl: *node) *sym = { +export fn scopedefine(s: *scope, name: str, k: skind, t: *tinfo, decl: *node) *sym = { if (scopelookuplocal(s, name) != nil) { return nil; }; let sy: *sym = amalloc(s.a, 80u64): *sym; sy.name = name; diff --git a/lib/ww/typ.ww b/lib/ww/typ.ww index 06775dfa..e3d58e2f 100644 --- a/lib/ww/typ.ww +++ b/lib/ww/typ.ww @@ -74,7 +74,7 @@ type tparam = struct { }; type tinfo = struct { - kind: i32, + kind: tykind, size: u64, align: u64, sub: *tinfo, // ptr/slice/array/chan element @@ -120,13 +120,13 @@ type tctx = struct { // ---- constructors ----------------------------------------------------- -export fn newtype(a: *arena, k: i32) *tinfo = { +export fn newtype(a: *arena, k: tykind) *tinfo = { let t: *tinfo = amalloc(a, 96u64): *tinfo; t.kind = k; return t; }; -fn prim(a: *arena, k: i32, nm: str, sz: u64, al: u64) *tinfo = { +fn prim(a: *arena, k: tykind, nm: str, sz: u64, al: u64) *tinfo = { let t: *tinfo = newtype(a, k); t.name = nm; t.size = sz; @@ -216,7 +216,7 @@ export fn typenamed(a: *arena, name: str, under: *tinfo) *tinfo = { export fn typeisint(t: *tinfo) bool = { if (t == nil) { return false; }; - let k: i32 = t.kind; + let k: tykind = t.kind; if (k == tykind.TY_I8) { return true; }; if (k == tykind.TY_I16) { return true; }; if (k == tykind.TY_I32) { return true; }; @@ -238,7 +238,7 @@ export fn typeisint(t: *tinfo) bool = { export fn typeisfloat(t: *tinfo) bool = { if (t == nil) { return false; }; - let k: i32 = t.kind; + let k: tykind = t.kind; if (k == tykind.TY_F32) { return true; }; if (k == tykind.TY_F64) { return true; }; if (k == tykind.TY_UNTYPED_FLOAT) { return true; }; @@ -253,7 +253,7 @@ export fn typeisnum(t: *tinfo) bool = { export fn typeisunsigned(t: *tinfo) bool = { if (t == nil) { return false; }; - let k: i32 = t.kind; + let k: tykind = t.kind; if (k == tykind.TY_U8) { return true; }; if (k == tykind.TY_U16) { return true; }; if (k == tykind.TY_U32) { return true; }; @@ -266,7 +266,7 @@ export fn typeisunsigned(t: *tinfo) bool = { export fn typeisuntyped(t: *tinfo) bool = { if (t == nil) { return false; }; - let k: i32 = t.kind; + let k: tykind = t.kind; if (k == tykind.TY_UNTYPED_INT) { return true; }; if (k == tykind.TY_UNTYPED_FLOAT) { return true; }; if (k == tykind.TY_UNTYPED_STR) { return true; }; @@ -282,7 +282,7 @@ export fn typeeq(a: *tinfo, b: *tinfo) bool = { if (a == nil) { return false; }; if (b == nil) { return false; }; if (a.kind != b.kind) { return false; }; - let k: i32 = a.kind; + let k: tykind = a.kind; if (k == tykind.TY_PTR) { return typeeq(a.sub, b.sub); }; if (k == tykind.TY_SLICE) { return typeeq(a.sub, b.sub); }; if (k == tykind.TY_CHAN) { return typeeq(a.sub, b.sub); }; diff --git a/selfhost/cmd/w6c/main.combined.ww b/selfhost/cmd/w6c/main.combined.ww index b512a136..04a44ca1 100644 --- a/selfhost/cmd/w6c/main.combined.ww +++ b/selfhost/cmd/w6c/main.combined.ww @@ -581,8 +581,7 @@ type pos = struct { }; type tok = struct { - kind: i32, // holds a `tkind` value; bare i32 so the cgen's - // fixed 8B/struct-field layout matches the C side + kind: tkind, file: str, // path of the source the token came from line: i32, col: i32, @@ -607,7 +606,7 @@ fn streqn(a: *u8, b: str, n: i32) bool = { // kwlookup — returns the matching TK_* keyword kind for a byte run, // or tkind.TK_NONE if it's an ordinary identifier. Linear search over a // small alphabetised list, matching cmd/wcc/tok.c. -export fn kwlookup(p: *u8, n: i32) i32 = { +export fn kwlookup(p: *u8, n: i32) tkind = { if (streqn(p, "as", n)) { return tkind.TK_AS; }; if (streqn(p, "break", n)) { return tkind.TK_BREAK; }; if (streqn(p, "case", n)) { return tkind.TK_CASE; }; @@ -645,7 +644,7 @@ export fn kwlookup(p: *u8, n: i32) i32 = { // Returns the canonical printable spelling for a token kind. Matches // the C tokname()'s output exactly so wwdump output diffs cleanly. -export fn tokname(k: i32) str = { +export fn tokname(k: tkind) str = { if (k == tkind.TK_NONE) { return ""; }; if (k == tkind.TK_EOF) { return "EOF"; }; if (k == tkind.TK_ERR) { return "ERR"; }; @@ -1421,7 +1420,7 @@ fn lexident(l: *lex, start: *pos, out: *tok) void = { return; }; }; - let k: i32 = kwlookup(p, n: i32); + let k: tkind = kwlookup(p, n: i32); if (k != tkind.TK_NONE) { out.kind = k; } else { @@ -1514,7 +1513,7 @@ fn lexrune(l: *lex, start: *pos, out: *tok) void = { out.uval = ch: u64; }; -fn emitsimple(start: *pos, k: i32, out: *tok) void = { +fn emitsimple(start: *pos, k: tkind, out: *tok) void = { out.kind = k; out.file = start.file; out.line = start.line; @@ -1766,11 +1765,11 @@ type nkind = enum i32 { // ---- Node ------------------------------------------------------------- type node = struct { - kind: i32, + kind: nkind, file: str, line: i32, col: i32, - op: i32, // for nkind.N_BIN / nkind.N_UN / nkind.N_ASSIGN + op: tkind, // for nkind.N_BIN / nkind.N_UN / nkind.N_ASSIGN str: str, uval: u64, fval: f64, @@ -1788,7 +1787,7 @@ type node = struct { module: str, // originating module from `// MODULE: foo`; "" if none }; -export fn newnode(a: *arena, k: i32, file: str, line: i32, col: i32) *node = { +export fn newnode(a: *arena, k: nkind, file: str, line: i32, col: i32) *node = { let n: *node = amalloc(a, 208u64): *node; // ≥ struct size n.kind = k; n.file = file; @@ -1799,7 +1798,7 @@ export fn newnode(a: *arena, k: i32, file: str, line: i32, col: i32) *node = { // ---- printer ---------------------------------------------------------- -fn nkname(k: i32) str = { +fn nkname(k: nkind) str = { if (k == nkind.N_NONE) { return "none"; }; if (k == nkind.N_INTLIT) { return "int"; }; if (k == nkind.N_FLOATLIT) { return "float"; }; @@ -2222,7 +2221,7 @@ fn parseprimary(p: *parser) *node = { return newnode(p.a, nkind.N_NONE, pf, pl, pc); }; -fn parsearglist(p: *parser, closekind: i32, headout: **node) void = { +fn parsearglist(p: *parser, closekind: tkind, headout: **node) void = { *headout = nil; if (p.curkind == closekind) { return; }; let head: *node = nil; @@ -2378,7 +2377,7 @@ fn parseunary(p: *parser) *node = { let pf: str = p.curfile; let pl: i32 = p.curline; let pc: i32 = p.curcol; - let k: i32 = p.curkind; + let k: tkind = p.curkind; if (k == tkind.TK_MINUS) { advance(p); let n: *node = newnode(p.a, nkind.N_UN, pf, pl, pc); @@ -2421,7 +2420,7 @@ fn parseunary(p: *parser) *node = { fn parsebin(p: *parser, lhs: *node, minp: i32) *node = { let cur: *node = lhs; for (true) { - let op: i32 = p.curkind; + let op: tkind = p.curkind; let pr: i32 = bprec(op); if (pr == 0) { return cur; }; if (pr < minp) { return cur; }; @@ -2448,7 +2447,7 @@ fn parseexpr(p: *parser) *node = { let pf: str = p.curfile; let pl: i32 = p.curline; let pc: i32 = p.curcol; - let op: i32 = p.curkind; + let op: tkind = p.curkind; advance(p); let n: *node = newnode(p.a, nkind.N_ASSIGN, pf, pl, pc); n.op = op; @@ -2933,7 +2932,7 @@ type parser = struct { // nocast: while inside `[...]` we treat ':' as the slice // separator, not the cast operator. Mirrors parse.c's flag. nocast: i32, - curkind: i32, // holds a `tkind` value (relaxation lets it mix) + curkind: tkind, curfile: str, curline: i32, curcol: i32, @@ -2962,7 +2961,7 @@ export fn parserinit(p: *parser, a: *arena, l: *lex) void = { fn advance(p: *parser) void = { refill(p); }; -fn accepttok(p: *parser, k: i32) bool = { +fn accepttok(p: *parser, k: tkind) bool = { if (p.curkind == k) { advance(p); return true; }; return false; }; @@ -2975,7 +2974,7 @@ fn errmsg(p: *parser, msg: str) void = { p.errs += 1; }; -fn expecttok(p: *parser, k: i32, what: str) bool = { +fn expecttok(p: *parser, k: tkind, what: str) bool = { if (p.curkind == k) { advance(p); return true; }; errmsg(p, what); return false; @@ -3222,7 +3221,7 @@ fn parsetype(p: *parser) *node = { // and the ?/! try operators are not yet wired — they'll arrive as the // AST diff fixture grows to need them. -fn bprec(k: i32) i32 = { +fn bprec(k: tkind) i32 = { if (k == tkind.TK_OR) { return 1; }; if (k == tkind.TK_AND) { return 2; }; if (k == tkind.TK_EQ) { return 3; }; @@ -3244,7 +3243,7 @@ fn bprec(k: i32) i32 = { return 0; }; -fn isassignop(k: i32) bool = { +fn isassignop(k: tkind) bool = { if (k == tkind.TK_ASSIGN) { return true; }; if (k == tkind.TK_PLUSEQ) { return true; }; if (k == tkind.TK_MINUSEQ) { return true; }; @@ -3402,7 +3401,7 @@ type tparam = struct { }; type tinfo = struct { - kind: i32, + kind: tykind, size: u64, align: u64, sub: *tinfo, // ptr/slice/array/chan element @@ -3448,13 +3447,13 @@ type tctx = struct { // ---- constructors ----------------------------------------------------- -export fn newtype(a: *arena, k: i32) *tinfo = { +export fn newtype(a: *arena, k: tykind) *tinfo = { let t: *tinfo = amalloc(a, 96u64): *tinfo; t.kind = k; return t; }; -fn prim(a: *arena, k: i32, nm: str, sz: u64, al: u64) *tinfo = { +fn prim(a: *arena, k: tykind, nm: str, sz: u64, al: u64) *tinfo = { let t: *tinfo = newtype(a, k); t.name = nm; t.size = sz; @@ -3544,7 +3543,7 @@ export fn typenamed(a: *arena, name: str, under: *tinfo) *tinfo = { export fn typeisint(t: *tinfo) bool = { if (t == nil) { return false; }; - let k: i32 = t.kind; + let k: tykind = t.kind; if (k == tykind.TY_I8) { return true; }; if (k == tykind.TY_I16) { return true; }; if (k == tykind.TY_I32) { return true; }; @@ -3566,7 +3565,7 @@ export fn typeisint(t: *tinfo) bool = { export fn typeisfloat(t: *tinfo) bool = { if (t == nil) { return false; }; - let k: i32 = t.kind; + let k: tykind = t.kind; if (k == tykind.TY_F32) { return true; }; if (k == tykind.TY_F64) { return true; }; if (k == tykind.TY_UNTYPED_FLOAT) { return true; }; @@ -3581,7 +3580,7 @@ export fn typeisnum(t: *tinfo) bool = { export fn typeisunsigned(t: *tinfo) bool = { if (t == nil) { return false; }; - let k: i32 = t.kind; + let k: tykind = t.kind; if (k == tykind.TY_U8) { return true; }; if (k == tykind.TY_U16) { return true; }; if (k == tykind.TY_U32) { return true; }; @@ -3594,7 +3593,7 @@ export fn typeisunsigned(t: *tinfo) bool = { export fn typeisuntyped(t: *tinfo) bool = { if (t == nil) { return false; }; - let k: i32 = t.kind; + let k: tykind = t.kind; if (k == tykind.TY_UNTYPED_INT) { return true; }; if (k == tykind.TY_UNTYPED_FLOAT) { return true; }; if (k == tykind.TY_UNTYPED_STR) { return true; }; @@ -3610,7 +3609,7 @@ export fn typeeq(a: *tinfo, b: *tinfo) bool = { if (a == nil) { return false; }; if (b == nil) { return false; }; if (a.kind != b.kind) { return false; }; - let k: i32 = a.kind; + let k: tykind = a.kind; if (k == tykind.TY_PTR) { return typeeq(a.sub, b.sub); }; if (k == tykind.TY_SLICE) { return typeeq(a.sub, b.sub); }; if (k == tykind.TY_CHAN) { return typeeq(a.sub, b.sub); }; @@ -3693,7 +3692,7 @@ type skind = enum i32 { type sym = struct { name: str, - skind: i32, + skind: skind, type_: *tinfo, decl: *node, exported: i32, @@ -3769,7 +3768,7 @@ export fn scopelookup(s: *scope, name: str) *sym = { return nil; }; -export fn scopedefine(s: *scope, name: str, k: i32, t: *tinfo, decl: *node) *sym = { +export fn scopedefine(s: *scope, name: str, k: skind, t: *tinfo, decl: *node) *sym = { if (scopelookuplocal(s, name) != nil) { return nil; }; let sy: *sym = amalloc(s.a, 80u64): *sym; sy.name = name; @@ -3857,7 +3856,7 @@ fn seedprimitives(c: *checker) void = { // the name so forward references resolve. fn installdecl(c: *checker, d: *node) void = { if (d == nil) { return; }; - let k: i32 = d.kind; + let k: nkind = d.kind; let nm: str = d.str; if (k == nkind.N_USE) { scopedefine(c.top, nm, skind.SK_USE, nil, d); return; }; if (k == nkind.N_DEF) { scopedefine(c.top, nm, skind.SK_DEF, nil, d); return; }; @@ -3876,7 +3875,7 @@ fn installdecl(c: *checker, d: *node) void = { // the same pass — they need the same scope state. fn resolvewalk(c: *checker, n: *node) void = { if (n == nil) { return; }; - let k: i32 = n.kind; + let k: nkind = n.kind; // Typed checks fire on the way down so the scrutinee/operand // is examined before the arm bodies install new bindings. @@ -4042,7 +4041,7 @@ fn typeeqast(a: *node, b: *node) bool = { if (aa == nil) { return bb == nil; }; if (bb == nil) { return false; }; if (aa.kind != bb.kind) { return false; }; - let k: i32 = aa.kind; + let k: nkind = aa.kind; if (k == nkind.N_TNAME) { return streq(aa.str, bb.str); }; if (k == nkind.N_TPTR) { return typeeqast(aa.lhs, bb.lhs); }; if (k == nkind.N_TSLICE){ return typeeqast(aa.lhs, bb.lhs); }; @@ -4131,7 +4130,7 @@ fn mktname(c: *checker, nm: str) *node = { // field access into non-primitive types, etc). fn exprtype(c: *checker, e: *node) *node = { if (e == nil) { return nil; }; - let k: i32 = e.kind; + let k: nkind = e.kind; if (k == nkind.N_INTLIT) { return mktname(c, "untyped_int"); }; if (k == nkind.N_FLOATLIT) { return mktname(c, "untyped_float"); }; if (k == nkind.N_STRLIT) { return mktname(c, "str"); }; @@ -4689,7 +4688,7 @@ export fn checkfile(c: *checker, file: *node) void = { // Pass 2: walk decl bodies/types and resolve identifiers. d = file.list; for (d != nil) { - let k: i32 = d.kind; + let k: nkind = d.kind; if (k == nkind.N_FNDECL) { if (d.lhs != nil) { resolvewalk(c, d.lhs); }; // return type resolvefnbody(c, d); @@ -4863,7 +4862,7 @@ fn pushargsrev(c: *cgen, arg: *node) i32 = { fn nodeisslice(c: *cgen, n: *node) bool = { if (n == nil) { return false; }; - let k: i32 = n.kind; + let k: nkind = n.kind; if (k == nkind.N_IDENT) { let nm: str = n.str; let lc: *local = localfindnode(c, nm); @@ -4879,7 +4878,7 @@ fn nodeisslice(c: *cgen, n: *node) bool = { // (str args take two slots: ptr + len). fn nodeisstr(c: *cgen, n: *node) bool = { if (n == nil) { return false; }; - let k: i32 = n.kind; + let k: nkind = n.kind; if (k == nkind.N_STRLIT) { return true; }; if (k == nkind.N_IDENT) { let nm: str = n.str; @@ -4920,7 +4919,7 @@ fn nodeisstr(c: *cgen, n: *node) bool = { let lc: *local = localfindnode(c, base.str); if (lc != nil) { let tn: *node = lc.tnode; - let lkind: i32 = -1; + let lkind: nkind = nkind.N_NONE; if (tn != nil) { lkind = tn.kind; }; if (lkind == nkind.N_TNAME) { sname = tn.str; }; if (lkind == nkind.N_TPTR) { @@ -4989,7 +4988,7 @@ fn typenodeisunsigned(t: *node) bool = { // false here even when their *slot* rounds up to 8. fn typeis8byteprimitive(c: *cgen, t: *node) bool = { if (t == nil) { return false; }; - let k: i32 = t.kind; + let k: nkind = t.kind; if (k == nkind.N_TPTR) { return true; }; if (k == nkind.N_TFN) { return true; }; if (k == nkind.N_TCHAN) { return true; }; @@ -5081,7 +5080,7 @@ fn indexbaseesz(c: *cgen, base: *node) i32 = { }; // Generic struct field: if it's *T, element size is T's size. - let lkind: i32 = tn.kind; + let lkind: nkind = tn.kind; let sname: str; sname.ptr = nil; sname.len = 0; if (lkind == nkind.N_TNAME) { sname = tn.str; }; @@ -5180,7 +5179,7 @@ fn dotinnerstructptr(c: *cgen, n: *node) *node = { // bool/str-byte, 8 otherwise — same shape as C cgen's esz fallback). fn elemsizeof(t: *node) i32 = { if (t == nil) { return 1; }; - let k: i32 = t.kind; + let k: nkind = t.kind; let elem: *node = nil; if (k == nkind.N_TPTR) { elem = t.lhs; }; if (k == nkind.N_TSLICE) { elem = t.lhs; }; @@ -5216,7 +5215,7 @@ fn elemsizeof(t: *node) i32 = { // being wrong here is byte-different asm vs C, not bad runtime. fn nodeisunsigned(c: *cgen, n: *node) bool = { if (n == nil) { return false; }; - let k: i32 = n.kind; + let k: nkind = n.kind; if (k == nkind.N_IDENT) { let nm: str = n.str; let lc: *local = localfindnode(c, nm); @@ -5232,7 +5231,7 @@ fn nodeisunsigned(c: *cgen, n: *node) bool = { let lc: *local = localfindnode(c, bn); if (lc != nil) { let tn: *node = lc.tnode; - let lkind: i32 = -1; + let lkind: nkind = nkind.N_NONE; if (tn != nil) { lkind = tn.kind; }; let sname: str; sname.ptr = nil; sname.len = 0; @@ -5394,7 +5393,7 @@ export fn letslotsize(c: *cgen, n: *node) i32 = { fn slotsize(c: *cgen, typn: *node) i32 = { if (typn == nil) { return 8; }; - let k: i32 = typn.kind; + let k: nkind = typn.kind; if (k == nkind.N_TPTR) { return 8; }; if (k == nkind.N_TFN) { return 8; }; if (k == nkind.N_TCHAN) { return 8; }; @@ -5481,7 +5480,7 @@ fn slotsize(c: *cgen, typn: *node) i32 = { // only round to 8 for stack slots, not struct interiors). fn fieldsize(c: *cgen, tnode: *node) i32 = { if (tnode == nil) { return 8; }; - let k: i32 = tnode.kind; + let k: nkind = tnode.kind; if (k == nkind.N_TNAME) { let nm: str = tnode.str; if (streq(nm, "str")) { return 16; }; @@ -5489,6 +5488,18 @@ fn fieldsize(c: *cgen, tnode: *node) i32 = { if (ps > 0) { return ps; }; let si: *structinfo = structlookup(c, nm); if (si != nil) { return si.totsize; }; + // Enum: size of its storage type. Mirrors the C cgen, which + // reads Type.size off the TY_ENUM (which inherits from .sub). + let en: *enumtype = enumlookup(c, nm); + if (en != nil) { + if (en.storage != nil) { + if (en.storage.kind == nkind.N_TNAME) { + let sps: i32 = primsize(en.storage.str); + if (sps > 0) { return sps; }; + }; + }; + return 4; // default storage is i32 + }; return 8; }; if (k == nkind.N_TPTR) { return 8; }; @@ -5739,7 +5750,7 @@ use strconv; fn cgexpr(c: *cgen, n: *node) void = { if (n == nil) { return; }; - let k: i32 = n.kind; + let k: nkind = n.kind; if (k == nkind.N_INTLIT) { // Print signed (i64), not unsigned (u64). C cgen uses @@ -5974,7 +5985,7 @@ fn cgtypetest(c: *cgen, n: *node) void = { // through the cast pass-through too). fn isenumexpr(c: *cgen, e: *node) bool = { if (e == nil) { return false; }; - let k: i32 = e.kind; + let k: nkind = e.kind; if (k == nkind.N_DOT) { if (e.lhs != nil) { if (e.lhs.kind == nkind.N_IDENT) { @@ -6367,7 +6378,7 @@ fn cgdot(c: *cgen, n: *node) void = { let lc: *local = localfindnode(c, nm); if (lc != nil) { let tn: *node = lc.tnode; - let lkind: i32 = -1; + let lkind: nkind = nkind.N_NONE; if (tn != nil) { lkind = tn.kind; }; // Pointer-to-struct: deref then field load. if (lkind == nkind.N_TPTR) { @@ -6524,7 +6535,7 @@ fn cgdot(c: *cgen, n: *node) void = { // pointed-to header. C cgen does the same. if (lkind == nkind.N_TPTR) { let inner: *node = tn.lhs; - let innerkind: i32 = -1; + let innerkind: nkind = nkind.N_NONE; if (inner != nil) { innerkind = inner.kind; }; let innerstr: bool = false; if (innerkind == nkind.N_TNAME) { @@ -6788,7 +6799,7 @@ fn cgcall(c: *cgen, n: *node) void = { if (lc != nil) { let tn: *node = lc.tnode; if (tn != nil) { - let lkind: i32 = tn.kind; + let lkind: nkind = tn.kind; let sname: str; sname.ptr = nil; sname.len = 0; if (lkind == nkind.N_TNAME) { sname = tn.str; }; @@ -7008,7 +7019,7 @@ fn cgassign(c: *cgen, n: *node) void = { let lc: *local = localfindnode(c, bn); if (lc != nil) { let tn: *node = lc.tnode; - let lkind: i32 = -1; + let lkind: nkind = nkind.N_NONE; if (tn != nil) { lkind = tn.kind; }; // Pointer-to-struct: deref then store. if (lkind == nkind.N_TPTR) { @@ -7114,7 +7125,7 @@ fn cgassign(c: *cgen, n: *node) void = { if (delta >= 0) { if (lkind == nkind.N_TPTR) { let inner: *node = tn.lhs; - let innerkind: i32 = -1; + let innerkind: nkind = nkind.N_NONE; if (inner != nil) { innerkind = inner.kind; }; let innerstr: bool = false; if (innerkind == nkind.N_TNAME) { @@ -7322,7 +7333,7 @@ use strconv; fn cgstmt(c: *cgen, n: *node) void = { if (n == nil) { return; }; - let k: i32 = n.kind; + let k: nkind = n.kind; if (k == nkind.N_BLOCK) { cgblock(c, n); return; }; @@ -8306,8 +8317,11 @@ export fn cgfile(c: *cgen, file: *node) void = { c.strlits = nil; c.strlitseq = 0; collectaliases(c, file); - collectstructs(c, file); + // Enums must register before structs — fieldsize on a tkind-typed + // field needs the enum's storage size, otherwise it falls back to + // 8 (wrong load width). collectenums(c, file); + collectstructs(c, file); collectdefs(c, file); collectfnrets(c, file); fficollect(c, file); @@ -8417,7 +8431,7 @@ fn aliaslookup(c: *cgen, name: str) *node = { fn enumevalmember(prev: *enummember, e: *node, out: *u64) bool = { if (e == nil) { return false; }; - let k: i32 = e.kind; + let k: nkind = e.kind; if (k == nkind.N_INTLIT) { *out = e.uval; return true; }; if (k == nkind.N_RUNELIT) { *out = e.uval; return true; }; if (k == nkind.N_TRUE) { *out = 1u64; return true; }; @@ -8438,7 +8452,7 @@ fn enumevalmember(prev: *enummember, e: *node, out: *u64) bool = { let b: u64; if (!enumevalmember(prev, e.lhs, &a)) { return false; }; if (!enumevalmember(prev, e.rhs, &b)) { return false; }; - let op: i32 = e.op; + let op: tkind = e.op; if (op == tkind.TK_PLUS) { *out = a + b; return true; }; if (op == tkind.TK_MINUS) { *out = a - b; return true; }; if (op == tkind.TK_STAR) { *out = a * b; return true; }; @@ -8460,7 +8474,7 @@ fn enumevalmember(prev: *enummember, e: *node, out: *u64) bool = { if (k == nkind.N_UN) { let v: u64; if (!enumevalmember(prev, e.lhs, &v)) { return false; }; - let op: i32 = e.op; + let op: tkind = e.op; if (op == tkind.TK_MINUS) { *out = (-(v: i64)): u64; return true; }; if (op == tkind.TK_TILDE) { *out = ~v; return true; }; if (op == tkind.TK_PLUS) { *out = v; return true; }; diff --git a/selfhost/cmd/wcc/cgen.ww b/selfhost/cmd/wcc/cgen.ww index 92267ad6..065c2859 100644 --- a/selfhost/cmd/wcc/cgen.ww +++ b/selfhost/cmd/wcc/cgen.ww @@ -89,7 +89,7 @@ fn aliaslookup(c: *cgen, name: str) *node = { fn enumevalmember(prev: *enummember, e: *node, out: *u64) bool = { if (e == nil) { return false; }; - let k: i32 = e.kind; + let k: nkind = e.kind; if (k == nkind.N_INTLIT) { *out = e.uval; return true; }; if (k == nkind.N_RUNELIT) { *out = e.uval; return true; }; if (k == nkind.N_TRUE) { *out = 1u64; return true; }; @@ -110,7 +110,7 @@ fn enumevalmember(prev: *enummember, e: *node, out: *u64) bool = { let b: u64; if (!enumevalmember(prev, e.lhs, &a)) { return false; }; if (!enumevalmember(prev, e.rhs, &b)) { return false; }; - let op: i32 = e.op; + let op: tkind = e.op; if (op == tkind.TK_PLUS) { *out = a + b; return true; }; if (op == tkind.TK_MINUS) { *out = a - b; return true; }; if (op == tkind.TK_STAR) { *out = a * b; return true; }; @@ -132,7 +132,7 @@ fn enumevalmember(prev: *enummember, e: *node, out: *u64) bool = { if (k == nkind.N_UN) { let v: u64; if (!enumevalmember(prev, e.lhs, &v)) { return false; }; - let op: i32 = e.op; + let op: tkind = e.op; if (op == tkind.TK_MINUS) { *out = (-(v: i64)): u64; return true; }; if (op == tkind.TK_TILDE) { *out = ~v; return true; }; if (op == tkind.TK_PLUS) { *out = v; return true; }; diff --git a/selfhost/cmd/wcc/cgendecl.ww b/selfhost/cmd/wcc/cgendecl.ww index 498e3a68..0e859d98 100644 --- a/selfhost/cmd/wcc/cgendecl.ww +++ b/selfhost/cmd/wcc/cgendecl.ww @@ -278,8 +278,11 @@ export fn cgfile(c: *cgen, file: *node) void = { c.strlits = nil; c.strlitseq = 0; collectaliases(c, file); - collectstructs(c, file); + // Enums must register before structs — fieldsize on a tkind-typed + // field needs the enum's storage size, otherwise it falls back to + // 8 (wrong load width). collectenums(c, file); + collectstructs(c, file); collectdefs(c, file); collectfnrets(c, file); fficollect(c, file); diff --git a/selfhost/cmd/wcc/cgenexpr.ww b/selfhost/cmd/wcc/cgenexpr.ww index ee321aa7..a8476962 100644 --- a/selfhost/cmd/wcc/cgenexpr.ww +++ b/selfhost/cmd/wcc/cgenexpr.ww @@ -22,7 +22,7 @@ use strconv; fn cgexpr(c: *cgen, n: *node) void = { if (n == nil) { return; }; - let k: i32 = n.kind; + let k: nkind = n.kind; if (k == nkind.N_INTLIT) { // Print signed (i64), not unsigned (u64). C cgen uses @@ -257,7 +257,7 @@ fn cgtypetest(c: *cgen, n: *node) void = { // through the cast pass-through too). fn isenumexpr(c: *cgen, e: *node) bool = { if (e == nil) { return false; }; - let k: i32 = e.kind; + let k: nkind = e.kind; if (k == nkind.N_DOT) { if (e.lhs != nil) { if (e.lhs.kind == nkind.N_IDENT) { @@ -650,7 +650,7 @@ fn cgdot(c: *cgen, n: *node) void = { let lc: *local = localfindnode(c, nm); if (lc != nil) { let tn: *node = lc.tnode; - let lkind: i32 = -1; + let lkind: nkind = nkind.N_NONE; if (tn != nil) { lkind = tn.kind; }; // Pointer-to-struct: deref then field load. if (lkind == nkind.N_TPTR) { @@ -807,7 +807,7 @@ fn cgdot(c: *cgen, n: *node) void = { // pointed-to header. C cgen does the same. if (lkind == nkind.N_TPTR) { let inner: *node = tn.lhs; - let innerkind: i32 = -1; + let innerkind: nkind = nkind.N_NONE; if (inner != nil) { innerkind = inner.kind; }; let innerstr: bool = false; if (innerkind == nkind.N_TNAME) { @@ -1071,7 +1071,7 @@ fn cgcall(c: *cgen, n: *node) void = { if (lc != nil) { let tn: *node = lc.tnode; if (tn != nil) { - let lkind: i32 = tn.kind; + let lkind: nkind = tn.kind; let sname: str; sname.ptr = nil; sname.len = 0; if (lkind == nkind.N_TNAME) { sname = tn.str; }; @@ -1291,7 +1291,7 @@ fn cgassign(c: *cgen, n: *node) void = { let lc: *local = localfindnode(c, bn); if (lc != nil) { let tn: *node = lc.tnode; - let lkind: i32 = -1; + let lkind: nkind = nkind.N_NONE; if (tn != nil) { lkind = tn.kind; }; // Pointer-to-struct: deref then store. if (lkind == nkind.N_TPTR) { @@ -1397,7 +1397,7 @@ fn cgassign(c: *cgen, n: *node) void = { if (delta >= 0) { if (lkind == nkind.N_TPTR) { let inner: *node = tn.lhs; - let innerkind: i32 = -1; + let innerkind: nkind = nkind.N_NONE; if (inner != nil) { innerkind = inner.kind; }; let innerstr: bool = false; if (innerkind == nkind.N_TNAME) { diff --git a/selfhost/cmd/wcc/cgenstmt.ww b/selfhost/cmd/wcc/cgenstmt.ww index e2654bb2..2e47a08a 100644 --- a/selfhost/cmd/wcc/cgenstmt.ww +++ b/selfhost/cmd/wcc/cgenstmt.ww @@ -20,7 +20,7 @@ use strconv; fn cgstmt(c: *cgen, n: *node) void = { if (n == nil) { return; }; - let k: i32 = n.kind; + let k: nkind = n.kind; if (k == nkind.N_BLOCK) { cgblock(c, n); return; }; diff --git a/selfhost/cmd/wcc/cgenutil.ww b/selfhost/cmd/wcc/cgenutil.ww index cb38129b..41768e0f 100644 --- a/selfhost/cmd/wcc/cgenutil.ww +++ b/selfhost/cmd/wcc/cgenutil.ww @@ -153,7 +153,7 @@ fn pushargsrev(c: *cgen, arg: *node) i32 = { fn nodeisslice(c: *cgen, n: *node) bool = { if (n == nil) { return false; }; - let k: i32 = n.kind; + let k: nkind = n.kind; if (k == nkind.N_IDENT) { let nm: str = n.str; let lc: *local = localfindnode(c, nm); @@ -169,7 +169,7 @@ fn nodeisslice(c: *cgen, n: *node) bool = { // (str args take two slots: ptr + len). fn nodeisstr(c: *cgen, n: *node) bool = { if (n == nil) { return false; }; - let k: i32 = n.kind; + let k: nkind = n.kind; if (k == nkind.N_STRLIT) { return true; }; if (k == nkind.N_IDENT) { let nm: str = n.str; @@ -210,7 +210,7 @@ fn nodeisstr(c: *cgen, n: *node) bool = { let lc: *local = localfindnode(c, base.str); if (lc != nil) { let tn: *node = lc.tnode; - let lkind: i32 = -1; + let lkind: nkind = nkind.N_NONE; if (tn != nil) { lkind = tn.kind; }; if (lkind == nkind.N_TNAME) { sname = tn.str; }; if (lkind == nkind.N_TPTR) { @@ -279,7 +279,7 @@ fn typenodeisunsigned(t: *node) bool = { // false here even when their *slot* rounds up to 8. fn typeis8byteprimitive(c: *cgen, t: *node) bool = { if (t == nil) { return false; }; - let k: i32 = t.kind; + let k: nkind = t.kind; if (k == nkind.N_TPTR) { return true; }; if (k == nkind.N_TFN) { return true; }; if (k == nkind.N_TCHAN) { return true; }; @@ -371,7 +371,7 @@ fn indexbaseesz(c: *cgen, base: *node) i32 = { }; // Generic struct field: if it's *T, element size is T's size. - let lkind: i32 = tn.kind; + let lkind: nkind = tn.kind; let sname: str; sname.ptr = nil; sname.len = 0; if (lkind == nkind.N_TNAME) { sname = tn.str; }; @@ -470,7 +470,7 @@ fn dotinnerstructptr(c: *cgen, n: *node) *node = { // bool/str-byte, 8 otherwise — same shape as C cgen's esz fallback). fn elemsizeof(t: *node) i32 = { if (t == nil) { return 1; }; - let k: i32 = t.kind; + let k: nkind = t.kind; let elem: *node = nil; if (k == nkind.N_TPTR) { elem = t.lhs; }; if (k == nkind.N_TSLICE) { elem = t.lhs; }; @@ -506,7 +506,7 @@ fn elemsizeof(t: *node) i32 = { // being wrong here is byte-different asm vs C, not bad runtime. fn nodeisunsigned(c: *cgen, n: *node) bool = { if (n == nil) { return false; }; - let k: i32 = n.kind; + let k: nkind = n.kind; if (k == nkind.N_IDENT) { let nm: str = n.str; let lc: *local = localfindnode(c, nm); @@ -522,7 +522,7 @@ fn nodeisunsigned(c: *cgen, n: *node) bool = { let lc: *local = localfindnode(c, bn); if (lc != nil) { let tn: *node = lc.tnode; - let lkind: i32 = -1; + let lkind: nkind = nkind.N_NONE; if (tn != nil) { lkind = tn.kind; }; let sname: str; sname.ptr = nil; sname.len = 0; @@ -684,7 +684,7 @@ export fn letslotsize(c: *cgen, n: *node) i32 = { fn slotsize(c: *cgen, typn: *node) i32 = { if (typn == nil) { return 8; }; - let k: i32 = typn.kind; + let k: nkind = typn.kind; if (k == nkind.N_TPTR) { return 8; }; if (k == nkind.N_TFN) { return 8; }; if (k == nkind.N_TCHAN) { return 8; }; @@ -771,7 +771,7 @@ fn slotsize(c: *cgen, typn: *node) i32 = { // only round to 8 for stack slots, not struct interiors). fn fieldsize(c: *cgen, tnode: *node) i32 = { if (tnode == nil) { return 8; }; - let k: i32 = tnode.kind; + let k: nkind = tnode.kind; if (k == nkind.N_TNAME) { let nm: str = tnode.str; if (streq(nm, "str")) { return 16; }; @@ -779,6 +779,18 @@ fn fieldsize(c: *cgen, tnode: *node) i32 = { if (ps > 0) { return ps; }; let si: *structinfo = structlookup(c, nm); if (si != nil) { return si.totsize; }; + // Enum: size of its storage type. Mirrors the C cgen, which + // reads Type.size off the TY_ENUM (which inherits from .sub). + let en: *enumtype = enumlookup(c, nm); + if (en != nil) { + if (en.storage != nil) { + if (en.storage.kind == nkind.N_TNAME) { + let sps: i32 = primsize(en.storage.str); + if (sps > 0) { return sps; }; + }; + }; + return 4; // default storage is i32 + }; return 8; }; if (k == nkind.N_TPTR) { return 8; }; diff --git a/selfhost/cmd/wcc/check.ww b/selfhost/cmd/wcc/check.ww index dd42bb00..f5d1fb98 100644 --- a/selfhost/cmd/wcc/check.ww +++ b/selfhost/cmd/wcc/check.ww @@ -68,7 +68,7 @@ fn seedprimitives(c: *checker) void = { // the name so forward references resolve. fn installdecl(c: *checker, d: *node) void = { if (d == nil) { return; }; - let k: i32 = d.kind; + let k: nkind = d.kind; let nm: str = d.str; if (k == nkind.N_USE) { scopedefine(c.top, nm, skind.SK_USE, nil, d); return; }; if (k == nkind.N_DEF) { scopedefine(c.top, nm, skind.SK_DEF, nil, d); return; }; @@ -87,7 +87,7 @@ fn installdecl(c: *checker, d: *node) void = { // the same pass — they need the same scope state. fn resolvewalk(c: *checker, n: *node) void = { if (n == nil) { return; }; - let k: i32 = n.kind; + let k: nkind = n.kind; // Typed checks fire on the way down so the scrutinee/operand // is examined before the arm bodies install new bindings. @@ -253,7 +253,7 @@ fn typeeqast(a: *node, b: *node) bool = { if (aa == nil) { return bb == nil; }; if (bb == nil) { return false; }; if (aa.kind != bb.kind) { return false; }; - let k: i32 = aa.kind; + let k: nkind = aa.kind; if (k == nkind.N_TNAME) { return streq(aa.str, bb.str); }; if (k == nkind.N_TPTR) { return typeeqast(aa.lhs, bb.lhs); }; if (k == nkind.N_TSLICE){ return typeeqast(aa.lhs, bb.lhs); }; @@ -342,7 +342,7 @@ fn mktname(c: *checker, nm: str) *node = { // field access into non-primitive types, etc). fn exprtype(c: *checker, e: *node) *node = { if (e == nil) { return nil; }; - let k: i32 = e.kind; + let k: nkind = e.kind; if (k == nkind.N_INTLIT) { return mktname(c, "untyped_int"); }; if (k == nkind.N_FLOATLIT) { return mktname(c, "untyped_float"); }; if (k == nkind.N_STRLIT) { return mktname(c, "str"); }; @@ -900,7 +900,7 @@ export fn checkfile(c: *checker, file: *node) void = { // Pass 2: walk decl bodies/types and resolve identifiers. d = file.list; for (d != nil) { - let k: i32 = d.kind; + let k: nkind = d.kind; if (k == nkind.N_FNDECL) { if (d.lhs != nil) { resolvewalk(c, d.lhs); }; // return type resolvefnbody(c, d); diff --git a/selfhost/cmd/wwdump/main.combined.ww b/selfhost/cmd/wwdump/main.combined.ww index 238b4a14..c0c936b8 100644 --- a/selfhost/cmd/wwdump/main.combined.ww +++ b/selfhost/cmd/wwdump/main.combined.ww @@ -581,8 +581,7 @@ type pos = struct { }; type tok = struct { - kind: i32, // holds a `tkind` value; bare i32 so the cgen's - // fixed 8B/struct-field layout matches the C side + kind: tkind, file: str, // path of the source the token came from line: i32, col: i32, @@ -607,7 +606,7 @@ fn streqn(a: *u8, b: str, n: i32) bool = { // kwlookup — returns the matching TK_* keyword kind for a byte run, // or tkind.TK_NONE if it's an ordinary identifier. Linear search over a // small alphabetised list, matching cmd/wcc/tok.c. -export fn kwlookup(p: *u8, n: i32) i32 = { +export fn kwlookup(p: *u8, n: i32) tkind = { if (streqn(p, "as", n)) { return tkind.TK_AS; }; if (streqn(p, "break", n)) { return tkind.TK_BREAK; }; if (streqn(p, "case", n)) { return tkind.TK_CASE; }; @@ -645,7 +644,7 @@ export fn kwlookup(p: *u8, n: i32) i32 = { // Returns the canonical printable spelling for a token kind. Matches // the C tokname()'s output exactly so wwdump output diffs cleanly. -export fn tokname(k: i32) str = { +export fn tokname(k: tkind) str = { if (k == tkind.TK_NONE) { return ""; }; if (k == tkind.TK_EOF) { return "EOF"; }; if (k == tkind.TK_ERR) { return "ERR"; }; @@ -1421,7 +1420,7 @@ fn lexident(l: *lex, start: *pos, out: *tok) void = { return; }; }; - let k: i32 = kwlookup(p, n: i32); + let k: tkind = kwlookup(p, n: i32); if (k != tkind.TK_NONE) { out.kind = k; } else { @@ -1514,7 +1513,7 @@ fn lexrune(l: *lex, start: *pos, out: *tok) void = { out.uval = ch: u64; }; -fn emitsimple(start: *pos, k: i32, out: *tok) void = { +fn emitsimple(start: *pos, k: tkind, out: *tok) void = { out.kind = k; out.file = start.file; out.line = start.line; @@ -1766,11 +1765,11 @@ type nkind = enum i32 { // ---- Node ------------------------------------------------------------- type node = struct { - kind: i32, + kind: nkind, file: str, line: i32, col: i32, - op: i32, // for nkind.N_BIN / nkind.N_UN / nkind.N_ASSIGN + op: tkind, // for nkind.N_BIN / nkind.N_UN / nkind.N_ASSIGN str: str, uval: u64, fval: f64, @@ -1788,7 +1787,7 @@ type node = struct { module: str, // originating module from `// MODULE: foo`; "" if none }; -export fn newnode(a: *arena, k: i32, file: str, line: i32, col: i32) *node = { +export fn newnode(a: *arena, k: nkind, file: str, line: i32, col: i32) *node = { let n: *node = amalloc(a, 208u64): *node; // ≥ struct size n.kind = k; n.file = file; @@ -1799,7 +1798,7 @@ export fn newnode(a: *arena, k: i32, file: str, line: i32, col: i32) *node = { // ---- printer ---------------------------------------------------------- -fn nkname(k: i32) str = { +fn nkname(k: nkind) str = { if (k == nkind.N_NONE) { return "none"; }; if (k == nkind.N_INTLIT) { return "int"; }; if (k == nkind.N_FLOATLIT) { return "float"; }; @@ -2222,7 +2221,7 @@ fn parseprimary(p: *parser) *node = { return newnode(p.a, nkind.N_NONE, pf, pl, pc); }; -fn parsearglist(p: *parser, closekind: i32, headout: **node) void = { +fn parsearglist(p: *parser, closekind: tkind, headout: **node) void = { *headout = nil; if (p.curkind == closekind) { return; }; let head: *node = nil; @@ -2378,7 +2377,7 @@ fn parseunary(p: *parser) *node = { let pf: str = p.curfile; let pl: i32 = p.curline; let pc: i32 = p.curcol; - let k: i32 = p.curkind; + let k: tkind = p.curkind; if (k == tkind.TK_MINUS) { advance(p); let n: *node = newnode(p.a, nkind.N_UN, pf, pl, pc); @@ -2421,7 +2420,7 @@ fn parseunary(p: *parser) *node = { fn parsebin(p: *parser, lhs: *node, minp: i32) *node = { let cur: *node = lhs; for (true) { - let op: i32 = p.curkind; + let op: tkind = p.curkind; let pr: i32 = bprec(op); if (pr == 0) { return cur; }; if (pr < minp) { return cur; }; @@ -2448,7 +2447,7 @@ fn parseexpr(p: *parser) *node = { let pf: str = p.curfile; let pl: i32 = p.curline; let pc: i32 = p.curcol; - let op: i32 = p.curkind; + let op: tkind = p.curkind; advance(p); let n: *node = newnode(p.a, nkind.N_ASSIGN, pf, pl, pc); n.op = op; @@ -2933,7 +2932,7 @@ type parser = struct { // nocast: while inside `[...]` we treat ':' as the slice // separator, not the cast operator. Mirrors parse.c's flag. nocast: i32, - curkind: i32, // holds a `tkind` value (relaxation lets it mix) + curkind: tkind, curfile: str, curline: i32, curcol: i32, @@ -2962,7 +2961,7 @@ export fn parserinit(p: *parser, a: *arena, l: *lex) void = { fn advance(p: *parser) void = { refill(p); }; -fn accepttok(p: *parser, k: i32) bool = { +fn accepttok(p: *parser, k: tkind) bool = { if (p.curkind == k) { advance(p); return true; }; return false; }; @@ -2975,7 +2974,7 @@ fn errmsg(p: *parser, msg: str) void = { p.errs += 1; }; -fn expecttok(p: *parser, k: i32, what: str) bool = { +fn expecttok(p: *parser, k: tkind, what: str) bool = { if (p.curkind == k) { advance(p); return true; }; errmsg(p, what); return false; @@ -3222,7 +3221,7 @@ fn parsetype(p: *parser) *node = { // and the ?/! try operators are not yet wired — they'll arrive as the // AST diff fixture grows to need them. -fn bprec(k: i32) i32 = { +fn bprec(k: tkind) i32 = { if (k == tkind.TK_OR) { return 1; }; if (k == tkind.TK_AND) { return 2; }; if (k == tkind.TK_EQ) { return 3; }; @@ -3244,7 +3243,7 @@ fn bprec(k: i32) i32 = { return 0; }; -fn isassignop(k: i32) bool = { +fn isassignop(k: tkind) bool = { if (k == tkind.TK_ASSIGN) { return true; }; if (k == tkind.TK_PLUSEQ) { return true; }; if (k == tkind.TK_MINUSEQ) { return true; }; @@ -3402,7 +3401,7 @@ type tparam = struct { }; type tinfo = struct { - kind: i32, + kind: tykind, size: u64, align: u64, sub: *tinfo, // ptr/slice/array/chan element @@ -3448,13 +3447,13 @@ type tctx = struct { // ---- constructors ----------------------------------------------------- -export fn newtype(a: *arena, k: i32) *tinfo = { +export fn newtype(a: *arena, k: tykind) *tinfo = { let t: *tinfo = amalloc(a, 96u64): *tinfo; t.kind = k; return t; }; -fn prim(a: *arena, k: i32, nm: str, sz: u64, al: u64) *tinfo = { +fn prim(a: *arena, k: tykind, nm: str, sz: u64, al: u64) *tinfo = { let t: *tinfo = newtype(a, k); t.name = nm; t.size = sz; @@ -3544,7 +3543,7 @@ export fn typenamed(a: *arena, name: str, under: *tinfo) *tinfo = { export fn typeisint(t: *tinfo) bool = { if (t == nil) { return false; }; - let k: i32 = t.kind; + let k: tykind = t.kind; if (k == tykind.TY_I8) { return true; }; if (k == tykind.TY_I16) { return true; }; if (k == tykind.TY_I32) { return true; }; @@ -3566,7 +3565,7 @@ export fn typeisint(t: *tinfo) bool = { export fn typeisfloat(t: *tinfo) bool = { if (t == nil) { return false; }; - let k: i32 = t.kind; + let k: tykind = t.kind; if (k == tykind.TY_F32) { return true; }; if (k == tykind.TY_F64) { return true; }; if (k == tykind.TY_UNTYPED_FLOAT) { return true; }; @@ -3581,7 +3580,7 @@ export fn typeisnum(t: *tinfo) bool = { export fn typeisunsigned(t: *tinfo) bool = { if (t == nil) { return false; }; - let k: i32 = t.kind; + let k: tykind = t.kind; if (k == tykind.TY_U8) { return true; }; if (k == tykind.TY_U16) { return true; }; if (k == tykind.TY_U32) { return true; }; @@ -3594,7 +3593,7 @@ export fn typeisunsigned(t: *tinfo) bool = { export fn typeisuntyped(t: *tinfo) bool = { if (t == nil) { return false; }; - let k: i32 = t.kind; + let k: tykind = t.kind; if (k == tykind.TY_UNTYPED_INT) { return true; }; if (k == tykind.TY_UNTYPED_FLOAT) { return true; }; if (k == tykind.TY_UNTYPED_STR) { return true; }; @@ -3610,7 +3609,7 @@ export fn typeeq(a: *tinfo, b: *tinfo) bool = { if (a == nil) { return false; }; if (b == nil) { return false; }; if (a.kind != b.kind) { return false; }; - let k: i32 = a.kind; + let k: tykind = a.kind; if (k == tykind.TY_PTR) { return typeeq(a.sub, b.sub); }; if (k == tykind.TY_SLICE) { return typeeq(a.sub, b.sub); }; if (k == tykind.TY_CHAN) { return typeeq(a.sub, b.sub); }; @@ -3693,7 +3692,7 @@ type skind = enum i32 { type sym = struct { name: str, - skind: i32, + skind: skind, type_: *tinfo, decl: *node, exported: i32, @@ -3769,7 +3768,7 @@ export fn scopelookup(s: *scope, name: str) *sym = { return nil; }; -export fn scopedefine(s: *scope, name: str, k: i32, t: *tinfo, decl: *node) *sym = { +export fn scopedefine(s: *scope, name: str, k: skind, t: *tinfo, decl: *node) *sym = { if (scopelookuplocal(s, name) != nil) { return nil; }; let sy: *sym = amalloc(s.a, 80u64): *sym; sy.name = name; @@ -3857,7 +3856,7 @@ fn seedprimitives(c: *checker) void = { // the name so forward references resolve. fn installdecl(c: *checker, d: *node) void = { if (d == nil) { return; }; - let k: i32 = d.kind; + let k: nkind = d.kind; let nm: str = d.str; if (k == nkind.N_USE) { scopedefine(c.top, nm, skind.SK_USE, nil, d); return; }; if (k == nkind.N_DEF) { scopedefine(c.top, nm, skind.SK_DEF, nil, d); return; }; @@ -3876,7 +3875,7 @@ fn installdecl(c: *checker, d: *node) void = { // the same pass — they need the same scope state. fn resolvewalk(c: *checker, n: *node) void = { if (n == nil) { return; }; - let k: i32 = n.kind; + let k: nkind = n.kind; // Typed checks fire on the way down so the scrutinee/operand // is examined before the arm bodies install new bindings. @@ -4042,7 +4041,7 @@ fn typeeqast(a: *node, b: *node) bool = { if (aa == nil) { return bb == nil; }; if (bb == nil) { return false; }; if (aa.kind != bb.kind) { return false; }; - let k: i32 = aa.kind; + let k: nkind = aa.kind; if (k == nkind.N_TNAME) { return streq(aa.str, bb.str); }; if (k == nkind.N_TPTR) { return typeeqast(aa.lhs, bb.lhs); }; if (k == nkind.N_TSLICE){ return typeeqast(aa.lhs, bb.lhs); }; @@ -4131,7 +4130,7 @@ fn mktname(c: *checker, nm: str) *node = { // field access into non-primitive types, etc). fn exprtype(c: *checker, e: *node) *node = { if (e == nil) { return nil; }; - let k: i32 = e.kind; + let k: nkind = e.kind; if (k == nkind.N_INTLIT) { return mktname(c, "untyped_int"); }; if (k == nkind.N_FLOATLIT) { return mktname(c, "untyped_float"); }; if (k == nkind.N_STRLIT) { return mktname(c, "str"); }; @@ -4689,7 +4688,7 @@ export fn checkfile(c: *checker, file: *node) void = { // Pass 2: walk decl bodies/types and resolve identifiers. d = file.list; for (d != nil) { - let k: i32 = d.kind; + let k: nkind = d.kind; if (k == nkind.N_FNDECL) { if (d.lhs != nil) { resolvewalk(c, d.lhs); }; // return type resolvefnbody(c, d); @@ -4863,7 +4862,7 @@ fn pushargsrev(c: *cgen, arg: *node) i32 = { fn nodeisslice(c: *cgen, n: *node) bool = { if (n == nil) { return false; }; - let k: i32 = n.kind; + let k: nkind = n.kind; if (k == nkind.N_IDENT) { let nm: str = n.str; let lc: *local = localfindnode(c, nm); @@ -4879,7 +4878,7 @@ fn nodeisslice(c: *cgen, n: *node) bool = { // (str args take two slots: ptr + len). fn nodeisstr(c: *cgen, n: *node) bool = { if (n == nil) { return false; }; - let k: i32 = n.kind; + let k: nkind = n.kind; if (k == nkind.N_STRLIT) { return true; }; if (k == nkind.N_IDENT) { let nm: str = n.str; @@ -4920,7 +4919,7 @@ fn nodeisstr(c: *cgen, n: *node) bool = { let lc: *local = localfindnode(c, base.str); if (lc != nil) { let tn: *node = lc.tnode; - let lkind: i32 = -1; + let lkind: nkind = nkind.N_NONE; if (tn != nil) { lkind = tn.kind; }; if (lkind == nkind.N_TNAME) { sname = tn.str; }; if (lkind == nkind.N_TPTR) { @@ -4989,7 +4988,7 @@ fn typenodeisunsigned(t: *node) bool = { // false here even when their *slot* rounds up to 8. fn typeis8byteprimitive(c: *cgen, t: *node) bool = { if (t == nil) { return false; }; - let k: i32 = t.kind; + let k: nkind = t.kind; if (k == nkind.N_TPTR) { return true; }; if (k == nkind.N_TFN) { return true; }; if (k == nkind.N_TCHAN) { return true; }; @@ -5081,7 +5080,7 @@ fn indexbaseesz(c: *cgen, base: *node) i32 = { }; // Generic struct field: if it's *T, element size is T's size. - let lkind: i32 = tn.kind; + let lkind: nkind = tn.kind; let sname: str; sname.ptr = nil; sname.len = 0; if (lkind == nkind.N_TNAME) { sname = tn.str; }; @@ -5180,7 +5179,7 @@ fn dotinnerstructptr(c: *cgen, n: *node) *node = { // bool/str-byte, 8 otherwise — same shape as C cgen's esz fallback). fn elemsizeof(t: *node) i32 = { if (t == nil) { return 1; }; - let k: i32 = t.kind; + let k: nkind = t.kind; let elem: *node = nil; if (k == nkind.N_TPTR) { elem = t.lhs; }; if (k == nkind.N_TSLICE) { elem = t.lhs; }; @@ -5216,7 +5215,7 @@ fn elemsizeof(t: *node) i32 = { // being wrong here is byte-different asm vs C, not bad runtime. fn nodeisunsigned(c: *cgen, n: *node) bool = { if (n == nil) { return false; }; - let k: i32 = n.kind; + let k: nkind = n.kind; if (k == nkind.N_IDENT) { let nm: str = n.str; let lc: *local = localfindnode(c, nm); @@ -5232,7 +5231,7 @@ fn nodeisunsigned(c: *cgen, n: *node) bool = { let lc: *local = localfindnode(c, bn); if (lc != nil) { let tn: *node = lc.tnode; - let lkind: i32 = -1; + let lkind: nkind = nkind.N_NONE; if (tn != nil) { lkind = tn.kind; }; let sname: str; sname.ptr = nil; sname.len = 0; @@ -5394,7 +5393,7 @@ export fn letslotsize(c: *cgen, n: *node) i32 = { fn slotsize(c: *cgen, typn: *node) i32 = { if (typn == nil) { return 8; }; - let k: i32 = typn.kind; + let k: nkind = typn.kind; if (k == nkind.N_TPTR) { return 8; }; if (k == nkind.N_TFN) { return 8; }; if (k == nkind.N_TCHAN) { return 8; }; @@ -5481,7 +5480,7 @@ fn slotsize(c: *cgen, typn: *node) i32 = { // only round to 8 for stack slots, not struct interiors). fn fieldsize(c: *cgen, tnode: *node) i32 = { if (tnode == nil) { return 8; }; - let k: i32 = tnode.kind; + let k: nkind = tnode.kind; if (k == nkind.N_TNAME) { let nm: str = tnode.str; if (streq(nm, "str")) { return 16; }; @@ -5489,6 +5488,18 @@ fn fieldsize(c: *cgen, tnode: *node) i32 = { if (ps > 0) { return ps; }; let si: *structinfo = structlookup(c, nm); if (si != nil) { return si.totsize; }; + // Enum: size of its storage type. Mirrors the C cgen, which + // reads Type.size off the TY_ENUM (which inherits from .sub). + let en: *enumtype = enumlookup(c, nm); + if (en != nil) { + if (en.storage != nil) { + if (en.storage.kind == nkind.N_TNAME) { + let sps: i32 = primsize(en.storage.str); + if (sps > 0) { return sps; }; + }; + }; + return 4; // default storage is i32 + }; return 8; }; if (k == nkind.N_TPTR) { return 8; }; @@ -5739,7 +5750,7 @@ use strconv; fn cgexpr(c: *cgen, n: *node) void = { if (n == nil) { return; }; - let k: i32 = n.kind; + let k: nkind = n.kind; if (k == nkind.N_INTLIT) { // Print signed (i64), not unsigned (u64). C cgen uses @@ -5974,7 +5985,7 @@ fn cgtypetest(c: *cgen, n: *node) void = { // through the cast pass-through too). fn isenumexpr(c: *cgen, e: *node) bool = { if (e == nil) { return false; }; - let k: i32 = e.kind; + let k: nkind = e.kind; if (k == nkind.N_DOT) { if (e.lhs != nil) { if (e.lhs.kind == nkind.N_IDENT) { @@ -6367,7 +6378,7 @@ fn cgdot(c: *cgen, n: *node) void = { let lc: *local = localfindnode(c, nm); if (lc != nil) { let tn: *node = lc.tnode; - let lkind: i32 = -1; + let lkind: nkind = nkind.N_NONE; if (tn != nil) { lkind = tn.kind; }; // Pointer-to-struct: deref then field load. if (lkind == nkind.N_TPTR) { @@ -6524,7 +6535,7 @@ fn cgdot(c: *cgen, n: *node) void = { // pointed-to header. C cgen does the same. if (lkind == nkind.N_TPTR) { let inner: *node = tn.lhs; - let innerkind: i32 = -1; + let innerkind: nkind = nkind.N_NONE; if (inner != nil) { innerkind = inner.kind; }; let innerstr: bool = false; if (innerkind == nkind.N_TNAME) { @@ -6788,7 +6799,7 @@ fn cgcall(c: *cgen, n: *node) void = { if (lc != nil) { let tn: *node = lc.tnode; if (tn != nil) { - let lkind: i32 = tn.kind; + let lkind: nkind = tn.kind; let sname: str; sname.ptr = nil; sname.len = 0; if (lkind == nkind.N_TNAME) { sname = tn.str; }; @@ -7008,7 +7019,7 @@ fn cgassign(c: *cgen, n: *node) void = { let lc: *local = localfindnode(c, bn); if (lc != nil) { let tn: *node = lc.tnode; - let lkind: i32 = -1; + let lkind: nkind = nkind.N_NONE; if (tn != nil) { lkind = tn.kind; }; // Pointer-to-struct: deref then store. if (lkind == nkind.N_TPTR) { @@ -7114,7 +7125,7 @@ fn cgassign(c: *cgen, n: *node) void = { if (delta >= 0) { if (lkind == nkind.N_TPTR) { let inner: *node = tn.lhs; - let innerkind: i32 = -1; + let innerkind: nkind = nkind.N_NONE; if (inner != nil) { innerkind = inner.kind; }; let innerstr: bool = false; if (innerkind == nkind.N_TNAME) { @@ -7322,7 +7333,7 @@ use strconv; fn cgstmt(c: *cgen, n: *node) void = { if (n == nil) { return; }; - let k: i32 = n.kind; + let k: nkind = n.kind; if (k == nkind.N_BLOCK) { cgblock(c, n); return; }; @@ -8306,8 +8317,11 @@ export fn cgfile(c: *cgen, file: *node) void = { c.strlits = nil; c.strlitseq = 0; collectaliases(c, file); - collectstructs(c, file); + // Enums must register before structs — fieldsize on a tkind-typed + // field needs the enum's storage size, otherwise it falls back to + // 8 (wrong load width). collectenums(c, file); + collectstructs(c, file); collectdefs(c, file); collectfnrets(c, file); fficollect(c, file); @@ -8417,7 +8431,7 @@ fn aliaslookup(c: *cgen, name: str) *node = { fn enumevalmember(prev: *enummember, e: *node, out: *u64) bool = { if (e == nil) { return false; }; - let k: i32 = e.kind; + let k: nkind = e.kind; if (k == nkind.N_INTLIT) { *out = e.uval; return true; }; if (k == nkind.N_RUNELIT) { *out = e.uval; return true; }; if (k == nkind.N_TRUE) { *out = 1u64; return true; }; @@ -8438,7 +8452,7 @@ fn enumevalmember(prev: *enummember, e: *node, out: *u64) bool = { let b: u64; if (!enumevalmember(prev, e.lhs, &a)) { return false; }; if (!enumevalmember(prev, e.rhs, &b)) { return false; }; - let op: i32 = e.op; + let op: tkind = e.op; if (op == tkind.TK_PLUS) { *out = a + b; return true; }; if (op == tkind.TK_MINUS) { *out = a - b; return true; }; if (op == tkind.TK_STAR) { *out = a * b; return true; }; @@ -8460,7 +8474,7 @@ fn enumevalmember(prev: *enummember, e: *node, out: *u64) bool = { if (k == nkind.N_UN) { let v: u64; if (!enumevalmember(prev, e.lhs, &v)) { return false; }; - let op: i32 = e.op; + let op: tkind = e.op; if (op == tkind.TK_MINUS) { *out = (-(v: i64)): u64; return true; }; if (op == tkind.TK_TILDE) { *out = ~v; return true; }; if (op == tkind.TK_PLUS) { *out = v; return true; };