A primary-package top-level decl whose leaf also names a bundled module (`type sym` vs `import sym`; the lib/test->fnmatch->ascii -T floor's `ascii` module vs a `@test fn ascii`) collided in the flat scope: #23's installtop dup-check false-fired "duplicate fn/type" where cstage coexists. cstage keys the module name out of the value namespace by PROMOTING the same-leaf SK_USE in place to the value kind with use_alias=1 (cmd/wcc/check.c:2831/2848/2871/2907/2928/2951), so one correctly-kinded sym serves bare refs (call/structlit/var) while `name.member` still resolves the module via the `kind==SK_USE || use_alias` N_DOT guards (check.c:87/1337). This REVERSES wwstage's documented two-sym coexistence design (lib/ww/sym.ww scopelookupuselocal): keeping the SK_USE as a separate coexisting sym ripples into every bare-reference resolver (~25 scopelookup sites), and a missed site is a byte-id-consistent-but-wrong cat-A risk the gate cannot prove away — the same failure mode retired with the name-keyed variant-match cluster. The promote model is correct by construction: one sym of the right kind, identical to cstage. sym gains a use_alias field; the three N_DOT/N_CALL module-qualified guards honor use_alias. cstage installs every SK_USE in a dedicated first pass, so its value-arm promote is order-INDEPENDENT; wwstage installs in source order, so BOTH directions of the collision are promoted to reach cstage's identical single-sym end state: - use-before-value (`import aa` then `fn aa`): installtop promotes the pre-installed SK_USE to the value kind (use_alias=1). - value-before-use (`fn aa` then `import aa`): installdecl's N_USE arm promotes the pre-installed value sym in place (set use_alias=1, no coexisting SK_USE), mirroring cstage's self-import N_USE arm (check.c:2823-2834 `if (prev) prev->use_alias = 1`). Both orders compile + are cs/ww byte-identical AND byte-identical to each other. Cannot split: promote without the guards leaves `name.member` red on the promoted sym; the guards without promote are inert (no use_alias is ever set) — no bisect-clean intermediate. (#30) Pins (910/997): modfn_coexist_ok (use-before-value) AND modfn_coexist_vbu_ok (value-before-use) both accept on cstage + are cs/ww byte-id + run to exit 6 (bare fn and qualified module both resolve); the dup_fn row still rejects both stages (regression). fnmatch byte-id holds. The order-dependence is exactly what regresses silently, so both orders are pinned.
445 lines
16 KiB
C
445 lines
16 KiB
C
/*
|
|
* 997_at_test_ww — the wwstage twin of 910_at_test, driving the `-T`
|
|
* @test mode through `w6c_ww` (the ww-built compiler) instead of `w6c`
|
|
* (the C bootstrap). Task #15.
|
|
*
|
|
* Probes:
|
|
* 1. RUN — `w6c_ww -T` the @test-only fixture (import-resolved by
|
|
* `ww_ww build` into a combined unit), assemble, link, run; the
|
|
* synthesized entry must exit 0.
|
|
* 2. BYTE-ID (rule 10) — `w6c -T` and `w6c_ww -T` must emit
|
|
* byte-identical asm for the same source. The synthesized entry
|
|
* rides cgfn at the gated choke point, so the @test set + the
|
|
* collection-order calls are identical by construction. This is
|
|
* the new entry-synth byte-id gate.
|
|
* 3. REJECT — `-T` of a user-main fixture exits nonzero.
|
|
* 4. GUARD — `-T` of a non-`fn() void` @test exits nonzero.
|
|
*/
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <sys/wait.h>
|
|
|
|
static int
|
|
runwait(const char *cmd)
|
|
{
|
|
int rc = system(cmd);
|
|
if (rc == -1) return -1;
|
|
if (WIFEXITED(rc)) return WEXITSTATUS(rc);
|
|
return 1;
|
|
}
|
|
|
|
static const char *
|
|
absbin(void)
|
|
{
|
|
const char *b = getenv("BIN");
|
|
if (!b) b = "out/bin";
|
|
if (b[0] == '/') return b;
|
|
static char buf[2048];
|
|
char cwd[1024];
|
|
if (getcwd(cwd, sizeof cwd) == NULL) return NULL;
|
|
snprintf(buf, sizeof buf, "%s/%s", cwd, b);
|
|
return buf;
|
|
}
|
|
|
|
static int
|
|
slurp(const char *path, char **outbuf, size_t *outlen)
|
|
{
|
|
FILE *f = fopen(path, "rb");
|
|
if (!f) return -1;
|
|
fseek(f, 0, SEEK_END);
|
|
long n = ftell(f);
|
|
fseek(f, 0, SEEK_SET);
|
|
if (n < 0) { fclose(f); return -1; }
|
|
char *b = malloc((size_t)n + 1);
|
|
if (!b) { fclose(f); return -1; }
|
|
if (fread(b, 1, (size_t)n, f) != (size_t)n) { free(b); fclose(f); return -1; }
|
|
b[n] = '\0';
|
|
fclose(f);
|
|
*outbuf = b;
|
|
*outlen = (size_t)n;
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
run_fixture(const char *bin)
|
|
{
|
|
int pid = getpid();
|
|
char src[256], comb[256], binout[256], asmf[256], obj[256], exe[256];
|
|
char rt[1024], cmd[4096];
|
|
snprintf(src, sizeof src, "/tmp/at997_%d.ww", pid);
|
|
snprintf(binout, sizeof binout, "/tmp/at997_%d", pid);
|
|
snprintf(comb, sizeof comb, "/tmp/at997_%d.combined.ww", pid);
|
|
snprintf(asmf, sizeof asmf, "/tmp/at997_%d.s", pid);
|
|
snprintf(obj, sizeof obj, "/tmp/at997_%d.o", pid);
|
|
snprintf(exe, sizeof exe, "/tmp/at997_%d.exe", pid);
|
|
snprintf(rt, sizeof rt, "%s/../lib/libwwrt.a", bin);
|
|
|
|
snprintf(cmd, sizeof cmd, "cp test/wcc/data/attest_pass.ww %s", src);
|
|
if (runwait(cmd) != 0) { fprintf(stderr, "997 FAIL: cp\n"); return 1; }
|
|
|
|
/* `ww_ww test -c -o <stem>` (compile-only) resolves imports AND auto-
|
|
* bundles lib/test (#17) into <stem>.combined.ww — the synth's run()
|
|
* callee must link below — WITHOUT running the harness. We gate on the
|
|
* combined ARTIFACT existing; `-o` keeps the binary off the CWD. */
|
|
snprintf(cmd, sizeof cmd, "%s/ww_ww test -c -o %s %s > /dev/null 2>&1",
|
|
bin, binout, src);
|
|
runwait(cmd);
|
|
if (access(comb, 0) != 0) {
|
|
fprintf(stderr, "997 FAIL: ww_ww build produced no %s\n", comb);
|
|
return 1;
|
|
}
|
|
|
|
snprintf(cmd, sizeof cmd, "%s/w6c_ww -T %s -o %s 2>/dev/null", bin, comb, asmf);
|
|
if (runwait(cmd) != 0) { fprintf(stderr, "997 FAIL: w6c_ww -T errored\n"); return 1; }
|
|
snprintf(cmd, sizeof cmd, "%s/w6a_ww -o %s %s 2>/dev/null", bin, obj, asmf);
|
|
if (runwait(cmd) != 0) { fprintf(stderr, "997 FAIL: w6a_ww\n"); return 1; }
|
|
snprintf(cmd, sizeof cmd, "%s/w6l_ww -o %s %s %s 2>/dev/null", bin, exe, obj, rt);
|
|
if (runwait(cmd) != 0) { fprintf(stderr, "997 FAIL: w6l_ww\n"); return 1; }
|
|
|
|
int rc = runwait(exe);
|
|
if (rc != 0) {
|
|
fprintf(stderr, "997 FAIL: synth entry exited %d (a @test failed)\n", rc);
|
|
return 1;
|
|
}
|
|
unlink(src); unlink(comb); unlink(asmf); unlink(obj); unlink(exe);
|
|
unlink(binout);
|
|
char tmp[300];
|
|
snprintf(tmp, sizeof tmp, "%s.s", binout); unlink(tmp);
|
|
snprintf(tmp, sizeof tmp, "%s.o", binout); unlink(tmp);
|
|
return 0;
|
|
}
|
|
|
|
/* byteid — `w6c -T` and `w6c_ww -T` on the same unit must agree. The #17
|
|
* synth's run() callee only resolves against the auto-bundled lib/test, so
|
|
* we byte-compare the lib/test-INCLUSIVE combined (raw -T of the fixture
|
|
* would loud-reject the undefined run); `ww test -c` writes that combined. */
|
|
static int
|
|
byteid(const char *bin)
|
|
{
|
|
int pid = getpid();
|
|
char stem[256], comb[256], cs[256], ws[256], cmd[4096];
|
|
snprintf(stem, sizeof stem, "/tmp/at997_bid_%d", pid);
|
|
snprintf(comb, sizeof comb, "%s.combined.ww", stem);
|
|
snprintf(cs, sizeof cs, "/tmp/at997_bid_c_%d.s", pid);
|
|
snprintf(ws, sizeof ws, "/tmp/at997_bid_w_%d.s", pid);
|
|
|
|
snprintf(cmd, sizeof cmd,
|
|
"%s/ww test -c -o %s test/wcc/data/attest_pass.ww > /dev/null 2>&1",
|
|
bin, stem);
|
|
runwait(cmd);
|
|
if (access(comb, 0) != 0) {
|
|
fprintf(stderr, "997 FAIL: ww test -c produced no %s\n", comb);
|
|
return 1;
|
|
}
|
|
snprintf(cmd, sizeof cmd, "%s/w6c -T %s -o %s 2>/dev/null", bin, comb, cs);
|
|
if (runwait(cmd) != 0) { fprintf(stderr, "997 FAIL: w6c -T (byteid)\n"); return 1; }
|
|
snprintf(cmd, sizeof cmd, "%s/w6c_ww -T %s -o %s 2>/dev/null", bin, comb, ws);
|
|
if (runwait(cmd) != 0) { fprintf(stderr, "997 FAIL: w6c_ww -T (byteid)\n"); return 1; }
|
|
|
|
char *bc = NULL, *bw = NULL;
|
|
size_t nc = 0, nw = 0;
|
|
int rc = 0;
|
|
if (slurp(cs, &bc, &nc) < 0 || slurp(ws, &bw, &nw) < 0) {
|
|
fprintf(stderr, "997 FAIL: slurp byteid asm\n");
|
|
rc = 1;
|
|
} else if (nc != nw || memcmp(bc, bw, nc) != 0) {
|
|
fprintf(stderr, "997 FAIL: -T asm differs (cs %zu, ww %zu)\n", nc, nw);
|
|
rc = 1;
|
|
}
|
|
free(bc); free(bw);
|
|
unlink(comb); unlink(cs); unlink(ws);
|
|
char tmp[300];
|
|
snprintf(tmp, sizeof tmp, "%s.s", stem); unlink(tmp);
|
|
snprintf(tmp, sizeof tmp, "%s.o", stem); unlink(tmp);
|
|
unlink(stem);
|
|
return rc;
|
|
}
|
|
|
|
static int
|
|
reject(const char *bin, const char *fixture, const char *what)
|
|
{
|
|
char cmd[4096];
|
|
snprintf(cmd, sizeof cmd, "%s/w6c_ww -T %s -o /dev/null 2>/dev/null", bin, fixture);
|
|
if (runwait(cmd) == 0) {
|
|
fprintf(stderr, "997 FAIL: w6c_ww -T accepted %s (expected reject)\n", what);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* Each row: a fixture `w6c_ww -T` must loud-reject, and why. */
|
|
static const struct {
|
|
const char *fixture;
|
|
const char *what;
|
|
} rejects[] = {
|
|
{ "test/wcc/data/attest_userman.ww", "user main" },
|
|
{ "test/wcc/data/attest_badsig.ww", "non-void @test" },
|
|
};
|
|
|
|
/* #6: TEXT-def present/absent rows for attest_nondrop.ww (mirror 910). */
|
|
static const struct {
|
|
const char *sym;
|
|
int testmode; /* 1 => -T, 0 => plain build */
|
|
int present;
|
|
const char *what;
|
|
} nondrop_rows[] = {
|
|
{ "data.nondrop_keep", 0, 1, "plain fn kept non-T" },
|
|
{ "data.nondrop_test_a", 0, 0, "head @test dropped non-T" },
|
|
{ "data.nondrop_test_b", 0, 0, "mid @test dropped non-T" },
|
|
{ "data.nondrop_test_c", 0, 0, "consecutive @test dropped non-T" },
|
|
{ "data.nondrop_keep", 1, 1, "plain fn kept under -T" },
|
|
{ "data.nondrop_test_a", 1, 1, "head @test kept under -T" },
|
|
{ "data.nondrop_test_b", 1, 1, "mid @test kept under -T" },
|
|
{ "data.nondrop_test_c", 1, 1, "consecutive @test kept under -T" },
|
|
};
|
|
|
|
/* nondrop — drive the #6 splice through w6c_ww (rows) AND assert the
|
|
* non-T asm is cs/ww byte-identical (rule 10: the drop must be symmetric,
|
|
* not just cstage-side — 997's byteid above only covered -T mode). */
|
|
static int
|
|
nondrop(const char *bin)
|
|
{
|
|
int pid = getpid();
|
|
char wp[256], wt[256], cp[256], stem[256], comb[300], cmd[4096];
|
|
snprintf(wp, sizeof wp, "/tmp/at997nd_wp_%d.s", pid);
|
|
snprintf(wt, sizeof wt, "/tmp/at997nd_wt_%d.s", pid);
|
|
snprintf(cp, sizeof cp, "/tmp/at997nd_cp_%d.s", pid);
|
|
snprintf(stem, sizeof stem, "/tmp/at997nd_c_%d", pid);
|
|
snprintf(comb, sizeof comb, "%s.combined.ww", stem);
|
|
|
|
snprintf(cmd, sizeof cmd,
|
|
"%s/w6c_ww test/wcc/data/attest_nondrop.ww -o %s 2>/dev/null", bin, wp);
|
|
if (runwait(cmd) != 0) {
|
|
fprintf(stderr, "997 FAIL: w6c_ww non-T nondrop compile\n");
|
|
return 1;
|
|
}
|
|
/* the -T compile synthesizes a main calling lib/test's run(), so it
|
|
* needs the lib/test-inclusive combined `ww test -c` writes. */
|
|
snprintf(cmd, sizeof cmd,
|
|
"%s/ww test -c -o %s test/wcc/data/attest_nondrop.ww > /dev/null 2>&1",
|
|
bin, stem);
|
|
runwait(cmd);
|
|
snprintf(cmd, sizeof cmd,
|
|
"%s/w6c_ww -T %s -o %s 2>/dev/null", bin, comb, wt);
|
|
if (runwait(cmd) != 0) {
|
|
fprintf(stderr, "997 FAIL: w6c_ww -T nondrop compile\n");
|
|
return 1;
|
|
}
|
|
snprintf(cmd, sizeof cmd,
|
|
"%s/w6c test/wcc/data/attest_nondrop.ww -o %s 2>/dev/null", bin, cp);
|
|
if (runwait(cmd) != 0) {
|
|
fprintf(stderr, "997 FAIL: w6c non-T nondrop compile\n");
|
|
return 1;
|
|
}
|
|
|
|
int rc = 0;
|
|
for (size_t i = 0; i < sizeof nondrop_rows / sizeof nondrop_rows[0]; i++) {
|
|
const char *f = nondrop_rows[i].testmode ? wt : wp;
|
|
snprintf(cmd, sizeof cmd, "grep -q '^TEXT %s,' %s",
|
|
nondrop_rows[i].sym, f);
|
|
int found = runwait(cmd) == 0;
|
|
if (found != nondrop_rows[i].present) {
|
|
fprintf(stderr, "997 FAIL: w6c_ww — %s: %s %s (expected %s)\n",
|
|
nondrop_rows[i].what, nondrop_rows[i].sym,
|
|
found ? "present" : "absent",
|
|
nondrop_rows[i].present ? "present" : "absent");
|
|
rc = 1;
|
|
break;
|
|
}
|
|
}
|
|
if (rc == 0) {
|
|
char *bc = NULL, *bw = NULL;
|
|
size_t nc = 0, nw = 0;
|
|
if (slurp(cp, &bc, &nc) < 0 || slurp(wp, &bw, &nw) < 0) {
|
|
fprintf(stderr, "997 FAIL: slurp non-T nondrop asm\n");
|
|
rc = 1;
|
|
} else if (nc != nw || memcmp(bc, bw, nc) != 0) {
|
|
fprintf(stderr, "997 FAIL: non-T @test-drop asm differs "
|
|
"(cs %zu, ww %zu)\n", nc, nw);
|
|
rc = 1;
|
|
}
|
|
free(bc); free(bw);
|
|
}
|
|
unlink(wp); unlink(wt); unlink(cp); unlink(comb);
|
|
char tmp[300];
|
|
snprintf(tmp, sizeof tmp, "%s.s", stem); unlink(tmp);
|
|
snprintf(tmp, sizeof tmp, "%s.o", stem); unlink(tmp);
|
|
unlink(stem);
|
|
return rc;
|
|
}
|
|
|
|
/* reject_plain — `w6c_ww <fixture>` (NON-T) must exit nonzero. Pins (as
|
|
* 910 does for cstage) that wwstage type-checks a @test body before the
|
|
* #6 splice drops it: an undefined symbol is caught loud even though the
|
|
* fn never reaches codegen (checked at check.ww pass 2/3, dropped after). */
|
|
static int
|
|
reject_plain(const char *bin, const char *fixture, const char *what)
|
|
{
|
|
char cmd[4096];
|
|
snprintf(cmd, sizeof cmd, "%s/w6c_ww %s -o /dev/null 2>/dev/null",
|
|
bin, fixture);
|
|
if (runwait(cmd) == 0) {
|
|
fprintf(stderr, "997 FAIL: w6c_ww (non-T) accepted %s "
|
|
"(expected reject)\n", what);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* accept_byteid — a #23 legal-accept control: `<fixture>` must COMPILE on
|
|
* BOTH stages (no false dup reject) AND be cs/ww byte-identical (rule 10).
|
|
* Used for the cross-package same-leaf control (keying is (name, mod), so
|
|
* distinct-package leaves coexist) and the builtin-redecl carve-out (the
|
|
* one structural point where wwstage seeds builtins and cstage does not —
|
|
* byte-id proves the drop-the-redecl mirror is exact). */
|
|
static int
|
|
accept_byteid(const char *bin, const char *fixture, const char *what)
|
|
{
|
|
int pid = getpid();
|
|
char cs[256], ws[256], cmd[4096];
|
|
snprintf(cs, sizeof cs, "/tmp/at997ab_c_%d.s", pid);
|
|
snprintf(ws, sizeof ws, "/tmp/at997ab_w_%d.s", pid);
|
|
|
|
snprintf(cmd, sizeof cmd,
|
|
"%s/w6c %s -o %s 2>/dev/null", bin, fixture, cs);
|
|
if (runwait(cmd) != 0) {
|
|
fprintf(stderr, "997 FAIL: w6c rejected %s\n", what);
|
|
return 1;
|
|
}
|
|
snprintf(cmd, sizeof cmd,
|
|
"%s/w6c_ww %s -o %s 2>/dev/null", bin, fixture, ws);
|
|
if (runwait(cmd) != 0) {
|
|
fprintf(stderr, "997 FAIL: w6c_ww rejected %s\n", what);
|
|
return 1;
|
|
}
|
|
char *bc = NULL, *bw = NULL;
|
|
size_t nc = 0, nw = 0;
|
|
int rc = 0;
|
|
if (slurp(cs, &bc, &nc) < 0 || slurp(ws, &bw, &nw) < 0) {
|
|
fprintf(stderr, "997 FAIL: slurp %s asm\n", what);
|
|
rc = 1;
|
|
} else if (nc != nw || memcmp(bc, bw, nc) != 0) {
|
|
fprintf(stderr, "997 FAIL: %s asm differs (cs %zu, ww %zu)\n",
|
|
what, nc, nw);
|
|
rc = 1;
|
|
}
|
|
free(bc); free(bw);
|
|
unlink(cs); unlink(ws);
|
|
return rc;
|
|
}
|
|
|
|
/* collide_run — a @test unit defining a user `fn run` collides with
|
|
* lib/test's bound runner once `ww test -c` bundles it; `w6c_ww -T` of the
|
|
* combined must loud-reject the duplicate (#23). Pre-fix wwstage built a
|
|
* binary that called the user run and silently skipped every @test. */
|
|
static int
|
|
collide_run(const char *bin)
|
|
{
|
|
int pid = getpid();
|
|
char stem[256], comb[300], cmd[4096];
|
|
snprintf(stem, sizeof stem, "/tmp/at997cr_%d", pid);
|
|
snprintf(comb, sizeof comb, "%s.combined.ww", stem);
|
|
snprintf(cmd, sizeof cmd,
|
|
"%s/ww test -c -o %s test/wcc/data/attest_userrun.ww > /dev/null 2>&1",
|
|
bin, stem);
|
|
runwait(cmd);
|
|
if (access(comb, 0) != 0) {
|
|
fprintf(stderr, "997 FAIL: ww build produced no %s\n", comb);
|
|
return 1;
|
|
}
|
|
snprintf(cmd, sizeof cmd, "%s/w6c_ww -T %s -o /dev/null 2>/dev/null",
|
|
bin, comb);
|
|
int rc = 0;
|
|
if (runwait(cmd) == 0) {
|
|
fprintf(stderr, "997 FAIL: w6c_ww -T accepted user `fn run` collision "
|
|
"(expected duplicate-fn reject)\n");
|
|
rc = 1;
|
|
}
|
|
unlink(comb);
|
|
char tmp[320];
|
|
snprintf(tmp, sizeof tmp, "%s.s", stem); unlink(tmp);
|
|
snprintf(tmp, sizeof tmp, "%s.o", stem); unlink(tmp);
|
|
unlink(stem);
|
|
return rc;
|
|
}
|
|
|
|
/* modfn_run — `ww_ww run <fixture>` and assert exit 6 (#30): the wwstage
|
|
* runtime twin of 910's modfn_run. The fixture's main returns `aa() +
|
|
* aa.helper()` = 1 + 5; the bare fn must resolve to 1 and the qualified
|
|
* module member to 5, so a mis-resolution that still compiled runs to a
|
|
* different code. Pins the resolved TARGETS on the wwstage driver. */
|
|
static int
|
|
modfn_run(const char *bin, const char *fixture, const char *what)
|
|
{
|
|
char cmd[4096];
|
|
snprintf(cmd, sizeof cmd, "%s/ww_ww run %s > /dev/null 2>&1", bin, fixture);
|
|
int rc = runwait(cmd);
|
|
if (rc != 6) {
|
|
fprintf(stderr, "997 FAIL: ww_ww run %s exited %d (expected 6 — bare "
|
|
"fn + qualified module resolution)\n", what, rc);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
main(void)
|
|
{
|
|
const char *bin = absbin();
|
|
if (!bin) { fprintf(stderr, "997 FAIL: getcwd\n"); return 1; }
|
|
|
|
if (run_fixture(bin) != 0) return 1;
|
|
if (byteid(bin) != 0) return 1;
|
|
for (size_t i = 0; i < sizeof rejects / sizeof rejects[0]; i++)
|
|
if (reject(bin, rejects[i].fixture, rejects[i].what) != 0)
|
|
return 1;
|
|
if (nondrop(bin) != 0) return 1;
|
|
if (reject_plain(bin, "test/wcc/data/attest_undefbody.ww",
|
|
"undefined symbol in @test body") != 0) return 1;
|
|
|
|
/* #23 — wwstage top-level duplicate-decl reject (one row per kind:
|
|
* all four route through installtop) + legal cross-package control
|
|
* (byte-id) + the builtin-redecl carve-out (byte-id) + the -T
|
|
* `fn run` collision parity row. */
|
|
if (reject_plain(bin, "test/wcc/data/dup_fn.ww",
|
|
"same-module duplicate fn") != 0) return 1;
|
|
if (reject_plain(bin, "test/wcc/data/dup_type.ww",
|
|
"same-module duplicate type") != 0) return 1;
|
|
if (reject_plain(bin, "test/wcc/data/dup_def.ww",
|
|
"same-module duplicate def") != 0) return 1;
|
|
if (reject_plain(bin, "test/wcc/data/dup_let.ww",
|
|
"same-module duplicate let") != 0) return 1;
|
|
if (accept_byteid(bin, "test/wcc/data/dup_xpkg_ok.ww",
|
|
"cross-package same-name") != 0) return 1;
|
|
if (accept_byteid(bin, "test/wcc/data/builtin_redecl_ok.ww",
|
|
"builtin nomem redecl (carve-out)") != 0) return 1;
|
|
/* #30 — a top-level fn whose leaf matches an imported module name
|
|
* coexists with the module bareword. wwstage now PROMOTES the same-leaf
|
|
* collision in place (use_alias=1), mirroring cstage exactly, so byte-id
|
|
* proves the resolved call targets match. Both decl orders are pinned:
|
|
* use-before-value promotes via installtop's value-arm, value-before-use
|
|
* via installdecl's N_USE arm — both reach the identical single-sym end
|
|
* state, so cstage and wwstage agree on every source order. The bare
|
|
* `aa()` and qualified `aa.helper()` both resolve, else the compile
|
|
* fails. */
|
|
if (accept_byteid(bin, "test/wcc/data/modfn_coexist_ok.ww",
|
|
"fn named like imported module (use-before-value)") != 0) return 1;
|
|
if (accept_byteid(bin, "test/wcc/data/modfn_coexist_vbu_ok.ww",
|
|
"fn named like imported module (value-before-use)") != 0) return 1;
|
|
/* runtime-resolve: both orders run to exit 6 on the wwstage driver,
|
|
* pinning that the promoted sym resolves bare fn=1 + module member=5. */
|
|
if (modfn_run(bin, "test/wcc/data/modfn_coexist_ok.ww",
|
|
"use-before-value") != 0) return 1;
|
|
if (modfn_run(bin, "test/wcc/data/modfn_coexist_vbu_ok.ww",
|
|
"value-before-use") != 0) return 1;
|
|
if (collide_run(bin) != 0) return 1;
|
|
|
|
printf("@test -T (ww_ww): run ok + cs/ww byte-id + rejects + "
|
|
"non-T @test drop cs/ww byte-id + checked-body (#6) + "
|
|
"dup fn/type/def/let reject + xpkg/builtin-redecl byte-id + "
|
|
"modfn coexist byte-id (#30) + fn-run collision (#23)\n");
|
|
return 0;
|
|
}
|