compiler: separate package exports from entry roots

This commit is contained in:
2026-08-12 21:59:51 +09:00
parent a88078faf8
commit fc4bde703e
15 changed files with 420 additions and 190 deletions

View File

@@ -15,11 +15,10 @@ package wwi_test;
// stressor. A synth fixture covers the decl-kinds + type-nodes no lib
// package reaches (def const-expr fold, let global, [N]T, fn-ptr, !T,
// tuple, storage-less enum, and the #47 @symbol round-trip); the types
// gate proves the exported limit defs reach the interface. NEGATIVE: an
// exported fn naming a private nominal must be LOUD-REJECTED by
// check_exported_type identically on both stages (nonzero exit +
// byte-identical diagnostic) — without it a vacuous no-op check would
// pass the positive gate silently.
// gate proves the exported limit defs reach the interface. PRIVATE CLOSURE:
// an exported fn naming a private nominal carries that nominal without
// `export`, remains byte-identical and re-parseable, and still rejects source
// qualification of the compiler-private name on both stages.
//
// wwileaf — BUG-C (#11) regression pin: a decl-less / export-less
// primary module's `.wwi` `package` line must carry the module's real
@@ -273,9 +272,9 @@ fn m2positive(pkg: str) void = {
testenv.clean(td);
};
// negative: an exported fn naming a private nominal must be rejected
// identically (exit + diagnostic) by BOTH stages.
@test fn m2negative() void = {
// A public declaration may reach a private nominal as compiler export data,
// but that private spelling must not become source-importable.
@test fn m2privateclosure() void = {
let td: str = testenv.fresh();
let src: str = strings.concat(
"package leaktest;\n",
@@ -284,24 +283,40 @@ fn m2positive(pkg: str) void = {
"export fn clean(a: i32) i32 = { return a; };\n");
testenv.writefile(strings.concat(td, "/leak.ww"), src);
// relative leak.ww under td so both stages report the bare
// `leak.ww:L:C:` prefix.
let cav: []str = [testenv.driver("w6c"), "-I", "out.wwi", "leak.ww"];
let cco: testenv.commandout;
testenv.runcommand(td, td, "cs", cav, lifetime(), &cco);
let wav: []str = [testenv.driver("w6c_ww"), "-I", "out.wwi", "leak.ww"];
let wco: testenv.commandout;
testenv.runcommand(td, td, "ws", wav, lifetime(), &wco);
let csok: bool = cco.termination == exec.termination.EXIT
&& cco.code == 0;
let wsok: bool = wco.termination == exec.termination.EXIT
&& wco.code == 0;
if (csok || wsok) {
fail("negative", "check_exported_type is vacuous (a stage accepted the private-type leak)");
let cav: []str = [testenv.driver("w6c"), "-I", "cs.wwi", "leak.ww"];
let wav: []str = [testenv.driver("w6c_ww"), "-I", "ww.wwi", "leak.ww"];
if (!runok(td, "cs", cav) || !runok(td, "ws", wav)) {
fail("private-closure", "a stage rejected reachable private type data");
};
if (!testenv.same(cco.stderr, wco.stderr)) {
fail("negative", "reject diagnostics differ across stages (rule-10)");
let csbody: str = testenv.readfile(strings.concat(td, "/cs.wwi"));
let wsbody: str = testenv.readfile(strings.concat(td, "/ww.wwi"));
if (!testenv.same(csbody, wsbody)
|| !testenv.has(csbody, "type secret = struct { x: i32 };")
|| testenv.has(csbody, "export type secret")
|| !testenv.has(csbody, "export fn leaks(s: secret) i32;")) {
fail("private-closure", "private compiler fact bytes are wrong");
};
let dav: []str = [testenv.driver("wwdump"), "-a", "cs.wwi"];
if (!runok(td, "private-reparse", dav)) {
fail("private-closure", "self-contained export does not re-parse");
};
testenv.writefile(strings.concat(td, "/consumer.ww"), strings.concat(
"package consumer;\nimport leaktest;\n",
"fn forbidden(s: leaktest.secret) void = {};\n"));
let ccav: []str = [testenv.driver("w6c"), "-c", "--import",
"leaktest", "cs.wwi", "-o", "cs.s", "consumer.ww"];
let wcav: []str = [testenv.driver("w6c_ww"), "-c", "--import",
"leaktest", "ww.wwi", "-o", "ww.s", "consumer.ww"];
let cco: testenv.commandout;
let wco: testenv.commandout;
testenv.runcommand(td, td, "private-cs", ccav, lifetime(), &cco);
testenv.runcommand(td, td, "private-ws", wcav, lifetime(), &wco);
if (cco.termination != exec.termination.EXIT || cco.code == 0
|| wco.termination != exec.termination.EXIT || wco.code == 0
|| !testenv.same(cco.stderr, wco.stderr)
|| !testenv.has(cco.stderr,
"package 'leaktest' has no exported declaration 'secret'")) {
fail("private-closure", "private nominal became source-visible");
};
testenv.clean(td);
};