selfhost/cmd/wcc: collapse signedness predicates onto n.type_ (A.6.3a, #45)

The node-keyed signedness helpers (typenodeisunsigned,
typenodeisunsignedc, elemissigned, elemissignedc, fieldissignedc) each
re-walked TBANG / TENUM / TNAME chains and re-consulted alias / enum
registries — duplicating cstage's type_isunsigned (cmd/wcc/type.c:178)
and fld_issigned (cmd/w6c/cgen.c:240) at the AST level. After A.6.2
every type-AST kind we read here is tinfo-stamped at check.ww L426-436,
so the predicates collapse to a single tinfo read.

Two new arms close the wwstage divergence from cstage: typeisunsigned
gains TY_RUNE and TY_ENUM (recurse on .sub), matching type.c:178
verbatim. typeissigned is added as the cgen-facing predicate per
fld_issigned semantics (TY_BOOL excluded for sub-word storage —
0/1 → MOVZBQ — so it's not just !typeisunsigned). Rule 9 carve-out:
the helper exists in cstage; harec keeps the same pair.

elemissigned was fully dead (no callers); deleted. typenameissigned
was internal-only and dead post-collapse; deleted. typenameisunsigned
survives — two call sites (typenodeprimresolved, exprprimresolved)
hold only a raw `str` (TNAME.str / INTLIT.tsuffix). paramissigned in
cgenstmt.ww unchanged. Both deferrals close in A.6.3c (#47).

Byte-identity (994/995) is the behavior gate for the alias/enum
sites — full `make test` green at 133/133 confirms.
This commit is contained in:
2026-05-22 05:24:49 +09:00
parent 045c49e398
commit 03e4718199
5 changed files with 180 additions and 312 deletions

View File

@@ -305,6 +305,10 @@ export fn typeisnum(t: *tinfo) bool = {
return typeisfloat(t);
};
// TY_RUNE is unsigned: Unicode codepoint (0..0x10FFFF) zero-extends on
// sub-word load (MOVL, not MOVSXD). TY_ENUM recurses on .sub so a
// `type k = enum u32 {…}` reads as unsigned. Cite cstage type.c:178
// `type_isunsigned`; rule 10 keeps wwstage aligned down to cstage.
export fn typeisunsigned(t: *tinfo) bool = {
if (t == nil) { return false; };
let k: tykind = t.kind;
@@ -314,10 +318,24 @@ export fn typeisunsigned(t: *tinfo) bool = {
if (k == tykind.TY_U64) { return true; };
if (k == tykind.TY_UINT){ return true; };
if (k == tykind.TY_UINTPTR) { return true; };
if (k == tykind.TY_RUNE){ return true; };
if (k == tykind.TY_NAMED) { return typeisunsigned(t.under); };
if (k == tykind.TY_ENUM) { return typeisunsigned(t.sub); };
return false;
};
// typeissigned — does this type need sign-extension on a sub-word
// (1/2/4B) load? Mirrors cstage cgen.c:240 `fld_issigned`. Cgen-facing
// predicate (TY_BOOL is unsigned for storage purposes — 0/1 → MOVZBQ),
// so it doesn't simply mirror `!typeisunsigned`. Pair-of-`is*`
// convention follows ref/hare/types/ helpers.
export fn typeissigned(t: *tinfo) bool = {
if (t == nil) { return false; };
if (t.kind == tykind.TY_BOOL) { return false; };
if (typeisunsigned(t)) { return false; };
return typeisint(t);
};
export fn typeisuntyped(t: *tinfo) bool = {
if (t == nil) { return false; };
let k: tykind = t.kind;