selfhost/cmd/wcc: N_CALL intercepts for len/append/free (A.6.2.1b)

Three Hare pseudo-builtins (len/append/free) were resolving via the
generic N_CALL path and leaving e.type_ nil, blocking #15's post-
checker assertion. Add inline intercepts in exprtype that stamp e.type_
to mktname("i32")/mktname("void") and return the same tnode, matching
the cstage shape at cmd/wcc/check.c:896-1011 (rule 10 stage byte-id).

No shadow guard: cstage's len/append/free intercepts have none either,
and L85-88 seeds the names into c.top so a same-module decl dup-
silences. No arg-walk: resolvewalk descends children before dispatching
the parent N_CALL (check.ww:404-417), so args are stamped before the
intercept fires.

insert/delete deferred — not implemented in either stage. The cstage
divergence from harec (len → i32 not size; append → void not tagged)
pre-dates this task; #19 (dedicated AST kinds) is the Hare-faithful
path. Behavior is transitively covered by the 990-997 byte-id corpus
(append used in progs 16, 19, 20); the stamp side gates on #15.
This commit is contained in:
2026-05-22 00:52:53 +09:00
parent f8aac547b9
commit edd27101bf
3 changed files with 78 additions and 0 deletions

View File

@@ -8663,6 +8663,32 @@ fn exprtype(c: *checker, e: *node, hint: *node) *node = {
};
};
};
// len(x) / append(s,...) / free(p) — Hare pseudo-builtins.
// Mirror cstage cmd/wcc/check.c:896-1011 (rule 10 requires
// stage byte-id; both stages stamp the same shape). No shadow
// guard: cstage's len/append/free intercepts have none either
// (check.c:901/962/1005), and the names are seeded into c.top
// at L85-88 so a user same-module decl dup-silences. Harec
// models these as dedicated AST kinds — EXPR_LEN at
// ref/harec/src/check.c:2630 (result `&builtin_type_size`),
// EXPR_APPEND at :745 (result `(nomem | void)`), EXPR_FREE at
// :2443 (result `&builtin_type_void`). The cstage divergence
// (len → i32 not size, append → void not tagged) pre-dates
// this task; #19 (Drew's δ — dedicated AST kinds) is the
// Hare-faithful path. This is the intercept-shim minimum to
// unblock #15 (A.6.2.1e assertion enable).
if (callee.kind == nkind.N_IDENT) {
if (streq(callee.str, "len")) {
let tn: *node = mktname(c, "i32");
e.type_ = tinfofornode(c, tn): *void;
return tn;
};
if (streq(callee.str, "append") || streq(callee.str, "free")) {
let tn: *node = mktname(c, "void");
e.type_ = tinfofornode(c, tn): *void;
return tn;
};
};
let nm: str;
nm.ptr = nil; nm.len = 0;
if (callee.kind == nkind.N_IDENT) { nm = callee.str; };

View File

@@ -1699,6 +1699,32 @@ fn exprtype(c: *checker, e: *node, hint: *node) *node = {
};
};
};
// len(x) / append(s,...) / free(p) — Hare pseudo-builtins.
// Mirror cstage cmd/wcc/check.c:896-1011 (rule 10 requires
// stage byte-id; both stages stamp the same shape). No shadow
// guard: cstage's len/append/free intercepts have none either
// (check.c:901/962/1005), and the names are seeded into c.top
// at L85-88 so a user same-module decl dup-silences. Harec
// models these as dedicated AST kinds — EXPR_LEN at
// ref/harec/src/check.c:2630 (result `&builtin_type_size`),
// EXPR_APPEND at :745 (result `(nomem | void)`), EXPR_FREE at
// :2443 (result `&builtin_type_void`). The cstage divergence
// (len → i32 not size, append → void not tagged) pre-dates
// this task; #19 (Drew's δ — dedicated AST kinds) is the
// Hare-faithful path. This is the intercept-shim minimum to
// unblock #15 (A.6.2.1e assertion enable).
if (callee.kind == nkind.N_IDENT) {
if (streq(callee.str, "len")) {
let tn: *node = mktname(c, "i32");
e.type_ = tinfofornode(c, tn): *void;
return tn;
};
if (streq(callee.str, "append") || streq(callee.str, "free")) {
let tn: *node = mktname(c, "void");
e.type_ = tinfofornode(c, tn): *void;
return tn;
};
};
let nm: str;
nm.ptr = nil; nm.len = 0;
if (callee.kind == nkind.N_IDENT) { nm = callee.str; };

View File

@@ -8663,6 +8663,32 @@ fn exprtype(c: *checker, e: *node, hint: *node) *node = {
};
};
};
// len(x) / append(s,...) / free(p) — Hare pseudo-builtins.
// Mirror cstage cmd/wcc/check.c:896-1011 (rule 10 requires
// stage byte-id; both stages stamp the same shape). No shadow
// guard: cstage's len/append/free intercepts have none either
// (check.c:901/962/1005), and the names are seeded into c.top
// at L85-88 so a user same-module decl dup-silences. Harec
// models these as dedicated AST kinds — EXPR_LEN at
// ref/harec/src/check.c:2630 (result `&builtin_type_size`),
// EXPR_APPEND at :745 (result `(nomem | void)`), EXPR_FREE at
// :2443 (result `&builtin_type_void`). The cstage divergence
// (len → i32 not size, append → void not tagged) pre-dates
// this task; #19 (Drew's δ — dedicated AST kinds) is the
// Hare-faithful path. This is the intercept-shim minimum to
// unblock #15 (A.6.2.1e assertion enable).
if (callee.kind == nkind.N_IDENT) {
if (streq(callee.str, "len")) {
let tn: *node = mktname(c, "i32");
e.type_ = tinfofornode(c, tn): *void;
return tn;
};
if (streq(callee.str, "append") || streq(callee.str, "free")) {
let tn: *node = mktname(c, "void");
e.type_ = tinfofornode(c, tn): *void;
return tn;
};
};
let nm: str;
nm.ptr = nil; nm.len = 0;
if (callee.kind == nkind.N_IDENT) { nm = callee.str; };