toolchain: banner purge + WHY-only comment sweep (rule 8)

selfhost/, cmd/, internal/ join the tree-wide sweep: every section
banner dies (91 selfhost + the cmd C-style dividers -> 0); narration
and stale contracts deleted (pre-#22 bundler notes, retired
single-PT_LOAD and no-archive claims, superseded ABI tables); every
ref/harec/qbe cite, task cite, encoding/ELF contract, and rule-10
twin pointer kept; lost lifetime/rationale lines restored where the
sweep over-cut (elf_globals ownership, kwtab linear-scan). Comment-
only proven: all five wwstage tool binaries byte-identical across
the sweep; test-commit, test-byteid (161+1399, 0 pinned-divergent),
and test-bootstrap (fixed point + 991-995 byte-id) all exit 0.
The read-through banked 66 latent-bug leads (checkpoint).
This commit is contained in:
2026-08-08 23:14:03 +09:00
parent 83f5956df2
commit 62b9d20383
60 changed files with 232 additions and 1045 deletions

View File

@@ -1,21 +1,4 @@
// selfhost/cmd/wcc/check.ww — minimal port of cmd/wcc/check.c.
//
// Status: name-resolution + primitive-type seeding only. Full type
// inference, conversion rules, tagged-union dispatch typing, return-
// type checking, etc. all live in cmd/wcc/check.c (937 lines) and
// will land here in subsequent commits.
//
// What this version does:
// 1. Creates a top scope and seeds it with primitive type names so
// `i32`, `str`, `*u8` etc. resolve.
// 2. Walks the file's top-level decls (use/def/type/fn/let) and
// installs Sym entries for each.
// 3. Recursively walks fn bodies; for every nkind.N_IDENT used as an
// expression or as a type name, looks it up and counts the
// resolved vs. unresolved.
// 4. Returns a summary the caller (wwdump -r) prints; the test
// asserts unresolved == 0 on every selfhost fixture, which is
// the floor signal that the frontend can name-resolve real ww.
// Port of cmd/wcc/check.c.
package wcc;
@@ -91,8 +74,6 @@ fn circularnamed(c: *checker, t: *syntax.tinfo, n: *syntax.node) bool = {
os.exit(1);
};
// seedprimitives — install the built-in type names so `i32`, `str`,
// etc. can be looked up like ordinary symbols.
fn seedprimitives(c: *checker) void = {
syntax.scopedefine(c.top, "void", syntax.skind.SK_TYPE, c.tc.tyvoid, nil);
syntax.scopedefine(c.top, "bool", syntax.skind.SK_TYPE, c.tc.tybool, nil);
@@ -822,8 +803,7 @@ fn resolvewalk(c: *checker, n: *syntax.node) void = {
// free identifier.
if (n.lhs != nil) { resolvewalk(c, n.lhs); };
// A.6.0: branch returns early; stamp here so the post-walk
// dispatch below sees N_DOT covered. exprtype N_DOT arm is
// added in A.6.1; for now this is a no-op nil return.
// dispatch below sees N_DOT covered.
let _t: *syntax.node = exprtype(c, n, nil);
return;
};
@@ -957,15 +937,12 @@ fn resolvewalk(c: *checker, n: *syntax.node) void = {
};
};
// ---- type-level helpers (AST-level, no resolved tinfo) --------------
//
// The selfhost check operates on AST type expressions rather than
// resolved Type structs. These helpers mirror what cmd/wcc/check.c
// does with tinfo, but only on the subset of cases this checker
// needs to enforce: tagged-union exhaustiveness, ? subset
// propagation, and !-flag semantics.
// unwrapbang — strip an nkind.N_TBANG wrapper; leaves other nodes alone.
fn unwrapbang(n: *syntax.node) *syntax.node = {
if (n == nil) { return nil; };
if (n.kind == syntax.nkind.N_TBANG) { return n.lhs; };
@@ -1050,10 +1027,6 @@ fn aliassym(c: *checker, n: *syntax.node) *syntax.sym = {
return s;
};
// resolvealias — if n is an nkind.N_TNAME pointing at a typedecl, return
// the typedecl's body (possibly recursively). Pass-through for any
// other node. The chain stops once we hit a non-nkind.N_TNAME node or a
// name we can't resolve.
fn resolvealias(c: *checker, n: *syntax.node) *syntax.node = {
let cur: *syntax.node = n;
for (cur != nil) {
@@ -1274,9 +1247,6 @@ fn scruttype(c: *checker, e: *syntax.node) *syntax.node = {
return nil;
};
// mktname — fabricate an nkind.N_TNAME node with str = `nm`. Used by
// exprtype to return primitive type nodes for literal
// expressions. The arena keeps them around as long as the checker.
fn mktname(c: *checker, nm: str) *syntax.node = {
let n: *syntax.node = syntax.newnode(syntax.nkind.N_TNAME, "", 0, 0);
n.str = nm;
@@ -4692,9 +4662,6 @@ fn exprtype(c: *checker, e: *syntax.node, hint: *syntax.node) *syntax.node = {
return nil;
};
// isuntypedint / is_str_like / is_bool_like — helpers used
// by the assignability check below to allow common AST shapes
// through without needing real type inference.
fn isuntypedint(t: *syntax.node) bool = {
if (t == nil) { return false; };
if (t.kind != syntax.nkind.N_TNAME) { return false; };
@@ -5386,14 +5353,10 @@ fn isassignable(c: *checker, dst: *syntax.node, src: *syntax.node, confident: *b
return true;
};
// ---- match exhaustiveness --------------------------------------------
//
// For every match arm, verify that every variant of the scrutinee's
// tagged-union type is handled by some case (or a default arm
// exists). Multi-pattern `case A | B =>` covers all alts.
// qualleaf — rightmost dotted segment of a (possibly module-qualified)
// type name; the whole name when unqualified.
fn qualleaf(nm: str) str = {
let dotidx: i32 = -1;
let i: i32 = 0;
@@ -5408,8 +5371,6 @@ fn qualleaf(nm: str) str = {
return leaf;
};
// qualmod — module qualifier of a type name (segment before the
// rightmost '.'), or `defmod` when unqualified.
fn qualmod(nm: str, defmod: str) str = {
let dotidx: i32 = -1;
let i: i32 = 0;
@@ -5646,8 +5607,6 @@ fn checkvariantcovered(c: *checker, n: *syntax.node, v: *syntax.node, unionmod:
if (!covered) { errmatchvariant(c, n, v); };
};
// ---- let init / return assignability --------------------------------
//
// AST-level approximation: when we can infer src's type and dst is
// explicitly declared, verify isassignable. We only emit an error
// when isassignable says "false with confidence." If we can't tell
@@ -6581,8 +6540,6 @@ fn checkretassign(c: *checker, n: *syntax.node) void = {
};
};
// ---- is / as validity ------------------------------------------------
//
// `e is T` and `e as T` require that e's declared type be a tagged
// union and that T name one of its variants. Operates on AST type
// expressions; falls back silently when we can't determine e's
@@ -6670,8 +6627,6 @@ fn checkisas(c: *checker, n: *syntax.node) void = {
c.errs += 1;
};
// ---- ? subset propagation --------------------------------------------
//
// For `expr?`, the operand's error subset must be a subset of the
// enclosing fn's return-type variants. Mirrors C check.c. Operand
// is nkind.N_TRYPROP or nkind.N_TRYUNW (the F8 cardinality gate covers
@@ -6836,9 +6791,6 @@ fn hascvariadic(params: *syntax.node) bool = {
return false;
};
// install_param — when entering a fn body, define its params in a
// fresh local scope.
//
// TODO(#11): cstage check.c (post-#32) errors `param '%s' redeclared`
// when two params share a name. The fn body's scope IS fresh here
// (resolvefnbody opens it before calling us), so guarding scopedefine's