From edd27101bf9e0d8c60eadaffb154615fccc653fe Mon Sep 17 00:00:00 2001 From: Hojun-Cho Date: Fri, 22 May 2026 00:52:53 +0900 Subject: [PATCH] selfhost/cmd/wcc: N_CALL intercepts for len/append/free (A.6.2.1b) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- selfhost/cmd/w6c/main.combined.ww | 26 ++++++++++++++++++++++++++ selfhost/cmd/wcc/check.ww | 26 ++++++++++++++++++++++++++ selfhost/cmd/wwdump/main.combined.ww | 26 ++++++++++++++++++++++++++ 3 files changed, 78 insertions(+) diff --git a/selfhost/cmd/w6c/main.combined.ww b/selfhost/cmd/w6c/main.combined.ww index d7b62c49..d51948d5 100644 --- a/selfhost/cmd/w6c/main.combined.ww +++ b/selfhost/cmd/w6c/main.combined.ww @@ -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; }; diff --git a/selfhost/cmd/wcc/check.ww b/selfhost/cmd/wcc/check.ww index 4e8e6a73..cf1e2e94 100644 --- a/selfhost/cmd/wcc/check.ww +++ b/selfhost/cmd/wcc/check.ww @@ -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; }; diff --git a/selfhost/cmd/wwdump/main.combined.ww b/selfhost/cmd/wwdump/main.combined.ww index 522d2841..6cedc0eb 100644 --- a/selfhost/cmd/wwdump/main.combined.ww +++ b/selfhost/cmd/wwdump/main.combined.ww @@ -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; };