ww+wcc: Hare-strict enum types — back out the int↔enum relaxation
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.
This commit is contained in:
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user