diff --git a/docs/test-system-v2.md b/docs/test-system-v2.md index 373ec439..d7862dea 100644 --- a/docs/test-system-v2.md +++ b/docs/test-system-v2.md @@ -32,9 +32,9 @@ categories out of the ordinary developer target. | Fixed point and self-host | `test-bootstrap` | | Host linker/platform behavior | `test-platform` | -The live declarative compiler corpus has 1,485 fixtures and 2,970 C/WW cells: +The live declarative compiler corpus has 1,486 fixtures and 2,972 C/WW cells: 338 expected rejections (314 shared and 24 stage-specific), 17 compile-only -successes, 191 exit-zero programs, and 939 explicit-exit programs. +successes, 191 exit-zero programs, and 940 explicit-exit programs. 147 native C carriers remain. They are partitioned exactly once as five in-process units, 24 byte/artifact gates, six bootstrap gates, one platform diff --git a/internal/wwfixture/types.ww b/internal/wwfixture/types.ww index 8e3c2b40..12210d32 100644 --- a/internal/wwfixture/types.ww +++ b/internal/wwfixture/types.ww @@ -1,13 +1,13 @@ package wwfixture; def protocolversion: i32 = 1; -def corpuscount: i32 = 1485; +def corpuscount: i32 = 1486; def errorcount: i32 = 338; def compilecount: i32 = 17; def runcount: i32 = 191; -def runexitcount: i32 = 939; -def nativecount: i32 = 2970; -def corpushash: str = "69453e64f903a75b8a3f27c79e336ae766b3fb7ecfaac85d13f5d1f0c0dc4f50"; +def runexitcount: i32 = 940; +def nativecount: i32 = 2972; +def corpushash: str = "ab4b1d1ffc078b23de0a70911740511e873cd8d6f76009c4719d704bb36e6133"; type directive = enum i32 { ERROR = 0, diff --git a/selfhost/cmd/wcc/check.ww b/selfhost/cmd/wcc/check.ww index ff23b92f..4bec0705 100644 --- a/selfhost/cmd/wcc/check.ww +++ b/selfhost/cmd/wcc/check.ww @@ -1083,7 +1083,18 @@ fn typeeqast(c: *checker, a: *syntax.node, b: *syntax.node) bool = { let va: bool = pa.op == syntax.tkind.TK_ELLIPSIS; let vb: bool = pb.op == syntax.tkind.TK_ELLIPSIS; if (va != vb) { return false; }; - if (!typeeqast(c, pa.lhs, pb.lhs)) { return false; }; + // installparams normalizes a DECL's `T...` param lhs to + // a marked []T in place; a fn TYPE expr stays surface. + // Peel exactly the marked wrapper so both sides compare + // at the declared element type (cstage's type_eq sees + // type_slice on BOTH sides, check.c:908-917). + let la: *syntax.node = pa.lhs; + let lb: *syntax.node = pb.lhs; + if (la != nil && la.kind == syntax.nkind.N_TSLICE + && la.op == syntax.tkind.TK_ELLIPSIS) { la = la.lhs; }; + if (lb != nil && lb.kind == syntax.nkind.N_TSLICE + && lb.op == syntax.tkind.TK_ELLIPSIS) { lb = lb.lhs; }; + if (!typeeqast(c, la, lb)) { return false; }; }; pa = pa.next; pb = pb.next; @@ -6817,6 +6828,14 @@ fn installparams(c: *checker, params: *syntax.node) void = { if (p.lhs != nil && p.lhs.kind != syntax.nkind.N_TSLICE) { let sl: *syntax.node = syntax.newnode(syntax.nkind.N_TSLICE, "", 0, 0); sl.lhs = p.lhs; + // op marks the wrapper as THIS normalization, not + // surface syntax, so typeeqast can peel exactly it + // when comparing against an unnormalized fn TYPE + // expr (`let f: fn(args: i64...) void = sum` — the + // decl side reads []i64 here, the let side i64). + // Param-lhs position never carries a tagged spread + // marker, so the op reads stay disjoint. + sl.op = syntax.tkind.TK_ELLIPSIS; p.lhs = sl; }; }; diff --git a/test/wcc/data/fnptrlet_variadic/case.ww b/test/wcc/data/fnptrlet_variadic/case.ww new file mode 100644 index 00000000..627c07a3 --- /dev/null +++ b/test/wcc/data/fnptrlet_variadic/case.ww @@ -0,0 +1,21 @@ +//ww:run-exit 42 +package main; + +// A variadic fn assigned to a fn-typed let and called through it. The +// wwstage over-rejected the let ("not assignable"): installparams +// normalizes the DECL's `T...` param lhs to []T in place, while the +// let's fn TYPE expr stays surface, so typeeqast compared []i64 vs +// i64. cstage compares resolved types with type_slice on both sides +// (check.c:908-917) and accepts. + +fn tally(args: i64...) i64 = { + let s: i64 = 0i64; + let i: i32 = 0; + for (i < args.len) { s += args[i]; i += 1; }; + return s; +}; + +fn main() i32 = { + let f: fn(args: i64...) i64 = tally; + return (f(1i64, 2i64, 3i64) * 7i64): i32; +};