check: populate fn-type params in the wwstage tinfo layer

The N_TFN arm stamped only size and return, so every fn tinfo carried
a nil param chain and typeeq judged any two same-return fn types
equal: tagged-union dedup collapsed (*fn(A) T | *fn(B) T) to a bare
8-byte pointer and match read the pointer word as a tag, falling
through every arm for a real second-variant value. Build the tparam
chain like cstage's N_TFN resolve (bare ... sets the FFI variadic
flag; a Hare T... param wraps to []T with a per-param variadic bit
that typeeq now compares, mirroring cstage type_eq). Graduates the
four r76_typeeq_fn pins; the DATABYTEID_DIVERGED ledger is empty.
This commit is contained in:
2026-08-07 23:54:10 +09:00
parent 06c20dbec4
commit 0b1cc5ef7c
3 changed files with 36 additions and 6 deletions

View File

@@ -581,10 +581,9 @@ DATABYTEID_EXPECTED_MIN = 911
# Known cs!=ww divergences (loud over blind, the 989_lib_byteid DIVERGE
# discipline): each entry must still build on both stages AND still differ.
# When a compiler fix lands the entry fails demanding graduation out of
# this list rather than silently widening coverage. Tracked with the #59
# divergence family.
DATABYTEID_DIVERGED = r76_typeeq_fn_diff_arity r76_typeeq_fn_diff_param_type \
r76_typeeq_fn_io_vtable_shape r76_typeeq_fn_variadic_vs_fixed
# this list rather than silently widening coverage. Currently empty: the
# 2026-08 drain closed all eight original entries.
DATABYTEID_DIVERGED =
$(if $(DATABYTEID_FILES),,$(error test-byteid: empty data corpus))
test-data-byteid: $(BIN)/ww $(BIN)/w6c $(BIN)/w6c_ww
@work=$$(mktemp -d "$(CURDIR)/$(DATABYTEID_DIR).XXXXXX") || exit 1; \

View File

@@ -88,6 +88,10 @@ export type tparam = struct {
// struct instead, matching cstage Type.iserror semantics.
// Faithful STORAGE_ERROR-node port filed as #62.
iserror: bool,
// Hare-style `T...` — type_ is []T when set. Mirrors cstage
// Tparam.variadic (cmd/wcc/ww.h); distinct from tinfo.variadic,
// the C-style FFI `...` marker.
variadic: bool,
tnext: *tparam,
};
@@ -547,6 +551,7 @@ export fn typeeq(a: *tinfo, b: *tinfo) bool = {
for (true) {
if (pa == nil) { if (pb == nil) { return true; }; return false; };
if (pb == nil) { return false; };
if (pa.variadic != pb.variadic) { return false; };
if (!typeeq(pa.type_, pb.type_)) { return false; };
pa = pa.tnext;
pb = pb.tnext;

View File

@@ -2311,6 +2311,32 @@ fn tinfofornode(c: *checker, n: *syntax.node) *syntax.tinfo = {
r.slotsize = 8u64;
syntax.tinfocachebind(c.tc, n, r);
r.ret = tinfofornode(c, n.lhs);
// Params must be populated (cstage check.c N_TFN builds the
// Tparam chain): with params nil on every fn tinfo, typeeq saw
// any two same-return fn types equal, so tagged-union dedup
// collapsed `(*fn(A) T | *fn(B) T)` to a bare 8B pointer and
// match read the pointer word as a tag.
{
let fphead: *syntax.tparam = nil;
let fptail: *syntax.tparam = nil;
let fpn: *syntax.node = n.list;
for (fpn != nil) {
if (syntax.streq(fpn.str, "...")) {
r.variadic = 1;
fpn = fpn.next;
continue;
};
let fpt: *syntax.tinfo = tinfofornode(c, fpn.lhs);
let fpv: bool = fpn.op == syntax.tkind.TK_ELLIPSIS;
if (fpv) { fpt = syntax.typeslice(fpt); };
let ftp: *syntax.tparam = alloc(syntax.tparam{name=fpn.str, type_=fpt, iserror=false, variadic=fpv, tnext=nil})!;
if (fphead == nil) { fphead = ftp; }
else { fptail.tnext = ftp; };
fptail = ftp;
fpn = fpn.next;
};
r.params = fphead;
};
case syntax.nkind.N_TENUM:
// Cstage cmd/wcc/check.c:529-542: storage type's size/align
// (default i32 = 4B/4B). Cgen's slotsize-TENUM fallback pads
@@ -2546,7 +2572,7 @@ fn tinfofornode(c: *checker, n: *syntax.node) *syntax.tinfo = {
if (st.size > maxsz) { maxsz = st.size; };
if (st.align > al) { al = st.align; };
};
let tp: *syntax.tparam = alloc(syntax.tparam{name="", type_=src.type_, iserror=src.iserror, tnext=nil})!;
let tp: *syntax.tparam = alloc(syntax.tparam{name="", type_=src.type_, iserror=src.iserror, variadic=false, tnext=nil})!;
if (head == nil) { head = tp; } else { tail.tnext = tp; };
tail = tp;
nv += 1;
@@ -2564,7 +2590,7 @@ fn tinfofornode(c: *checker, n: *syntax.node) *syntax.tinfo = {
if (vt.align > al) { al = vt.align; };
};
let ve: bool = varianterr(c, v);
let tp: *syntax.tparam = alloc(syntax.tparam{name="", type_=vt, iserror=ve, tnext=nil})!;
let tp: *syntax.tparam = alloc(syntax.tparam{name="", type_=vt, iserror=ve, variadic=false, tnext=nil})!;
if (head == nil) { head = tp; } else { tail.tnext = tp; };
tail = tp;
nv += 1;