Files
ww/test/misc/reject_test.ww
Hojun-Cho a82cfaa6ab test: port the cstage-only rejects to ww; retire 760_def_widen_const + 783_amp_fn_assign_run
Both carriers were already slim: the r76_def_widen_* byte-id legs are
owned by the test-data-byteid blanket, 783's positive byte rows by the
r78_amp_fn_assign_* fixtures plus that same blanket, and its symmetric
non-tagged rejects by the corpus //ww:error fixtures. The unowned
remainder is three cstage-only loud-rejects (the 760 narrowing def-ref
and 783's two tagged-slot rows); the wwstage over-accepts (no def-init
assignability check; #214 void-variant leniency) are documented at the
site per the residual audit, never asserted as desired — the rows
graduate to //ww:error fixtures when the wwstage side tightens.
Bundled: one file, one concern (cstage-reject pins awaiting wwstage
graduation).
2026-08-08 15:05:52 +09:00

108 lines
3.8 KiB
Plaintext

package reject_test;
// Cstage-only loud-reject pins, ported from the retired native
// carriers test/wcc/760_def_widen_const.c and
// test/wcc/783_amp_fn_assign_run.c. Each row asserts ONLY the cstage
// reject; the wwstage side over-accepts today and that over-accept is
// documented here (residual audit, test-infra-v2-residual-20260808),
// never asserted as desired — these rows graduate to //ww:error
// corpus fixtures the moment the wwstage checker gains the matching
// reject.
//
// 760 (#113 def_cast_fits): an out-of-range narrowing def-ref must
// fail the cstage build loud — the const-scoped widen must never
// become a silent truncation. wwstage has no def-init assignability
// check at all (pre-existing leanness) and accepts. The r76_def_widen_*
// byte-id legs the carrier also drove are owned by the
// test-data-byteid blanket over those fixtures.
//
// 783 (#206 gate, tagged rows): the two NEGATIVE tagged-slot rows are
// cstage-only pending #214 — wwstage's `(X | void)` tagged
// assignability leniently matches any *fn against the void variant
// (the accept-INVALID hole; its close is required before wwstage can
// be the authoritative checker). The positive byte-id rows are owned
// by the r78_amp_fn_assign_* fixtures plus the test-data-byteid
// blanket; the symmetric non-tagged rejects by the corpus
// r783_amp_fn_assign_neg_* //ww:error fixtures.
import os;
import os.exec;
import strings;
import testenv;
import time;
fn fail(label: str, why: str) void = {
let m: str = strings.concat("reject FAIL: ", label, " -- ", why,
"\n");
os.write(2, m.ptr, m.len: u64);
assert(false);
};
fn tmo() time.duration = {
return (180i64 * (time.second: i64)): time.duration;
};
@test fn defwidennarrow() void = {
let td: str = testenv.fresh();
testenv.writefile(strings.concat(td, "/nw.ww"), strings.concat(
"package main;\n",
"def BIG_I32: i32 = 70000;\n",
"def S_I16: i16 = BIG_I32;\n",
"export fn main() i32 = { let s: i16 = S_I16; ",
"return s: i32; };\n"));
let av: []str = [testenv.driver("w6c"), "-o",
strings.concat(td, "/nw.s"), strings.concat(td, "/nw.ww")];
let co: testenv.commandout;
testenv.runcommand(td, td, "narrow", av, tmo(), &co);
// A deadline kill is not a reject; only a loud EXIT failure is.
if (co.termination != exec.termination.EXIT) {
fail("narrow", "w6c did not terminate normally");
};
if (co.code == 0) {
fail("narrow", strings.concat("w6c exited 0 (expected loud ",
"failure, no silent truncation)"));
};
testenv.clean(td);
};
fn cstagerejectrow(label: str, src: str) void = {
let td: str = testenv.fresh();
testenv.writefile(strings.concat(td, "/main783.ww"), src);
let av: []str = [testenv.driver("ww"), "build", "-o", "main783",
"main783.ww"];
let co: testenv.commandout;
testenv.runcommand(td, td, label, av, tmo(), &co);
if (co.termination != exec.termination.EXIT) {
fail(label, "cstage build did not terminate normally");
};
if (co.code == 0) {
fail(label, "cstage built but expected reject");
};
testenv.clean(td);
};
@test fn ampfnassigntagged() void = {
// Two same-signature ptr-to-fn variants: a direct &fn is ambiguous
// and must never silently bind to one.
cstagerejectrow("neg_ambiguous_tagged", strings.concat(
"package main;\n",
"type reader = fn(x: i32) i32;\n",
"type writer = fn(x: i32) i32;\n",
"fn myfn(x: i32) i32 = { return x; };\n",
"fn main() i32 = {\n",
" let x: (*reader | *writer | void) = &myfn;\n",
" return 0;\n",
"};\n"));
// Laundering a materialized *fn into a (*reader|void) slot:
// cstage rejects nominally (harec types.c:1039-1066 mirror).
cstagerejectrow("neg_launder_tagged", strings.concat(
"package main;\n",
"type reader = fn(x: i32) i32;\n",
"fn rd(x: i32) i32 = { return x + 1; };\n",
"fn main() i32 = {\n",
" let p = &rd;\n",
" let s: (*reader | void) = p;\n",
" return 0;\n",
"};\n"));
};