fix: reject bare import bindings

This commit is contained in:
2026-08-22 15:17:10 +09:00
parent 91fce80b37
commit 89f519d5cb
6 changed files with 1490 additions and 38 deletions

View File

@@ -13267,7 +13267,7 @@ fn runtimepath(relative: str) str = {
"cmd.duplicate", "cmd.collision", "cmd.crosscollision",
"cmd.programuser"];
let rejectneedles: []str = ["undefined: codec",
"package 'wire' is not directly imported",
"undefined: wire",
"same redeclared in this block",
"same already declared through import of package same",
"same already declared through import of package same",
@@ -13297,6 +13297,7 @@ fn runtimepath(relative: str) str = {
"$WORK/cmd.collision.unit.new:3:1: error: \"scope.one\" imported as same and not used\n",
"$WORK/cmd.collision.unit.new:4:1: error: same already declared through import of package same (\"scope.one\")\n",
"\t$WORK/cmd.collision.unit.new:3:1: other declaration of same\n",
"$WORK/cmd.collision.unit.new:5:26: error: use of package same not in selector\n",
"ww: w6c failed for cmd.collision\n")));
};
if (si == 0) { diagnosticrefs[rj] = strings.dup(normalized); }
@@ -13681,7 +13682,7 @@ fn runtimepath(relative: str) str = {
"", "", "", "", "", ""];
let needles: []str = ["undefined: value", "unknown type 'Thing'",
"undefined: DEFINED", "undefined: CONSTANT", "undefined: VARIABLE",
"unknown type 'wire.Thing'", "package 'stable' is not directly imported",
"unknown type 'wire.Thing'", "undefined: stable",
"wire redeclared in this block", "stable redeclared in this block",
"wire redeclared in this block",
"stable already declared through import of package stable",
@@ -13728,6 +13729,7 @@ fn runtimepath(relative: str) str = {
"$WORK/cmd.declcollision.unit.new:3:1: error: \"pkg.one\" imported as stable and not used\n",
"$WORK/cmd.declcollision.unit.new:4:1: error: stable already declared through import of package stable (\"pkg.one\")\n",
"\t$WORK/cmd.declcollision.unit.new:3:1: other declaration of stable\n",
"$WORK/cmd.declcollision.unit.new:5:26: error: use of package stable not in selector\n",
"ww: w6c failed for cmd.declcollision\n"),
strings.concat(
"$WORK/cmd.unusedalias.unit.new:3:1: error: \"pkg.one\" imported as stable and not used\n",
@@ -19041,3 +19043,703 @@ fn runtimepath(relative: str) str = {
&& !directoryhasfragment(root, ".install"));
clean(root);
};
// An effective import name is a file-local package qualifier. It may qualify
// selectors, but it is neither a value nor a type by itself. Keep that rule at
// semantic checking, before a malformed binding can leak into code generation
// or linking, and preserve the ordinary undefined boundary in sibling files and
// after blank imports.
@test fn bare_import_bindings_require_selectors() void = {
let root: str = fresh();
let source: str = strings.concat(root, "/source");
let dependency: str = strings.concat(source, "/dep/wire");
let sizedependency: str = strings.concat(source, "/dep/size");
let cases: []str = ["bareonly", "aliasonly", "selectorbare",
"bareselector", "multiple", "typeonly", "aliastype", "typeselector",
"builtinalias", "builtincallee", "arraydim", "enumvalue",
"nestedconst", "nestedarg", "structhead", "structfieldtype",
"casttype", "builtincall", "sibling", "siblingtype", "transitive",
"blank", "initcase", "missing", "packagecalleeprim",
"packagecalleetype", "packagecalleealign", "arraypackagecallee",
"enumpackagecalleealign"];
let ci: i32 = 0;
mkdirall(dependency);
mkdirall(sizedependency);
for (ci < cases.len) {
mkdirall(strings.concat(source, "/", cases[ci]));
ci += 1;
};
writefile(strings.concat(dependency, "/wire.ww"), strings.concat(
"package wire;\n",
"export type record = struct { n: i32 };\n",
"export fn value() i32 = { return 41; };\n"));
writefile(strings.concat(sizedependency, "/size.ww"),
"package size;\nexport fn value() i32 = { return 1; };\n");
writefile(strings.concat(source, "/bareonly/main.ww"), strings.concat(
"package main;\nimport dep.wire;\n",
"fn main() i32 = { let bad: i32 = wire; return bad; };\n"));
writefile(strings.concat(source, "/aliasonly/main.ww"), strings.concat(
"package main;\nimport stable dep.wire;\n",
"fn main() i32 = { let bad: i32 = stable; return bad; };\n"));
writefile(strings.concat(source, "/selectorbare/main.ww"), strings.concat(
"package main;\nimport dep.wire;\n",
"fn main() i32 = { let ok: i32 = wire.value(); ",
"let bad: i32 = wire; return ok + bad; };\n"));
writefile(strings.concat(source, "/bareselector/main.ww"), strings.concat(
"package main;\nimport dep.wire;\n",
"fn main() i32 = { let bad: i32 = wire; ",
"return bad + wire.value(); };\n"));
writefile(strings.concat(source, "/multiple/main.ww"), strings.concat(
"package main;\nimport dep.wire;\n",
"fn main() i32 = { let ok: i32 = wire.value(); ",
"let a: i32 = wire; let b: i32 = wire; return ok + a + b; };\n"));
writefile(strings.concat(source, "/typeonly/main.ww"), strings.concat(
"package main;\nimport dep.wire;\n",
"fn bad(v: wire) i32 = { return 0; };\n",
"fn main() i32 = { return 0; };\n"));
writefile(strings.concat(source, "/aliastype/main.ww"), strings.concat(
"package main;\nimport stable dep.wire;\n",
"fn bad(v: stable) i32 = { return 0; };\n",
"fn main() i32 = { return 0; };\n"));
writefile(strings.concat(source, "/typeselector/main.ww"), strings.concat(
"package main;\nimport dep.wire;\n",
"fn bad(v: wire) i32 = { return 0; };\n",
"fn main() i32 = { return wire.value(); };\n"));
writefile(strings.concat(source, "/builtinalias/main.ww"), strings.concat(
"package main;\nimport len dep.wire;\n",
"fn main() i32 = { let ok: i32 = len.value(); ",
"let bad: i32 = len; return ok + bad; };\n"));
writefile(strings.concat(source, "/builtincallee/main.ww"), strings.concat(
"package main;\nimport len dep.wire;\n",
"fn main() i32 = { return len(\"abc\"); };\n"));
writefile(strings.concat(source, "/arraydim/main.ww"), strings.concat(
"package main;\nimport dep.wire;\n",
"let bad: [wire]i32;\nfn main() i32 = { return 0; };\n"));
writefile(strings.concat(source, "/enumvalue/main.ww"), strings.concat(
"package main;\nimport dep.wire;\n",
"type bad = enum { ZERO = wire };\n",
"fn main() i32 = { return 0; };\n"));
writefile(strings.concat(source, "/nestedconst/main.ww"), strings.concat(
"package main;\nimport dep.wire;\n",
"def BAD: i32 = 1 + (wire + wire);\n",
"fn main() i32 = { return 0; };\n"));
writefile(strings.concat(source, "/nestedarg/main.ww"), strings.concat(
"package main;\nimport dep.wire;\n",
"fn take(v: i32) i32 = { return v; };\n",
"fn main() i32 = { return take(wire.value() + (1 + wire)); };\n"));
writefile(strings.concat(source, "/structhead/main.ww"), strings.concat(
"package main;\nimport dep.wire;\n",
"fn main() i32 = { let bad = wire { n = 1 }; return bad.n; };\n"));
writefile(strings.concat(source, "/structfieldtype/main.ww"), strings.concat(
"package main;\nimport dep.wire;\n",
"type holder = struct { bad: wire };\n",
"fn main() i32 = { return 0; };\n"));
writefile(strings.concat(source, "/casttype/main.ww"), strings.concat(
"package main;\nimport dep.wire;\n",
"fn main() i32 = { let bad = 0: wire; return 0; };\n"));
writefile(strings.concat(source, "/builtincall/main.ww"), strings.concat(
"package main;\nimport dep.wire;\n",
"fn main() size = { return size(wire); };\n"));
writefile(strings.concat(source, "/sibling/a.ww"), strings.concat(
"package main;\nimport dep.wire;\n",
"fn anchor() i32 = { return wire.value(); };\n"));
writefile(strings.concat(source, "/sibling/b.ww"), strings.concat(
"package main;\n",
"fn bad() i32 = { let v: i32 = wire; return v; };\n",
"fn main() i32 = { return anchor() + bad(); };\n"));
writefile(strings.concat(source, "/siblingtype/a.ww"), strings.concat(
"package main;\nimport dep.wire;\n",
"fn anchor() i32 = { return wire.value(); };\n"));
writefile(strings.concat(source, "/siblingtype/b.ww"), strings.concat(
"package main;\nfn bad(v: wire) i32 = { return 0; };\n",
"fn main() i32 = { return anchor(); };\n"));
let middle: str = strings.concat(source, "/dep/middle");
mkdirall(middle);
writefile(strings.concat(middle, "/middle.ww"), strings.concat(
"package middle;\nimport dep.wire;\n",
"export fn value() i32 = { return wire.value(); };\n"));
writefile(strings.concat(source, "/transitive/main.ww"), strings.concat(
"package main;\nimport dep.middle;\n",
"fn main() i32 = { let ok: i32 = middle.value(); ",
"let bad: i32 = wire; return ok + bad; };\n"));
writefile(strings.concat(source, "/blank/main.ww"), strings.concat(
"package main;\nimport _ dep.wire;\n",
"fn main() i32 = { let v: i32 = wire; return v; };\n"));
writefile(strings.concat(source, "/initcase/main.ww"), strings.concat(
"package main;\nimport init dep.wire;\n",
"fn main() i32 = { return 0; };\n"));
writefile(strings.concat(source, "/missing/main.ww"), strings.concat(
"package main;\nimport stable dep.absent;\n",
"fn main() i32 = { let v: i32 = stable; return v; };\n"));
writefile(strings.concat(source, "/packagecalleeprim/main.ww"), strings.concat(
"package main;\nimport dep.size;\n",
"fn main() i32 = { return size(i32): i32; };\n"));
writefile(strings.concat(source, "/packagecalleetype/main.ww"), strings.concat(
"package main;\nimport dep.size;\nimport dep.wire;\n",
"fn main() i32 = { return size(wire): i32; };\n"));
writefile(strings.concat(source, "/packagecalleealign/main.ww"), strings.concat(
"package main;\nimport align dep.size;\nimport dep.wire;\n",
"fn main() i32 = { return align(wire): i32; };\n"));
writefile(strings.concat(source, "/arraypackagecallee/main.ww"), strings.concat(
"package main;\nimport dep.size;\nimport dep.wire;\n",
"let bad: [size(wire)]u8;\nfn main() i32 = { return 0; };\n"));
writefile(strings.concat(source, "/enumpackagecalleealign/main.ww"),
strings.concat("package main;\nimport align dep.size;\nimport dep.wire;\n",
"type bad = enum { ZERO = align(wire) };\n",
"fn main() i32 = { return 0; };\n"));
let valuecore: str = "use of package wire not in selector";
let aliascore: str = "use of package stable not in selector";
let builtinaliascore: str = "use of package len not in selector";
let sizecore: str = "use of package size not in selector";
let aligncore: str = "use of package align not in selector";
let typecore: str = "wire (package name) is not a type";
let aliastypecore: str = "stable (package name) is not a type";
let kinds: []i32 = [1, 6, 1, 1, 7, 2, 9, 2, 8, 8, 1, 1, 7, 1,
2, 2, 2, 2, 3, 10, 3, 3, 4, 5, 11, 12, 13, 12, 13];
let unusedcounts: []i32 = [1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1,
0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 2, 2, 2, 2];
let stages: []str = ["ww", "ww_ww"];
let tags: []str = ["c", "ww"];
let diagrefs: []str = alloc([], cases.len: u64)!;
ci = 0;
for (ci < cases.len) { append(diagrefs, ""); ci += 1; };
let si: i32 = 0;
for (si < stages.len) {
ci = 0;
for (ci < cases.len) {
let work: str = strings.concat(root, "/matrix-work-", tags[si],
"-", boundarypkgname(ci));
let output: str = strings.concat(root, "/matrix-output-", tags[si],
"-", boundarypkgname(ci));
mkdirall(work);
let av: []str = [driver(stages[si]), "build", "-w", work,
"-I", source, "-o", output, cases[ci]];
let out: commandout;
runcommand(root, strings.concat("bare-import-matrix-", tags[si],
"-", boundarypkgname(ci)), av,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(out.stdout.len == 0 && !os.exists(output)
&& !os.exists(strings.concat(output, ".new"))
&& !os.exists(strings.concat(output, ".sepwork"))
&& directoryisempty(work));
assert(!has(out.stderr, "undefined reference")
&& !has(out.stderr, "cgident: unresolvable identifier"));
if (kinds[ci] == 1) {
assert(occurrences(out.stderr, valuecore) == 1);
} else if (kinds[ci] == 2) {
assert(occurrences(out.stderr, typecore) == 1);
} else if (kinds[ci] == 3) {
assert(occurrences(out.stderr, "undefined: wire") == 1
&& !has(out.stderr, "package name) is not a type")
&& !has(out.stderr, "not in selector"));
} else if (kinds[ci] == 4) {
assert(occurrences(out.stderr,
"cannot import package as init - init must be a func") == 1
&& !has(out.stderr, "not in selector")
&& !has(out.stderr, "package name) is not a type"));
} else if (kinds[ci] == 5) {
assert(occurrences(out.stderr,
"cannot find package dep.absent") == 1
&& !has(out.stderr, "not in selector")
&& !has(out.stderr, "package name) is not a type"));
} else if (kinds[ci] == 6) {
assert(occurrences(out.stderr, aliascore) == 1);
} else if (kinds[ci] == 7) {
assert(occurrences(out.stderr, valuecore) == 2);
} else if (kinds[ci] == 8) {
assert(occurrences(out.stderr, builtinaliascore) == 1);
} else if (kinds[ci] == 10) {
assert(occurrences(out.stderr, "unknown type 'wire'") == 1
&& !has(out.stderr, "package name) is not a type")
&& !has(out.stderr, "not in selector"));
} else if (kinds[ci] == 11) {
assert(occurrences(out.stderr, sizecore) == 1
&& !has(out.stderr, "internal: unhandled expr kind")
&& !has(out.stderr, "package name) is not a type"));
} else if (kinds[ci] == 12) {
assert(occurrences(out.stderr, sizecore) == 1
&& occurrences(out.stderr, typecore) == 1
&& !has(out.stderr, "internal: unhandled expr kind"));
} else if (kinds[ci] == 13) {
assert(occurrences(out.stderr, aligncore) == 1
&& occurrences(out.stderr, typecore) == 1
&& !has(out.stderr, "internal: unhandled expr kind"));
} else {
assert(occurrences(out.stderr, aliastypecore) == 1);
};
assert(occurrences(out.stderr, "not used") == unusedcounts[ci]);
assert(!has(out.stderr, "array length must be an integer literal")
&& !has(out.stderr,
"enum value must be a constant integer expression")
&& !has(out.stderr, "arithmetic on non-numeric type")
&& !has(out.stderr, "unknown struct type")
&& !has(out.stderr, "called object is not a function")
&& !has(out.stderr, "asserttyped:"));
let normalized: str = normalizedtrace(out.stderr,
strings.concat(work, "/"), output);
if (ci == 0) {
assert(same(normalized, strings.concat(
"$WORK/bareonly.unit.new:3:1: error: ",
"\"dep.wire\" imported and not used\n",
"$WORK/bareonly.unit.new:4:34: error: ", valuecore, "\n",
"ww: w6c failed for bareonly\n")));
} else if (ci == 4) {
assert(same(normalized, strings.concat(
"$WORK/multiple.unit.new:4:60: error: ", valuecore, "\n",
"$WORK/multiple.unit.new:4:79: error: ", valuecore, "\n",
"ww: w6c failed for multiple\n")));
} else if (ci == 5) {
assert(same(normalized, strings.concat(
"$WORK/typeonly.unit.new:3:1: error: ",
"\"dep.wire\" imported and not used\n",
"$WORK/typeonly.unit.new:4:11: error: ", typecore, "\n",
"ww: w6c failed for typeonly\n")));
} else if (ci == 9) {
assert(same(normalized, strings.concat(
"$WORK/builtincallee.unit.new:3:1: error: ",
"\"dep.wire\" imported as len and not used\n",
"$WORK/builtincallee.unit.new:4:26: error: ",
builtinaliascore, "\n",
"ww: w6c failed for builtincallee\n")));
} else if (ci == 10) {
assert(same(normalized, strings.concat(
"$WORK/arraydim.unit.new:3:1: error: ",
"\"dep.wire\" imported and not used\n",
"$WORK/arraydim.unit.new:4:11: error: ", valuecore, "\n",
"ww: w6c failed for arraydim\n")));
} else if (ci == 12) {
assert(same(normalized, strings.concat(
"$WORK/nestedconst.unit.new:3:1: error: ",
"\"dep.wire\" imported and not used\n",
"$WORK/nestedconst.unit.new:4:21: error: ", valuecore, "\n",
"$WORK/nestedconst.unit.new:4:28: error: ", valuecore, "\n",
"ww: w6c failed for nestedconst\n")));
} else if (ci == 13) {
assert(same(normalized, strings.concat(
"$WORK/nestedarg.unit.new:5:51: error: ", valuecore, "\n",
"ww: w6c failed for nestedarg\n")));
} else if (ci == 18) {
assert(same(normalized, strings.concat(
"$WORK/sibling.unit.new:8:31: error: undefined: wire\n",
"ww: w6c failed for sibling\n")));
} else if (ci == 24) {
assert(same(normalized, strings.concat(
"$WORK/packagecalleeprim.unit.new:3:1: error: ",
"\"dep.size\" imported and not used\n",
"$WORK/packagecalleeprim.unit.new:4:26: error: ", sizecore,
"\nww: w6c failed for packagecalleeprim\n")));
} else if (ci == 25) {
assert(same(normalized, strings.concat(
"$WORK/packagecalleetype.unit.new:3:1: error: ",
"\"dep.size\" imported and not used\n",
"$WORK/packagecalleetype.unit.new:4:1: error: ",
"\"dep.wire\" imported and not used\n",
"$WORK/packagecalleetype.unit.new:5:26: error: ", sizecore,
"\n$WORK/packagecalleetype.unit.new:5:31: error: ", typecore,
"\nww: w6c failed for packagecalleetype\n")));
} else if (ci == 26) {
assert(same(normalized, strings.concat(
"$WORK/packagecalleealign.unit.new:3:1: error: ",
"\"dep.size\" imported as align and not used\n",
"$WORK/packagecalleealign.unit.new:4:1: error: ",
"\"dep.wire\" imported and not used\n",
"$WORK/packagecalleealign.unit.new:5:26: error: ", aligncore,
"\n$WORK/packagecalleealign.unit.new:5:32: error: ", typecore,
"\nww: w6c failed for packagecalleealign\n")));
} else if (ci == 27) {
assert(same(normalized, strings.concat(
"$WORK/arraypackagecallee.unit.new:3:1: error: ",
"\"dep.size\" imported and not used\n",
"$WORK/arraypackagecallee.unit.new:4:1: error: ",
"\"dep.wire\" imported and not used\n",
"$WORK/arraypackagecallee.unit.new:5:11: error: ", sizecore,
"\n$WORK/arraypackagecallee.unit.new:5:16: error: ", typecore,
"\nww: w6c failed for arraypackagecallee\n")));
} else if (ci == 28) {
assert(same(normalized, strings.concat(
"$WORK/enumpackagecalleealign.unit.new:3:1: error: ",
"\"dep.size\" imported as align and not used\n",
"$WORK/enumpackagecalleealign.unit.new:4:1: error: ",
"\"dep.wire\" imported and not used\n",
"$WORK/enumpackagecalleealign.unit.new:5:26: error: ", aligncore,
"\n$WORK/enumpackagecalleealign.unit.new:5:32: error: ", typecore,
"\nww: w6c failed for enumpackagecalleealign\n")));
};
if (si == 0) { diagrefs[ci] = strings.dup(normalized); }
else { assert(same(diagrefs[ci], normalized)); };
ci += 1;
};
si += 1;
};
// A raw source operand uses the same file-local import object and checker.
let raw: str = strings.concat(root, "/raw.ww");
writefile(raw, strings.concat(
"package main;\nimport dep.wire;\n",
"fn main() i32 = { let ok: i32 = wire.value(); ",
"let bad: i32 = wire; return ok + bad; };\n"));
let rawdiag: str = "";
si = 0;
for (si < stages.len) {
let work: str = strings.concat(root, "/raw-work-", tags[si]);
let output: str = strings.concat(root, "/raw-output-", tags[si]);
mkdirall(work);
let av: []str = [driver(stages[si]), "build", "-w", work,
"-I", source, "-o", output, raw];
let out: commandout;
runcommand(root, strings.concat("bare-import-raw-", tags[si]), av,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(out.stdout.len == 0 && occurrences(out.stderr, valuecore) == 1
&& !has(out.stderr, "imported as wire and not used")
&& !os.exists(output) && directoryisempty(work));
let normalized: str = normalizedtrace(out.stderr,
strings.concat(work, "/"), output);
if (si == 0) { rawdiag = strings.dup(normalized); }
else { assert(same(rawdiag, normalized)); };
si += 1;
};
// Valid selector use still owns import usage, artifact construction, and
// execution. Every comparable semantic action and public binary is exact.
let control: str = strings.concat(source, "/control");
mkdirall(control);
writefile(strings.concat(control, "/main.ww"), strings.concat(
"package main;\nimport dep.wire;\n",
"fn main() i32 = { let r: wire.record = wire.record { n = 0 }; ",
"return wire.value() + r.n; };\n"));
let suffixes: []str = [".unit.ww", ".wwi", ".s", ".o", ".a",
".init.unit.ww", ".init.s", ".init.o"];
let controlrefs: []str = alloc([], suffixes.len: u64)!;
let controlbin: str = "";
si = 0;
for (si < stages.len) {
let work: str = strings.concat(root, "/control-work-", tags[si]);
let output: str = strings.concat(root, "/control-output-", tags[si]);
mkdirall(work);
let av: []str = [driver(stages[si]), "build", "-w", work,
"-I", source, "-o", output, "control"];
let out: commandout;
runcommand(root, strings.concat("bare-import-control-", tags[si]), av,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(out.stdout.len == 0 && out.stderr.len == 0 && os.exists(output)
&& !directoryhasnew(work)
&& !directoryhasfragment(work, ".wwtxn."));
let runav: []str = [output];
runcommand(root, strings.concat("bare-import-control-run-", tags[si]),
runav, time.second, &out);
expectexit(&out, 41);
assert(out.stdout.len == 0 && out.stderr.len == 0);
let fi: i32 = 0;
for (fi < suffixes.len) {
let bytes: str = readfile(strings.concat(work, "/control",
suffixes[fi]));
if (si == 0) { append(controlrefs, strings.dup(bytes)); }
else { assert(same(controlrefs[fi], bytes)); };
fi += 1;
};
if (si == 0) { controlbin = strings.dup(readfile(output)); }
else { assert(same(controlbin, readfile(output))); };
si += 1;
};
// Production, same-package, external, honest test-only, a production
// function reached by a test, and an imported dependency all reject before
// test-main publication or execution. A filter cannot hide source errors.
let testtargets: []str = ["prodcase", "samecase", "externalcase",
"onlycase", "calledcase", "importedcase"];
ci = 0;
for (ci < testtargets.len) {
mkdirall(strings.concat(source, "/", testtargets[ci]));
ci += 1;
};
writefile(strings.concat(source, "/prodcase/prod.ww"), strings.concat(
"package prodcase;\nimport dep.wire;\n",
"fn bad() i32 = { let ok: i32 = wire.value(); ",
"let v: i32 = wire; return ok + v; };\n"));
writefile(strings.concat(source, "/prodcase/prod_test.ww"),
"package prodcase;\n@test fn must_not_run() void = { abort(); };\n");
writefile(strings.concat(source, "/samecase/prod.ww"),
"package samecase;\nfn value() i32 = { return 1; };\n");
writefile(strings.concat(source, "/samecase/same_test.ww"), strings.concat(
"package samecase;\nimport dep.wire;\n",
"@test fn must_not_run() void = { let ok: i32 = wire.value(); ",
"let bad: i32 = wire; abort(); };\n"));
writefile(strings.concat(source, "/externalcase/prod.ww"), strings.concat(
"package externalcase;\n",
"export fn value() i32 = { return 1; };\n"));
writefile(strings.concat(source, "/externalcase/external_test.ww"),
strings.concat("package externalcase_test;\nimport dep.wire;\n",
"@test fn must_not_run() void = { let ok: i32 = wire.value(); ",
"let bad: i32 = wire; abort(); };\n"));
writefile(strings.concat(source, "/onlycase/only_test.ww"), strings.concat(
"package onlycase;\nimport dep.wire;\n",
"@test fn must_not_run() void = { let ok: i32 = wire.value(); ",
"let bad: i32 = wire; abort(); };\n"));
writefile(strings.concat(source, "/calledcase/prod.ww"), strings.concat(
"package calledcase;\nimport dep.wire;\n",
"fn bad() i32 = { let ok: i32 = wire.value(); ",
"let v: i32 = wire; return ok + v; };\n"));
writefile(strings.concat(source, "/calledcase/called_test.ww"),
"package calledcase;\n@test fn must_not_run() void = { assert(bad() > 0); };\n");
let baddep: str = strings.concat(source, "/dep/baddep");
let buildimport: str = strings.concat(source, "/buildimport");
mkdirall(baddep);
mkdirall(buildimport);
writefile(strings.concat(baddep, "/baddep.ww"), strings.concat(
"package baddep;\nimport dep.wire;\n",
"export fn bad() i32 = { let ok: i32 = wire.value(); ",
"let v: i32 = wire; return ok + v; };\n"));
writefile(strings.concat(source, "/importedcase/prod.ww"), strings.concat(
"package importedcase;\nimport dep.baddep;\n",
"fn value() i32 = { return baddep.bad(); };\n"));
writefile(strings.concat(source, "/importedcase/imported_test.ww"),
"package importedcase;\n@test fn must_not_run() void = { assert(value() > 0); };\n");
writefile(strings.concat(buildimport, "/main.ww"), strings.concat(
"package main;\nimport dep.baddep;\n",
"fn main() i32 = { return baddep.bad(); };\n"));
let testdiagrefs: []str = alloc([], testtargets.len: u64)!;
ci = 0;
for (ci < testtargets.len) { append(testdiagrefs, ""); ci += 1; };
si = 0;
for (si < stages.len) {
ci = 0;
for (ci < testtargets.len) {
let work: str = strings.concat(root, "/test-work-", tags[si], "-",
boundarypkgname(ci));
let output: str = strings.concat(root, "/test-output-", tags[si], "-",
boundarypkgname(ci));
mkdirall(work);
let av: []str = [driver(stages[si]), "test", "-w", work,
"-I", source, "-run", "must_not_run", "-o", output,
testtargets[ci]];
let out: commandout;
runcommand(root, strings.concat("bare-import-test-", tags[si], "-",
boundarypkgname(ci)), av,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(same(out.stdout, "FAIL\n")
&& occurrences(out.stderr, valuecore) == 1
&& !has(out.stderr, "undefined reference")
&& !has(out.stderr, "cgident: unresolvable identifier")
&& !has(out.stdout, "must_not_run ...")
&& !os.exists(output)
&& !os.exists(strings.concat(output, ".new"))
&& !os.exists(strings.concat(output, ".sepwork"))
&& directoryisempty(work));
let normalized: str = normalizedtrace(out.stderr,
strings.concat(work, "/"), output);
if (si == 0) { testdiagrefs[ci] = strings.dup(normalized); }
else { assert(same(testdiagrefs[ci], normalized)); };
ci += 1;
};
si += 1;
};
// Ordinary build reaches the same invalid dependency compiler action, and
// a genuinely empty test selection still compiles selected source before
// considering whether any runtime test would match.
let buildimportdiag: str = "";
let nomatchdiag: str = "";
si = 0;
for (si < stages.len) {
let buildwork: str = strings.concat(root, "/buildimport-work-", tags[si]);
let buildout: str = strings.concat(root, "/buildimport-output-", tags[si]);
mkdirall(buildwork);
let buildav: []str = [driver(stages[si]), "build", "-w", buildwork,
"-I", source, "-o", buildout, "buildimport"];
let out: commandout;
runcommand(root, strings.concat("bare-import-build-dependency-", tags[si]),
buildav, (120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(out.stdout.len == 0 && occurrences(out.stderr, valuecore) == 1
&& !has(out.stderr, "undefined reference")
&& !has(out.stderr, "cgident: unresolvable identifier")
&& !has(out.stderr, "asserttyped:")
&& !os.exists(buildout)
&& !os.exists(strings.concat(buildout, ".new"))
&& !os.exists(strings.concat(buildout, ".sepwork"))
&& directoryisempty(buildwork));
let buildnormalized: str = normalizedtrace(out.stderr,
strings.concat(buildwork, "/"), buildout);
if (si == 0) { buildimportdiag = strings.dup(buildnormalized); }
else { assert(same(buildimportdiag, buildnormalized)); };
let testwork: str = strings.concat(root, "/nomatch-work-", tags[si]);
let testout: str = strings.concat(root, "/nomatch-output-", tags[si]);
mkdirall(testwork);
let testav: []str = [driver(stages[si]), "test", "-w", testwork,
"-I", source, "-run", "does_not_match_any_test", "-o", testout,
"samecase"];
runcommand(root, strings.concat("bare-import-test-nomatch-", tags[si]),
testav, (120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(same(out.stdout, "FAIL\n")
&& occurrences(out.stderr, valuecore) == 1
&& !has(out.stdout, "testing: warning: no tests to run")
&& !has(out.stdout, " discovered, ")
&& !has(out.stdout, "must_not_run ...")
&& !has(out.stderr, "undefined reference")
&& !has(out.stderr, "cgident: unresolvable identifier")
&& !has(out.stderr, "asserttyped:")
&& !os.exists(testout)
&& !os.exists(strings.concat(testout, ".new"))
&& !os.exists(strings.concat(testout, ".sepwork"))
&& directoryisempty(testwork));
let testnormalized: str = normalizedtrace(out.stderr,
strings.concat(testwork, "/"), testout);
if (si == 0) { nomatchdiag = strings.dup(testnormalized); }
else { assert(same(nomatchdiag, testnormalized)); };
si += 1;
};
// A warm command keeps its committed graph/actions, package artifacts, and
// public binary across rejection; restoring exact source reuses the same
// semantic generation. The same publication rule protects a filtered,
// retained test binary, which remains directly executable after rejection.
let warm: str = strings.concat(source, "/warm");
mkdirall(warm);
let warmfile: str = strings.concat(warm, "/main.ww");
let warmvalid: str = strings.concat(
"package main;\nimport dep.wire;\n",
"fn main() i32 = { return wire.value(); };\n");
let warminvalid: str = strings.concat(
"package main;\nimport dep.wire;\n",
"fn main() i32 = { let ok: i32 = wire.value(); ",
"let bad: i32 = wire; return ok + bad; };\n");
writefile(warmfile, warmvalid);
let retainedcase: str = strings.concat(source, "/retainedcase");
mkdirall(retainedcase);
let retainedfile: str = strings.concat(retainedcase, "/retained_test.ww");
let retainedvalid: str = strings.concat(
"package retainedcase;\nimport dep.wire;\n",
"@test fn kept() void = { assert(wire.value() == 41); };\n");
let retainedinvalid: str = strings.concat(
"package retainedcase;\nimport dep.wire;\n",
"@test fn kept() void = { let ok: i32 = wire.value(); ",
"let bad: i32 = wire; assert(ok + bad > 0); };\n");
writefile(retainedfile, retainedvalid);
let warmpaths: []str = ["/.wwtool.ww", "/.wwtool.w6c", "/.wwtool.w6a",
"/.wwtool.stamp", "/dep.wire.unit.ww", "/dep.wire.wwi",
"/dep.wire.s", "/dep.wire.o", "/dep.wire.a", "/warm.unit.ww",
"/warm.wwi", "/warm.s", "/warm.o", "/warm.a",
"/warm.init.unit.ww", "/warm.init.s", "/warm.init.o"];
let warmcross: []str = alloc([], warmpaths.len: u64)!;
let warmbincross: str = "";
let retainedcross: str = "";
let directoutrefs: []str = ["", ""];
let directerrrefs: []str = ["", ""];
si = 0;
for (si < stages.len) {
let work: str = strings.concat(root, "/warm-work-", tags[si]);
let output: str = strings.concat(root, "/warm-output-", tags[si]);
mkdirall(work);
let av: []str = [driver(stages[si]), "build", "-w", work,
"-I", source, "-o", output, "warm"];
let out: commandout;
runcommand(root, strings.concat("bare-import-warm-cold-", tags[si]), av,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(out.stdout.len == 0 && out.stderr.len == 0);
let snapshots: []str = alloc([], warmpaths.len: u64)!;
let pi: i32 = 0;
for (pi < warmpaths.len) {
let bytes: str = strings.dup(readfile(strings.concat(work,
warmpaths[pi])));
append(snapshots, bytes);
if (si == 0) { append(warmcross, strings.dup(bytes)); }
else if (pi >= 4) { assert(same(warmcross[pi], bytes)); };
pi += 1;
};
let binbytes: str = strings.dup(readfile(output));
if (si == 0) { warmbincross = strings.dup(binbytes); }
else { assert(same(warmbincross, binbytes)); };
rewritefile(warmfile, warminvalid);
runcommand(root, strings.concat("bare-import-warm-reject-", tags[si]), av,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(out.stdout.len == 0 && occurrences(out.stderr, valuecore) == 1
&& same(binbytes, readfile(output))
&& !os.exists(strings.concat(output, ".new"))
&& !os.exists(strings.concat(output, ".sepwork")));
pi = 0;
for (pi < warmpaths.len) {
assert(same(snapshots[pi], readfile(strings.concat(work,
warmpaths[pi]))));
pi += 1;
};
assert(!directoryhasnew(work)
&& !directoryhasfragment(work, ".wwtxn.")
&& !directoryhasfragment(work, ".install"));
rewritefile(warmfile, warmvalid);
runcommand(root, strings.concat("bare-import-warm-restored-", tags[si]),
av, (120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(out.stdout.len == 0 && out.stderr.len == 0
&& same(binbytes, readfile(output)));
pi = 0;
for (pi < warmpaths.len) {
assert(same(snapshots[pi], readfile(strings.concat(work,
warmpaths[pi]))));
pi += 1;
};
let testwork: str = strings.concat(root, "/retained-work-", tags[si]);
let retained: str = strings.concat(root, "/retained-", tags[si], ".test");
mkdirall(testwork);
let compileav: []str = [driver(stages[si]), "test", "-w",
testwork, "-I", source, "-run", "kept", "-o", retained,
"retainedcase"];
runcommand(root, strings.concat("bare-import-retained-cold-", tags[si]),
compileav, (120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(out.stderr.len == 0 && os.exists(retained)
&& occurrences(out.stdout, "retainedcase.kept ... ok\n") == 1
&& occurrences(out.stdout,
"1 passed, 0 failed, 0 skipped, 0 harness errors\n") == 1);
let retainedstdout: str = strings.dup(out.stdout);
let retainedbytes: str = strings.dup(readfile(retained));
if (si == 0) { retainedcross = strings.dup(retainedbytes); }
else { assert(same(retainedcross, retainedbytes)); };
rewritefile(retainedfile, retainedinvalid);
runcommand(root, strings.concat("bare-import-retained-reject-", tags[si]),
compileav, (120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(same(out.stdout, "FAIL\n")
&& occurrences(out.stderr, valuecore) == 1
&& same(retainedbytes, readfile(retained))
&& !os.exists(strings.concat(retained, ".new"))
&& !os.exists(strings.concat(retained, ".sepwork"))
&& !directoryhasnew(testwork)
&& !directoryhasfragment(testwork, ".wwtxn."));
let directav: []str = [retained, "-package=retainedcase", "kept"];
runcommand(root, strings.concat("bare-import-retained-direct-", tags[si]),
directav, (30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(out.stderr.len == 0
&& occurrences(out.stdout, "retainedcase.kept ... ok\n") == 1
&& occurrences(out.stdout,
"1 passed, 0 failed, 0 skipped, 0 harness errors\n") == 1);
directoutrefs[si] = strings.dup(out.stdout);
directerrrefs[si] = strings.dup(out.stderr);
rewritefile(retainedfile, retainedvalid);
runcommand(root, strings.concat("bare-import-retained-restored-", tags[si]),
compileav, (120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(same(out.stdout, retainedstdout) && out.stderr.len == 0
&& same(retainedbytes, readfile(retained))
&& !directoryhasnew(testwork)
&& !directoryhasfragment(testwork, ".wwtxn.")
&& !directoryhasfragment(testwork, ".install"));
si += 1;
};
assert(same(directoutrefs[0], directoutrefs[1])
&& same(directerrrefs[0], directerrrefs[1]));
assert(!directoryhasnew(root)
&& !directoryhasfragment(root, ".wwtxn.")
&& !directoryhasfragment(root, ".install"));
clean(root);
};