ww: finish initialization validation parity

This commit is contained in:
2026-08-14 20:03:11 +09:00
parent 25da54936d
commit c59a7c11de
26 changed files with 528 additions and 143 deletions

View File

@@ -3,8 +3,9 @@
// #156). emit_array_lit_bytes recurses on a TY_ARRAY element (esz=etype->size,
// rule 13); cgindex leaves the sub-array ADDRESS for an array element so the
// outer index dereferences the right cell (#135 sister). cstage build+run was
// T1; cs==ww .s byte-id rides T2 (test-lang-byteid). The nested-array `...`
// repeat reject is the runww carrier test/wcc/data/arr_nested_ellipsis_reject.
// T1; cs==ww .s byte-id rides T2 (test-lang-byteid). A nested-array `...`
// repeat now runs through package initialization when static emission cannot
// represent it, as pinned by test/wcc/data/arr_nested_ellipsis_reject.
//
// Float-element rows assert bit-exact incl negative elements (drew: exercise the
// sign-XOR byte-loop per element). The struct-with-array-field rows read the

View File

@@ -93,17 +93,26 @@ fn samefile(a: str, b: str, why: str) void = {
"example.foo.unit.ww"));
let wantfoo: str = strings.concat("//ww:module-reset example.foo\n", afoosrc,
"\n//ww:module-reset example.foo\n", zfoosrc, "\n");
if (!testenv.same(foounit, wantfoo)
let foovoucher: str = "//ww:direct-export example.bar ";
if (!strings.hasprefix(foounit, wantfoo)
|| testenv.occurrences(foounit, "//ww:direct-export ") != 1
|| testenv.occurrences(foounit, foovoucher) != 1
|| testenv.pos(foounit, foovoucher) != wantfoo.len
|| testenv.has(foounit, "DECOY_FILE")
|| testenv.has(foounit, "//ww:module ")) {
fail("foo unit is not exactly its sorted, owned source set");
fail("foo owner prefix/direct-export voucher mismatch");
};
let wantroot: str = strings.concat("//ww:module-reset ", appidentity,
"\n", appsrc,
"\n");
if (!testenv.same(wantroot, testenv.readfile(strings.concat(cwork,
appidentity, ".unit.ww")))) {
fail("root unit is not exactly its owned source");
let rootunit: str = testenv.readfile(strings.concat(cwork,
appidentity, ".unit.ww"));
let rootvoucher: str = "//ww:direct-export example.foo ";
if (!strings.hasprefix(rootunit, wantroot)
|| testenv.occurrences(rootunit, "//ww:direct-export ") != 1
|| testenv.occurrences(rootunit, rootvoucher) != 1
|| testenv.pos(rootunit, rootvoucher) != wantroot.len) {
fail("root owner prefix/direct-export voucher mismatch");
};
let keys: []str = ["example.base", "example.bar", "example.foo",
appidentity];

View File

@@ -288,10 +288,14 @@ fn rejectstable(dir: str, label: str, target: str, needle: str) void = {
};
let expectedunit: str = strings.concat("//ww:module-reset main\n",
mainsrc, "\n");
if (!testenv.same(expectedunit, testenv.readfile(strings.concat(cwork,
"main.unit.ww"))) || !testenv.same(expectedunit,
testenv.readfile(strings.concat(wwork, "main.unit.ww")))) {
fail("self-contained", "consumer unit was not exactly its owned source");
let cunit: str = testenv.readfile(strings.concat(cwork, "main.unit.ww"));
let cunit2: str = testenv.readfile(strings.concat(cwork2, "main.unit.ww"));
let wunit: str = testenv.readfile(strings.concat(wwork, "main.unit.ww"));
if (!strings.hasprefix(cunit, expectedunit)
|| testenv.occurrences(cunit, "//ww:direct-export api ") != 1
|| testenv.pos(cunit, "//ww:direct-export api ") != expectedunit.len
|| !testenv.same(cunit, cunit2) || !testenv.same(cunit, wunit)) {
fail("self-contained", "consumer owner prefix/direct-export voucher mismatch");
};
if (!testenv.exists(strings.concat(cwork, "implementation.a"))
|| !testenv.exists(strings.concat(cwork, "dimensions.a"))) {
@@ -408,9 +412,16 @@ fn writediamond(td: str, reverse: bool) str = {
let rootbody: str = testenv.readfile(strings.concat(main, "/main.ww"));
let wantroot: str = strings.concat("//ww:module-reset main\n", rootbody,
"\n");
if (!testenv.same(unit, wantroot) || testenv.has(unit,
"//ww:module ")) {
fail("diamond", "root unit contains non-owned export text");
let leftvoucher: str = "//ww:direct-export left ";
let rightvoucher: str = "//ww:direct-export right ";
if (!strings.hasprefix(unit, wantroot) || testenv.has(unit,
"//ww:module ")
|| testenv.occurrences(unit, "//ww:direct-export ") != 2
|| testenv.occurrences(unit, leftvoucher) != 1
|| testenv.occurrences(unit, rightvoucher) != 1
|| testenv.pos(unit, leftvoucher) != wantroot.len
|| testenv.pos(unit, leftvoucher) >= testenv.pos(unit, rightvoucher)) {
fail("diamond", "root owner prefix/sorted direct-export vouchers changed");
};
let sharedunit: str = testenv.readfile(strings.concat(scratch,
"shared.unit.ww"));
@@ -534,6 +545,9 @@ fn writediamond(td: str, reverse: bool) str = {
let referencearchive: str = "";
let referencerootwwi: str = "";
let referencerootarchive: str = "";
let referenceinitunit: str = "";
let referenceinitasm: str = "";
let referenceinitobj: str = "";
let referencebin: str = "";
let referencecompiler: str = "";
let referenceassembler: str = "";
@@ -583,9 +597,21 @@ fn writediamond(td: str, reverse: bool) str = {
|| !testenv.exists(strings.concat(work, "dep.a"))
|| !testenv.exists(strings.concat(work, "main.o"))
|| !testenv.exists(strings.concat(work, "main.wwi"))
|| !testenv.exists(strings.concat(work, "main.a"))) {
|| !testenv.exists(strings.concat(work, "main.a"))
|| !testenv.exists(strings.concat(work, "main.init.unit.ww"))
|| !testenv.exists(strings.concat(work, "main.init.s"))
|| !testenv.exists(strings.concat(work, "main.init.o"))) {
fail("library-roots", "package artifacts do not match root ownership");
};
let initunit: str = testenv.readfile(strings.concat(work,
"main.init.unit.ww"));
if (!testenv.same(initunit, strings.concat(
"//ww:init-root __ww..pkg.p.main.v0.r0.init\n",
"//ww:init-call __ww..pkg.p.leaf.v0.r0.init\n",
"//ww:init-call __ww..pkg.p.dep.v0.r0.init\n",
"//ww:init-call __ww..pkg.p.main.v0.r0.init\n"))) {
fail("library-roots", "root dispatcher unit order changed");
};
let ctrace: str = testenv.readfile(compilertrace);
let atrace: str = testenv.readfile(assemblertrace);
let ltrace: str = testenv.readfile(linkertrace);
@@ -604,20 +630,29 @@ fn writediamond(td: str, reverse: bool) str = {
fail("library-roots", "compiler actions were not deterministic postorder");
};
if (!testenv.has(ctrace, strings.concat(
"BEGIN<-c><--import><leaf><", work, "leaf.wwi><-I><", work,
"BEGIN<--package-init-symbol><__ww..pkg.p.leaf.v0.r0.init>",
"<-c><-I><", work, "leaf.wwi><-o><", work,
"leaf.s><", work, "leaf.unit.ww>"))
|| !testenv.has(ctrace, strings.concat(
"BEGIN<--package-init-symbol><__ww..pkg.p.dep.v0.r0.init>",
"<-c><--import><leaf><", work, "leaf.wwi><-I><", work,
"dep.wwi><-o><", work,
"dep.s><", work, "dep.unit.ww>"))
|| !testenv.has(ctrace, strings.concat(
"BEGIN<--entry><-c><--import><dep><", work,
"BEGIN<--entry><--package-init-symbol>",
"<__ww..pkg.p.main.v0.r0.init><--init-dispatch-symbol>",
"<__ww..dispatch><-c><--import><dep><", work,
"dep.wwi><-I><", work, "main.wwi><-o><", work,
"main.s><", work, "main.unit.ww>"))
|| testenv.occurrences(atrace, "\n") != 3
|| testenv.occurrences(atrace, "\n") != 4
|| !testenv.has(atrace, strings.concat("BEGIN<-o><", work,
"dep.o><", work, "dep.s>"))) {
"dep.o><", work, "dep.s>"))
|| !testenv.has(atrace, strings.concat("BEGIN<-o><", work,
"main.init.o><", work, "main.init.s>"))) {
fail("library-roots", "compiler or assembler argv changed");
};
if (testenv.occurrences(ltrace, "\n") != 1
|| !testenv.has(ltrace, strings.concat("BEGIN<-o><", bin, "><",
|| !testenv.has(ltrace, strings.concat("BEGIN<-o><", bin, ".new><",
work, "main.a>"))
|| testenv.pos(ltrace, strings.concat("<", work, "dep.a>")) < 0
|| testenv.pos(ltrace, strings.concat("<", work, "leaf.a>"))
@@ -655,6 +690,11 @@ fn writediamond(td: str, reverse: bool) str = {
"main.wwi")));
referencerootarchive = strings.dup(testenv.readfile(strings.concat(work,
"main.a")));
referenceinitunit = strings.dup(initunit);
referenceinitasm = strings.dup(testenv.readfile(strings.concat(work,
"main.init.s")));
referenceinitobj = strings.dup(testenv.readfile(strings.concat(work,
"main.init.o")));
referencebin = strings.dup(testenv.readfile(bin));
referencecompiler = strings.dup(ctrace);
referenceassembler = strings.dup(atrace);
@@ -669,6 +709,11 @@ fn writediamond(td: str, reverse: bool) str = {
testenv.readfile(strings.concat(work, "main.wwi")))
|| !testenv.same(referencerootarchive,
testenv.readfile(strings.concat(work, "main.a")))
|| !testenv.same(referenceinitunit, initunit)
|| !testenv.same(referenceinitasm,
testenv.readfile(strings.concat(work, "main.init.s")))
|| !testenv.same(referenceinitobj,
testenv.readfile(strings.concat(work, "main.init.o")))
|| !testenv.same(referencebin, testenv.readfile(bin))
|| !testenv.same(referencecompiler, ctrace)
|| !testenv.same(referenceassembler, atrace)
@@ -747,7 +792,7 @@ fn writediamond(td: str, reverse: bool) str = {
|| !testenv.exists(strings.concat(emptywork, "types.a"))
|| testenv.occurrences(ctrace, strings.concat("<", emptywork,
"types.unit.ww>")) != 1
|| testenv.occurrences(atrace, "\n") != 2) {
|| testenv.occurrences(atrace, "\n") != 3) {
fail("library-roots", "empty WW_SRCLIB did not use the default source root");
};
if (testenv.occurrences(ltrace, "\n") != 1
@@ -900,6 +945,9 @@ fn writediamond(td: str, reverse: bool) str = {
|| !testenv.exists(strings.concat(work, "/dep.a"))
|| !testenv.exists(strings.concat(work, "/main.wwi"))
|| !testenv.exists(strings.concat(work, "/main.a"))
|| !testenv.exists(strings.concat(work, "/main.init.unit.ww"))
|| !testenv.exists(strings.concat(work, "/main.init.s"))
|| !testenv.exists(strings.concat(work, "/main.init.o"))
|| !testenv.same(testenv.readfile(strings.concat(work,
"/.wwtool.ww")), testenv.readfile(copied[si]))
|| !testenv.same(testenv.readfile(strings.concat(work,
@@ -908,7 +956,7 @@ fn writediamond(td: str, reverse: bool) str = {
"/.wwtool.w6a")), testenv.readfile(assembler))
|| !testenv.same(testenv.readfile(strings.concat(work,
"/.wwtool.stamp")),
"ww workdir fmt 15 mode build asm 0\n")) {
"ww workdir fmt 17 mode build asm 0\n")) {
fail("driver-identity", "persistent artifacts or identities are incomplete");
};
let coldwwi: str = testenv.readfile(strings.concat(work, "/dep.wwi"));
@@ -919,28 +967,38 @@ fn writediamond(td: str, reverse: bool) str = {
let coldlinker: str = testenv.readfile(linkertrace);
if (testenv.occurrences(coldcompiler, "\n") != 3
|| !testenv.has(coldcompiler, strings.concat(
"BEGIN<-c><--import><leaf><", work, "/leaf.wwi><-I><", work,
"BEGIN<--package-init-symbol><__ww..pkg.p.leaf.v0.r0.init>",
"<-c><-I><", work, "/leaf.wwi.new><-o><", work,
"/leaf.s.new><", work, "/leaf.unit.new>"))
|| !testenv.has(coldcompiler, strings.concat(
"BEGIN<--package-init-symbol><__ww..pkg.p.dep.v0.r0.init>",
"<-c><--import><leaf><", work, "/leaf.wwi.new><-I><", work,
"/dep.wwi.new><-o><", work,
"/dep.s.new><", work, "/dep.unit.new>"))
|| !testenv.has(coldcompiler, strings.concat(
"BEGIN<--entry><-c><--import><dep><", work,
"/dep.wwi><-I><", work, "/main.wwi.new><-o><", work,
"BEGIN<--entry><--package-init-symbol>",
"<__ww..pkg.p.main.v0.r0.init><--init-dispatch-symbol>",
"<__ww..dispatch><-c><--import><dep><", work,
"/dep.wwi.new><-I><", work, "/main.wwi.new><-o><", work,
"/main.s.new><", work,
"/main.unit.new>"))
|| testenv.occurrences(coldassembler, "\n") != 3
|| testenv.occurrences(coldassembler, "\n") != 4
|| !testenv.has(coldassembler, strings.concat(
"BEGIN<-o><", work, "/dep.o.new><", work,
"/dep.s.new>"))) {
"/dep.s.new>"))
|| !testenv.has(coldassembler, strings.concat(
"BEGIN<-o><", work, "/main.init.o.new><", work,
"/main.init.s.new>"))) {
fail("driver-identity", "cold compiler or assembler argv changed");
};
if (testenv.occurrences(coldlinker, "\n") != 1
|| !testenv.has(coldlinker, strings.concat("BEGIN<-o><", bin,
"><", work, "/main.a>"))
".new><", work, "/main.a.new>"))
|| testenv.pos(coldlinker, strings.concat("<", work,
"/dep.a>")) < 0
"/dep.a.new>")) < 0
|| testenv.pos(coldlinker, strings.concat("<", work,
"/leaf.a>")) < testenv.pos(coldlinker, strings.concat("<",
work, "/dep.a>"))
"/leaf.a.new>")) < testenv.pos(coldlinker, strings.concat("<",
work, "/dep.a.new>"))
|| !testenv.has(coldlinker, strings.concat("<", runtime,
"/libwwrt.a>"))
|| testenv.has(coldlinker, ".wwi>")) {
@@ -970,7 +1028,7 @@ fn writediamond(td: str, reverse: bool) str = {
|| testenv.occurrences(changedexportcompiler, strings.concat("<", work,
"/main.unit.new>")) != 1
|| testenv.occurrences(changedexportcompiler, "\n") != 5
|| testenv.occurrences(changedexportassembler, "\n") != 5) {
|| testenv.occurrences(changedexportassembler, "\n") != 6) {
fail("driver-identity", "changed export did not stop at an unchanged importer export");
};
if (code(cwd, strings.concat("driver-export-change-run-", tags[si]),
@@ -1004,7 +1062,7 @@ fn writediamond(td: str, reverse: bool) str = {
|| testenv.occurrences(testenv.readfile(compilertrace), strings.concat(
"<", work, "/main.unit.new>")) != 1
|| testenv.occurrences(testenv.readfile(compilertrace), "\n") != 7
|| testenv.occurrences(testenv.readfile(assemblertrace), "\n") != 7
|| testenv.occurrences(testenv.readfile(assemblertrace), "\n") != 8
|| !testenv.same(coldbin, testenv.readfile(bin))) {
fail("driver-identity", "restored export did not rebuild only its direct importer");
};
@@ -1029,7 +1087,7 @@ fn writediamond(td: str, reverse: bool) str = {
|| testenv.occurrences(changedcompiler, strings.concat("<", work,
"/main.unit.new>")) != 2
|| testenv.occurrences(changedcompiler, "\n") != 10
|| testenv.occurrences(changedassembler, "\n") != 10
|| testenv.occurrences(changedassembler, "\n") != 12
|| testenv.occurrences(changedlinker, "\n") != 5) {
fail("driver-identity", "driver change reused stale package actions");
};
@@ -1339,9 +1397,11 @@ fn writediamond(td: str, reverse: bool) str = {
let linkers: []str = ["w6l", "w6l_ww"];
let tags: []str = ["c", "ww"];
let suffixes: []str = [".unit.ww", ".wwi", ".s", ".o", ".a"];
let initsuffixes: []str = [".init.unit.ww", ".init.s", ".init.o"];
let rootreference: []str = ["", "", "", "", ""];
let depreference: []str = ["", "", "", "", ""];
let commandreference: []str = ["", "", "", "", ""];
let commandinitreference: []str = ["", "", ""];
let nooutrootreference: []str = ["", "", "", "", ""];
let nooutdepreference: []str = ["", "", "", "", ""];
let publishreference: str = "";
@@ -1382,11 +1442,14 @@ fn writediamond(td: str, reverse: bool) str = {
let ctrace: str = testenv.readfile(compilertrace);
let atrace: str = testenv.readfile(assemblertrace);
let wantcompiler: str = strings.concat(
"BEGIN<-c><-I><", work,
"BEGIN<--package-init-symbol>",
"<__ww..pkg.p.foo.dep.v0.r0.init><-c><-I><", work,
"/foo.dep.wwi.new><-o><", work,
"/foo.dep.s.new><", work, "/foo.dep.unit.new>\n",
"BEGIN<-c><--import><foo.dep><", work,
"/foo.dep.wwi><-I><", work,
"BEGIN<--package-init-symbol>",
"<__ww..pkg.p.foo.bar.v0.r0.init><-c>",
"<--import><foo.dep><", work,
"/foo.dep.wwi.new><-I><", work,
"/foo.bar.wwi.new><-o><", work,
"/foo.bar.s.new><", work, "/foo.bar.unit.new>\n");
let wantassembler: str = strings.concat(
@@ -1461,15 +1524,20 @@ fn writediamond(td: str, reverse: bool) str = {
atrace = testenv.readfile(assemblertrace);
let commandlink: str = testenv.readfile(linkertrace);
let wantcommandcompiler: str = strings.concat(
"BEGIN<-c><-I><", commandwork,
"BEGIN<--package-init-symbol>",
"<__ww..pkg.p.foo.dep.v0.r0.init><-c><-I><", commandwork,
"/foo.dep.wwi.new><-o><", commandwork,
"/foo.dep.s.new><", commandwork, "/foo.dep.unit.new>\n",
"BEGIN<-c><--import><foo.dep><", commandwork,
"/foo.dep.wwi><-I><", commandwork,
"BEGIN<--package-init-symbol>",
"<__ww..pkg.p.foo.bar.v0.r0.init><-c>",
"<--import><foo.dep><", commandwork,
"/foo.dep.wwi.new><-I><", commandwork,
"/foo.bar.wwi.new><-o><", commandwork,
"/foo.bar.s.new><", commandwork, "/foo.bar.unit.new>\n",
"BEGIN<--entry><-c><--import><foo.bar><", commandwork,
"/foo.bar.wwi><-I><", commandwork,
"BEGIN<--entry><--package-init-symbol>",
"<__ww..pkg.p.foo.cmd.v0.r0.init><--init-dispatch-symbol>",
"<__ww..dispatch><-c><--import><foo.bar><", commandwork,
"/foo.bar.wwi.new><-I><", commandwork,
"/foo.cmd.wwi.new><-o><", commandwork,
"/foo.cmd.s.new><", commandwork, "/foo.cmd.unit.new>\n");
let wantcommandassembler: str = strings.concat(
@@ -1478,10 +1546,12 @@ fn writediamond(td: str, reverse: bool) str = {
"BEGIN<-o><", commandwork, "/foo.bar.o.new><", commandwork,
"/foo.bar.s.new>\n",
"BEGIN<-o><", commandwork, "/foo.cmd.o.new><", commandwork,
"/foo.cmd.s.new>\n");
"/foo.cmd.s.new>\n",
"BEGIN<-o><", commandwork, "/foo.cmd.init.o.new><", commandwork,
"/foo.cmd.init.s.new>\n");
let wantcommandlink: str = strings.concat("BEGIN<-o><", commandbin,
"><", commandwork, "/foo.cmd.a><", commandwork,
"/foo.bar.a><", commandwork, "/foo.dep.a><", runtime,
".new><", commandwork, "/foo.cmd.a.new><", commandwork,
"/foo.bar.a.new><", commandwork, "/foo.dep.a.new><", runtime,
"/libwwrt.a>\n");
if (out.termination != exec.termination.EXIT || out.code != 0
|| out.stderr.len != 0
@@ -1510,6 +1580,18 @@ fn writediamond(td: str, reverse: bool) str = {
}; };
ai += 1;
};
ai = 0;
for (ai < initsuffixes.len) {
let initbytes: str = testenv.readfile(strings.concat(commandwork,
"/foo.cmd", initsuffixes[ai]));
if (si == 0) {
commandinitreference[ai] = strings.dup(initbytes);
} else { if (!testenv.same(commandinitreference[ai], initbytes)) {
fail("package-autoaction",
"Cstage and WWstage dispatcher artifacts differ");
}; };
ai += 1;
};
let commandrun: []str = [commandbin];
if (code(td, strings.concat("auto-command-run-", tags[si]),
commandrun) != 42) {
@@ -1544,11 +1626,14 @@ fn writediamond(td: str, reverse: bool) str = {
ctrace = testenv.readfile(compilertrace);
atrace = testenv.readfile(assemblertrace);
let wantnooutcompiler: str = strings.concat(
"BEGIN<-c><-I><", nooutwork,
"BEGIN<--package-init-symbol>",
"<__ww..pkg.p.foo.dep.v0.r0.init><-c><-I><", nooutwork,
"/foo.dep.wwi.new><-o><", nooutwork,
"/foo.dep.s.new><", nooutwork, "/foo.dep.unit.new>\n",
"BEGIN<-c><--import><foo.dep><", nooutwork,
"/foo.dep.wwi><-I><", nooutwork,
"BEGIN<--package-init-symbol>",
"<__ww..pkg.p.foo.bar.v0.r0.init><-c>",
"<--import><foo.dep><", nooutwork,
"/foo.dep.wwi.new><-I><", nooutwork,
"/foo.bar.wwi.new><-o><", nooutwork,
"/foo.bar.s.new><", nooutwork, "/foo.bar.unit.new>\n");
let wantnooutassembler: str = strings.concat(
@@ -1660,11 +1745,14 @@ fn writediamond(td: str, reverse: bool) str = {
testenv.runcommandenv(td, td, strings.concat("auto-asm-long-output-",
tags[si]), asmav, env, tmo(), &out);
let wantasmcompiler: str = strings.concat(
"BEGIN<-c><-I><", asmwork,
"BEGIN<--package-init-symbol>",
"<__ww..pkg.p.foo.dep.v0.r0.init><-c><-I><", asmwork,
"/foo.dep.wwi.new><-o><", asmwork,
"/foo.dep.s.new><", asmwork, "/foo.dep.unit.new>\n",
"BEGIN<-c><--import><foo.dep><", asmwork,
"/foo.dep.wwi><-I><", asmwork,
"BEGIN<--package-init-symbol>",
"<__ww..pkg.p.foo.bar.v0.r0.init><-c>",
"<--import><foo.dep><", asmwork,
"/foo.dep.wwi.new><-I><", asmwork,
"/foo.bar.wwi.new><-o><", asmwork,
"/foo.bar.s.new><", asmwork, "/foo.bar.unit.new>\n");
if (out.termination != exec.termination.EXIT || out.code != 0
@@ -1752,7 +1840,8 @@ fn writediamond(td: str, reverse: bool) str = {
ctrace = testenv.readfile(compilertrace);
atrace = testenv.readfile(assemblertrace);
let wantprivatecompiler: str = strings.concat(
"BEGIN<-c><-I><", work,
"BEGIN<--package-init-symbol>",
"<__ww..pkg.p.foo.dep.v0.r0.init><-c><-I><", work,
"/foo.dep.wwi.new><-o><", work,
"/foo.dep.s.new><", work, "/foo.dep.unit.new>\n");
let wantprivateassembler: str = strings.concat(
@@ -1778,11 +1867,14 @@ fn writediamond(td: str, reverse: bool) str = {
ctrace = testenv.readfile(compilertrace);
atrace = testenv.readfile(assemblertrace);
let wantexportcompiler: str = strings.concat(
"BEGIN<-c><-I><", work,
"BEGIN<--package-init-symbol>",
"<__ww..pkg.p.foo.dep.v0.r0.init><-c><-I><", work,
"/foo.dep.wwi.new><-o><", work,
"/foo.dep.s.new><", work, "/foo.dep.unit.new>\n",
"BEGIN<-c><--import><foo.dep><", work,
"/foo.dep.wwi><-I><", work,
"BEGIN<--package-init-symbol>",
"<__ww..pkg.p.foo.bar.v0.r0.init><-c>",
"<--import><foo.dep><", work,
"/foo.dep.wwi.new><-I><", work,
"/foo.bar.wwi.new><-o><", work,
"/foo.bar.s.new><", work, "/foo.bar.unit.new>\n");
let wantexportassembler: str = strings.concat(

View File

@@ -101,7 +101,8 @@ fn samefile(label: str, what: str, a: str, b: str) void = {
i += 1;
};
// cs==ww (rule 10): per-package artifacts + the final binary
// cs==ww (rule 10): per-source-action artifacts + the final binary;
// sepinit owns the command root's additional dispatcher artifacts.
let sufs: []str = [".s", ".wwi", ".a", ".unit.ww"];
let p: i32 = 0;
for (p < pkgs.len) {
@@ -164,7 +165,8 @@ fn samefile(label: str, what: str, a: str, b: str) void = {
s += 1;
};
// cs==ww for the complete package artifacts, including the root archive.
// cs==ww for every source-action artifact, including the root archive;
// sepinit owns the command root's additional dispatcher artifacts.
let pkgs: []str = ["c", "__root"];
let sufs: []str = [".s", ".wwi", ".a", ".unit.ww"];
let p: i32 = 0;

View File

@@ -209,11 +209,12 @@ fn depmainrow(label: str, entry: str, want: i32, deps: str,
l += 1;
};
// Both the dependency and raw explicit root emit complete package artifacts.
// Both the dependency and raw explicit root emit complete source-action
// artifacts; sepinit owns command-dispatcher artifact parity.
let parts: []str = ["aa.s", "aa.wwi", "aa.a", "aa.unit.ww",
"__root.s", "__root.wwi", "__root.a", "__root.unit.ww"];
// cs==ww (rule 10) per layout over the complete package-artifact table
// cs==ww (rule 10) per layout over the source-action artifact table
let l2: i32 = 0;
for (l2 < 2) {
let p: i32 = 0;

View File

@@ -4,8 +4,9 @@ package seplink_test;
// retired native carriers test/wcc/989_separchive_run.c and
// 989_sepcycle_dup.c; every assertion preserved.
//
// archive — `ww build` wraps every package action's .o in the existing
// deterministic single-member .a and links the root archive first:
// archive — `ww build` wraps every library package action's .o in the existing
// deterministic single-member .a; the command root also owns its fixed
// dispatcher member, and the linker receives that root archive first:
// build+run exit 7 both stages; __root.a + helper.a present; both archives
// are byte-identical across stages; 3 cold cstage rebuilds emit
// byte-identical archives (zeroed mtime/uid/gid, fixed mode/member —

View File

@@ -81,14 +81,14 @@ main(void)
}
/* #93 sep layout: build an explicit command source via `ww build`,
* then independently link <stem>.sepwork/__root.o with both linkers.
* then independently link <stem>.sepwork/__root.a with both linkers.
* The direct getpid call guarantees one dynamic libc relocation. */
char cmd[4096], src[256], stem[256], scratch[320];
char obj[384], co[256], wo[256];
char archive[384], co[256], wo[256];
snprintf(src, sizeof src, "%s/dyn.ww", td);
snprintf(stem, sizeof stem, "%s/built", td);
snprintf(scratch, sizeof scratch, "%s.sepwork", stem);
snprintf(obj, sizeof obj, "%s/__root.o", scratch);
snprintf(archive, sizeof archive, "%s/__root.a", scratch);
snprintf(co, sizeof co, "%s/c", td);
snprintf(wo, sizeof wo, "%s/w", td);
@@ -125,7 +125,7 @@ main(void)
snprintf(cmd, sizeof cmd,
"%s/w6l -o %s %s -L %s "
"-l c %s/out/lib/libwwrt.a 2>/dev/null",
bin, co, obj, libdir, cwd);
bin, co, archive, libdir, cwd);
if (runwait(cmd) != 0) {
fprintf(stderr, "w6l_ww-dyn FAIL: C w6l errored\n");
rc = 1;
@@ -135,7 +135,7 @@ main(void)
snprintf(cmd, sizeof cmd,
"%s/w6l_ww -o %s %s -L %s "
"-l c %s/out/lib/libwwrt.a 2>/dev/null",
bin, wo, obj, libdir, cwd);
bin, wo, archive, libdir, cwd);
if (runwait(cmd) != 0) {
fprintf(stderr, "w6l_ww-dyn FAIL: ww w6l errored\n");
rc = 1;

View File

@@ -1,4 +1,4 @@
//ww:error "#129 A.2 scope"
//ww:run
package main;
type s1t = str;
type s2t = s1t;

View File

@@ -1,10 +1,6 @@
//ww:error "runtime initializer unsupported (alloc/call; rule 7)"
// Module-scope alloc initializer: no DATAW slot exists for a
// runtime-computed global, so pre-reject every reference died at
// LINK time ("undefined reference to 'main.gp'") — the checker now
// rejects at the declaration on both frontends (Hare model:
// ref/harec/src/check.c:4360 rejects non-compile-time-evaluable
// global initializers; ww has no @init path).
//ww:run
// A module-scope allocation is evaluated once by the package task before
// main; its pointer remains live in the zero-backed package variable.
package main;
type box = struct { s: str, n: int };
let gp = alloc(box { s = "hi", n = 1 })!;

View File

@@ -1,7 +1,9 @@
//ww:error "slice-of-{str,slice,tagged} literal static-init unsupported"
//ww:run
package main;
let G: []str = ["aa", "bbb"];
export fn main() i32 = {
if (len(G[0]) != 2) { return 1; };
if (G.len != 2 || G.cap != 2) { return 1; };
if (len(G[0]) != 2) { return 2; };
if (len(G[1]) != 3) { return 3; };
return 0;
};

View File

@@ -1,7 +1,12 @@
//ww:error "repeat with nested-array elements"
// #156/rule-7 carrier: a `...` repeat marker with a nested-array element must
// REJECT on both stages (no consumer needs it; powers_of_ten is fully
// enumerated). From test/wcc/919_array_static_init_run.c nested_ellipsis_reject.
//ww:run
// A fixed outer array gives the nested-row repeat an exact target length.
// Package initialization evaluates the row once and fills every remaining row.
package main;
let A: [4][2]u64 = [[1u64, 2u64]...];
export fn main() i32 = { return 0; };
export fn main() i32 = {
if (A[0][0] != 1 || A[0][1] != 2) { return 1; };
if (A[1][0] != 1 || A[1][1] != 2) { return 2; };
if (A[2][0] != 1 || A[2][1] != 2) { return 3; };
if (A[3][0] != 1 || A[3][1] != 2) { return 4; };
return 0;
};

View File

@@ -1,6 +1,5 @@
//ww:error "runtime initializer unsupported (alloc/call; rule 7)"
// The call sibling of alias_infptr_global's alloc reject: a
// module-scope call initializer has no link-time data either.
//ww:run-exit 7
// A module-scope call initializer executes once in the package task.
package main;
fn mk() i64 = { return 7; };
let gc: i64 = mk();

View File

@@ -1,4 +1,4 @@
//ww:error "slice-of-{str,slice,tagged} literal static-init unsupported"
//ww:run-exit 2
package main;
let g: []str = ["a", "b"];
export fn main() i32 = { return g.len: i32; };

View File

@@ -1,5 +1,12 @@
//ww:error "unsupported variant init"
//ww:run-exit 11
package main;
type u = (int | bool | str);
let g: u = true: u;
export fn main() i32 = { return 0; };
export fn main() i32 = {
match (g) {
case let n: int => return n: i32;
case let b: bool => return 11;
case let s: str => return 22;
};
return 99;
};

View File

@@ -1,5 +1,12 @@
//ww:error "unsupported variant init"
//ww:run-exit 7
package main;
type u = (int | bool | str);
let g: u = 7: u;
export fn main() i32 = { return 0; };
export fn main() i32 = {
match (g) {
case let n: int => return n: i32;
case let b: bool => return 11;
case let s: str => return 22;
};
return 99;
};

View File

@@ -1,4 +1,18 @@
//ww:error "tagged-union array element static-init needs a zero/int payload"
//ww:run-exit 2
package main;
let gs: [2](int | str) = ["hi", 0];
export fn main() int = { return 0; };
export fn main() int = {
match (gs[0]) {
case let n: int => return 10;
case let s: str => {
if (s.len != 2 || s[0] != 104u8 || s[1] != 105u8) {
return 11;
};
};
};
match (gs[1]) {
case let n: int => { if (n != 0) { return 12; }; };
case let s: str => return 13;
};
return 2;
};

View File

@@ -1,5 +1,15 @@
//ww:error "tagged-union struct-field"
//ww:run-exit 2
package main;
type sbox = struct { s: (int | str) };
let g: sbox = sbox { s = "hi" };
export fn main() int = { return 0; };
export fn main() int = {
match (g.s) {
case let n: int => return 10;
case let s: str => {
if (s.len != 2 || s[0] != 104u8 || s[1] != 105u8) {
return 11;
};
};
};
return 2;
};

View File

@@ -1,9 +1,11 @@
//ww:error "slice-of-{str,slice,tagged} literal static-init unsupported"
//ww:run-exit 0
package main;
type ms0 = str;
type ms = ms0;
let G: []ms = ["aa", "bbb"];
export fn main() i32 = {
if (len(G[0]) != 2) { return 1; };
if (G.len != 2 || G.cap != 2) { return 1; };
if (len(G[0]) != 2) { return 2; };
if (len(G[1]) != 3) { return 3; };
return 0;
};

View File

@@ -1,4 +1,4 @@
//ww:error "unsupported element init (int/str literals only; rule 7)"
//ww:run-exit 4
package main;
let g: ((void | size), i64) = (5, 4);
export fn main() i32 = { return g.1: i32; };

View File

@@ -1,4 +1,4 @@
//ww:error "unsupported element init (int/str literals only; rule 7)"
//ww:run
package main;
let g: (f64, i64) = (2.5, 4);
export fn main() i32 = {

View File

@@ -2,15 +2,15 @@ package collide_test;
// Cross-module leaf-name collision observers on both driver stages.
// Ports of the retired native carriers test/wcc/989_fnptrcollide_run.c
// and 989_barefn_collide_run.c; every assertion preserved.
// and 989_barefn_collide_run.c; their collision teeth remain explicit under
// the package-initialization contract.
//
// fnptrcollide (#14 F7-c7) — a data global `slot: i64` whose LEAF
// collides with the imported fn bar.slot must FAIL to build on BOTH
// stages: type-keyed nodefnptr refuses to fold `&slot` into the fn's
// TEXT reloc. Pre-fix wwstage was name-keyed and silently BUILT it
// (a DATAR to the fn symbol — cat-A: cs loud-fails, ww builds). The
// collision REQUIRES the import path (imported fn leaf vs local data
// global), so a single-file fixture cannot express it.
// fnptrcollide (#14 F7-c7) — a data global `slot: i64` whose leaf
// collides with imported fn bar.slot. `let fp: *i64 = &slot` is valid
// runtime package initialization: both stages must address main.slot,
// initialize fp before main, and run 7. The old loud-reject expectation
// predated runtime package lets. The collision still requires an import,
// and name-keyed lowering to bar.slot is rejected by exact asm/runtime pins.
//
// barefn (#84/#24a) — a `package main;` root `fn run` coexists with
// imported aa.run: build+run exit 9 on BOTH stages while an explicit
@@ -52,32 +52,86 @@ fn runcode(dir: str, name: str, argv: []str) i32 = {
};
@test fn fnptrcollide() void = {
let td: str = testenv.fresh();
let bar: str = strings.concat(td, "/bar");
let main: str = strings.concat(td, "/main");
assert(os.mkdir(bar, 493) == 0);
assert(os.mkdir(main, 493) == 0);
testenv.writefile(strings.concat(bar, "/bar.ww"), strings.concat(
"package bar;\n",
"export fn slot() i64 = { return 99; };\n"));
testenv.writefile(strings.concat(main, "/main.ww"), strings.concat(
"package main;\n",
"import bar;\n",
"let slot: i64 = 7;\n",
"let fp: *i64 = &slot;\n",
"export fn main() int = { let _ = bar.slot(); ",
"return (*fp): int; };\n"));
let drvs: []str = ["ww", "ww_ww"];
let tags: []str = ["cs", "ww"];
let works: []str = [strings.concat(td, "/work-c"),
strings.concat(td, "/work-ww")];
let progs: []str = [strings.concat(td, "/prog.cs"),
strings.concat(td, "/prog.ww")];
let i: i32 = 0;
for (i < 2) {
let td: str = testenv.fresh();
assert(os.mkdir(strings.concat(td, "/bar"), 493) == 0);
testenv.writefile(strings.concat(td, "/bar/bar.ww"),
strings.concat(
"package bar;\n",
"export fn slot() i64 = { return 99; };\n"));
testenv.writefile(strings.concat(td, "/main.ww"), strings.concat(
"package main;\n",
"import bar;\n",
"let slot: i64 = 7;\n",
"let fp: *i64 = &slot;\n",
"export fn main() int = { let _ = bar.slot(); ",
"return (*fp): int; };\n"));
let av: []str = [testenv.driver(drvs[i]), "build", "-I", "bar",
"main.ww"];
if (runcode(td, strings.concat("build_", drvs[i]), av) == 0) {
fail("fnptrcollide", strings.concat(drvs[i], " built ok, ",
"expected the leaf-name collision to be rejected (#14 -- ",
"&slot mis-folded to the fn TEXT reloc)"));
assert(os.mkdir(works[i], 493) == 0);
let av: []str = [testenv.driver(drvs[i]), "build", "-w", works[i],
"-I", td, "-o", progs[i], "main"];
if (runcode(td, strings.concat("build_", tags[i]), av) != 0) {
fail("fnptrcollide", strings.concat(drvs[i], " build failed"));
};
let rav: []str = [progs[i]];
if (runcode(td, strings.concat("run_", tags[i]), rav) != 7) {
fail("fnptrcollide", strings.concat(drvs[i], " exit != 7"));
};
let sourceasm: str = testenv.readfile(strings.concat(works[i],
"/main.s"));
let initasm: str = testenv.readfile(strings.concat(works[i],
"/main.init.s"));
let barasm: str = testenv.readfile(strings.concat(works[i], "/bar.s"));
if (testenv.occurrences(sourceasm, "DATAW main.slot(SB)") != 1
|| testenv.occurrences(sourceasm, "DATAW main.fp(SB)") != 1
|| testenv.occurrences(sourceasm,
"CALL\t__ww..dispatch(SB)") != 1
|| testenv.occurrences(sourceasm,
"LEAQ\tmain.slot(SB), AX") != 1
|| testenv.occurrences(sourceasm,
"MOVQ\tAX, main.fp(SB)") != 1
|| testenv.has(sourceasm, "LEAQ\tbar.slot(SB)")
|| testenv.has(sourceasm, "DATAR main.fp")
|| testenv.occurrences(initasm,
"CALL\t__ww..pkg.p.bar.v0.r0.init(SB)") != 1
|| testenv.occurrences(initasm,
"CALL\t__ww..pkg.p.main.v0.r0.init(SB)") != 1
|| testenv.occurrences(barasm, "TEXT bar.slot,") != 1) {
fail("fnptrcollide", "runtime initializer selected the colliding fn");
};
testenv.clean(td);
i += 1;
};
let wantdispatch: str = strings.concat(
"//ww:init-root __ww..pkg.p.main.v0.r0.init\n",
"//ww:init-call __ww..pkg.p.bar.v0.r0.init\n",
"//ww:init-call __ww..pkg.p.main.v0.r0.init\n");
if (!testenv.same(wantdispatch, testenv.readfile(strings.concat(works[0],
"/main.init.unit.ww")))) {
fail("fnptrcollide", "dispatcher did not initialize dependency first");
};
let names: []str = ["bar.unit.ww", "bar.wwi", "bar.s", "bar.o", "bar.a",
"main.unit.ww", "main.wwi", "main.s", "main.o", "main.a",
"main.init.unit.ww", "main.init.s", "main.init.o"];
i = 0;
for (i < names.len) {
if (!testenv.same(testenv.readfile(strings.concat(works[0], "/", names[i])),
testenv.readfile(strings.concat(works[1], "/", names[i])))) {
fail("fnptrcollide", strings.concat(names[i], " differs by stage"));
};
i += 1;
};
if (!testenv.same(testenv.readfile(progs[0]), testenv.readfile(progs[1]))) {
fail("fnptrcollide", "Cstage/WWstage binaries differ");
};
testenv.clean(td);
};
// __root.s then aa.s: the carrier's fixed #93 sep concat order.