wwiroundtrip pins the @packed re-emit through a real -I tree on both
driver stages (importer-side layout exit 91), strengthened with the
`struct @packed {` needle in the retained sepwork pk2.wwi (a
single-file two-package form emits no .wwi, so the tree is
irreducible). identityreject pins the stage asymmetry as a DIVERGE
row: cstage rejects with "not assignable" (packed is type identity,
harec types.c:621), wwstage builds+runs through the documented
#224/#10 nominal-lossy leniency; a wwstage tighten fails the row and
demands graduation to a //ww:error fixture. The 15 layout/runtime
value rows are fixture-shaped and move to the declarative corpus per
the residual audit port split.
135 lines
4.8 KiB
Plaintext
135 lines
4.8 KiB
Plaintext
package packedwwi_test;
|
|
|
|
// `struct @packed` legs no fixture can host, ported from the retired
|
|
// native carrier test/wcc/671_struct_packed.c (#51). The 15
|
|
// layout/runtime value rows are fixture-shaped and move to the
|
|
// declarative corpus per the residual audit port split; harec
|
|
// references live in that carrier's header (type_store.c:206-213,
|
|
// :886, :193; types.c:517,621).
|
|
//
|
|
// wwiroundtrip: a library package exports ONLY the packed type; the
|
|
// importer computes size+offset ITSELF, so the value depends on the
|
|
// .wwi producer re-emitting `struct @packed {` and the importer
|
|
// re-parsing it (unparse re-emit per ref/hare/hare/unparse/
|
|
// type.ha:122-126). Both driver stages must build the -I tree and run
|
|
// exit 91 (9*10+1; a dropped @packed gives 168). Strengthened over
|
|
// the carrier: the re-emitted `struct @packed {` is also asserted in
|
|
// the retained sepwork pk2.wwi. A single-file two-package form
|
|
// produces NO .wwi (one __root unit), so the real -I tree is
|
|
// irreducible here.
|
|
//
|
|
// identityreject: assigning packed A to a structurally-identical
|
|
// unpacked B — packed is type identity (harec types.c:621). STAGE-
|
|
// ASYMMETRIC divergence pin: cstage must reject WITH "not assignable"
|
|
// while wwstage must build AND run exit 0 through its pre-existing
|
|
// broadly-lenient nominal-lossy struct assignability (#224/#10 — a
|
|
// documented deferred arc, NOT desired behavior and NOT a #51
|
|
// regression). A wwstage tighten fails the row and demands graduation
|
|
// to a //ww:error two-frag fixture.
|
|
|
|
import os;
|
|
import os.exec;
|
|
import strings;
|
|
import testenv;
|
|
import time;
|
|
|
|
fn fail(label: str, why: str) void = {
|
|
let m: str = strings.concat("packedwwi FAIL: ", label, " -- ", why,
|
|
"\n");
|
|
os.write(2, m.ptr, m.len: u64);
|
|
assert(false);
|
|
};
|
|
|
|
fn tmo() time.duration = {
|
|
return (240i64 * (time.second: i64)): time.duration;
|
|
};
|
|
|
|
fn rundir(dir: str, name: str, argv: []str, out: *testenv.commandout) i32 = {
|
|
testenv.runcommand(dir, dir, name, argv, tmo(), out);
|
|
if (out.termination != exec.termination.EXIT) { return -1; };
|
|
return out.code;
|
|
};
|
|
|
|
@test fn wwiroundtrip() void = {
|
|
let drvs: []str = ["ww", "ww_ww"];
|
|
let s: i32 = 0;
|
|
for (s < 2) {
|
|
let td: str = testenv.fresh();
|
|
assert(os.mkdir(strings.concat(td, "/lib"), 493) == 0);
|
|
assert(os.mkdir(strings.concat(td, "/lib/pk2"), 493) == 0);
|
|
assert(os.mkdir(strings.concat(td, "/app"), 493) == 0);
|
|
testenv.writefile(strings.concat(td, "/lib/pk2/pk2.ww"),
|
|
strings.concat(
|
|
"package pk2;\n",
|
|
"export type Ev = struct @packed { tag: u8, data: u64 };\n"));
|
|
testenv.writefile(strings.concat(td, "/app/main.ww"),
|
|
strings.concat(
|
|
"package main;\n",
|
|
"import pk2;\n",
|
|
"export fn main() i32 = {\n",
|
|
"\tlet e: pk2.Ev = pk2.Ev { tag = 1u8, data = 2u64 };\n",
|
|
"\treturn size(pk2.Ev): i32 * 10 + offset(e.data): i32;\n",
|
|
"};\n"));
|
|
let app: str = strings.concat(td, "/app");
|
|
let co: testenv.commandout;
|
|
let av: []str = [testenv.driver(drvs[s]), "build", "-I",
|
|
strings.concat(td, "/lib"), "-o", "m", "main.ww"];
|
|
if (rundir(app, strings.concat("build_", drvs[s]), av, &co)
|
|
!= 0) {
|
|
fail(drvs[s], "-I tree build failed");
|
|
};
|
|
let rav: []str = [strings.concat(app, "/m")];
|
|
if (rundir(app, strings.concat("run_", drvs[s]), rav, &co)
|
|
!= 91) {
|
|
fail(drvs[s], strings.concat("importer-side run-exit ",
|
|
"!= 91 (@packed dropped in the .wwi re-emit ",
|
|
"gives 168)"));
|
|
};
|
|
let wwi: str = testenv.readfile(
|
|
strings.concat(app, "/m.sepwork/pk2.wwi"));
|
|
if (!testenv.has(wwi, "struct @packed {")) {
|
|
fail(drvs[s],
|
|
"pk2.wwi lost the `struct @packed {` re-emit");
|
|
};
|
|
testenv.clean(td);
|
|
s += 1;
|
|
};
|
|
};
|
|
|
|
@test fn identityreject() void = {
|
|
let src: str = strings.concat(
|
|
"package main;\n",
|
|
"type A = struct @packed { x: u8, y: u64 };\n",
|
|
"type B = struct { x: u8, y: u64 };\n",
|
|
"export fn main() i32 = {\n",
|
|
"\tlet a: A = A { x = 1u8, y = 2u64 };\n",
|
|
"\tlet b: B = a;\n",
|
|
"\treturn 0;\n",
|
|
"};\n");
|
|
let td: str = testenv.fresh();
|
|
testenv.writefile(strings.concat(td, "/id.ww"), src);
|
|
let co: testenv.commandout;
|
|
let cav: []str = [testenv.driver("ww"), "build", "-o", "idc",
|
|
"id.ww"];
|
|
if (rundir(td, "build_cstage", cav, &co) == 0) {
|
|
fail("identity_reject",
|
|
"cstage accepted packed->unpacked assignment");
|
|
};
|
|
if (!testenv.has(co.stderr, "not assignable")) {
|
|
fail("identity_reject", strings.concat("cstage reject lost ",
|
|
"its `not assignable` diagnostic (crash is vacuous)"));
|
|
};
|
|
let wav: []str = [testenv.driver("ww_ww"), "build", "-o", "idw",
|
|
"id.ww"];
|
|
if (rundir(td, "build_wwstage", wav, &co) != 0) {
|
|
fail("identity_reject", strings.concat("wwstage rejected -- ",
|
|
"#224/#10 leniency closed; graduate this row to a ",
|
|
"//ww:error fixture"));
|
|
};
|
|
let rav: []str = [strings.concat(td, "/idw")];
|
|
if (rundir(td, "run_wwstage", rav, &co) != 0) {
|
|
fail("identity_reject", "wwstage run-exit != 0");
|
|
};
|
|
testenv.clean(td);
|
|
};
|