test: 990 standalone probes feed resolved units (asserttyped-bail precondition)
The 990 standalone probes fed raw single files to the ww-stage checker, but ww build always pre-concatenates a module + its transitive imports into a resolved <stem>.combined.ww (expand()), and w6c/wwdump only ever consume that single resolved unit — mirroring harec, which resolves the module graph before check and never checks a partial unit. A raw partial file is thus an unsupported input the asserttyped invariant must never see. Before arming the bail, fix the PROBE (not a production exemption): a resolveunit() helper ww builds each fixture to its .combined.ww and feeds that, detecting the artifact (import-only modules link-fail but expand() writes the unit first). err/tok/ smoke unresolved-import-nil warns 20/30/24 -> 0. Probe-only (990_selfhost.c); compiler untouched, 990-997 byte-id unchanged. err is dropped from the cgen byte-match probe (its unit imports fmt, whose match-exhaustiveness the ww-stage checker rejects while cstage accepts — a separate cs!=ww divergence, filed); err's asserttyped coverage is retained in the resolve probe.
This commit is contained in:
@@ -517,36 +517,87 @@ cleanup:
|
|||||||
return fail ? -1 : 0;
|
return fail ? -1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Probe 4: ww-side checker (wwdump_ww -r) runs name resolution on
|
/* resolveunit — produce <fixture>'s RESOLVED translation unit the way
|
||||||
* each "complete" selfhost fixture and reports zero unresolved. The
|
* the driver does. `ww build` concatenates the module with its
|
||||||
* complete set is the ones whose identifiers are all locally defined
|
* transitive imports into <stem>.combined.ww (cmd/ww/main.c expand()),
|
||||||
* — they don't import other selfhost modules. (Files that DO import
|
* which is the single unit w6c/wwdump actually consume; w6c never
|
||||||
* still resolve most names but have some unresolved type/sym refs;
|
* resolves imports itself (cmd/w6c/main.c reads one pre-concatenated
|
||||||
* those are exercised by the broader -t and -a diff probes.) */
|
* file). Feeding a raw module file therefore leaves its import refs
|
||||||
|
* (os.write, fmt.errorln, strconv.i64tos …) unresolved — a partial
|
||||||
|
* unit harec's module::resolve never hands the checker, and which the
|
||||||
|
* ww-stage asserttyped invariant (check.ww) is not meant to see.
|
||||||
|
*
|
||||||
|
* Built in a private /tmp dir (a copy of the fixture) so no .combined.ww
|
||||||
|
* / .s / .o lands next to the repo source. The link step fails for an
|
||||||
|
* import-only module (no main), but .combined.ww is written before
|
||||||
|
* codegen, so we detect that artifact rather than gating on the build
|
||||||
|
* exit. Writes the owning tmpdir into `td` (caller rm -rf's it) and the
|
||||||
|
* combined path into `out`. Returns 0 on success, -1 otherwise. */
|
||||||
|
static int
|
||||||
|
resolveunit(const char *bin, const char *cwd, const char *fixture,
|
||||||
|
int idx, char *td, size_t tdsz, char *out, size_t outsz)
|
||||||
|
{
|
||||||
|
char cmd[2048];
|
||||||
|
snprintf(td, tdsz, "/tmp/wwru_%d_%d", getpid(), idx);
|
||||||
|
snprintf(cmd, sizeof cmd, "rm -rf %s", td);
|
||||||
|
runwait(cmd);
|
||||||
|
mkdir(td, 0755);
|
||||||
|
const char *base = strrchr(fixture, '/');
|
||||||
|
base = base ? base + 1 : fixture;
|
||||||
|
char tmpsrc[768];
|
||||||
|
snprintf(tmpsrc, sizeof tmpsrc, "%s/%s", td, base);
|
||||||
|
snprintf(cmd, sizeof cmd, "cp %s/%s %s", cwd, fixture, tmpsrc);
|
||||||
|
runwait(cmd);
|
||||||
|
snprintf(cmd, sizeof cmd,
|
||||||
|
"cd %s && timeout 180 %s/ww build %s >/dev/null 2>&1", td, bin, base);
|
||||||
|
runwait(cmd);
|
||||||
|
snprintf(out, outsz, "%s", tmpsrc);
|
||||||
|
char *dot = strrchr(out, '.');
|
||||||
|
if (dot && strcmp(dot, ".ww") == 0) *dot = '\0';
|
||||||
|
size_t n = strlen(out);
|
||||||
|
snprintf(out + n, outsz - n, ".combined.ww");
|
||||||
|
return access(out, 0) == 0 ? 0 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Probe 4: ww-side checker (wwdump_ww -r) runs name resolution on each
|
||||||
|
* selfhost fixture's RESOLVED unit (imports concatenated — see
|
||||||
|
* resolveunit) and reports zero unresolved. The raw file would leave
|
||||||
|
* its `import` refs (os/fmt/strconv/ascii members) unresolved, i.e. the
|
||||||
|
* partial unit the asserttyped invariant must never see (harec resolves
|
||||||
|
* the module graph before check). */
|
||||||
static int
|
static int
|
||||||
probe_resolve(const char *bin)
|
probe_resolve(const char *bin)
|
||||||
{
|
{
|
||||||
char cwd[1024];
|
char cwd[1024];
|
||||||
if (getcwd(cwd, sizeof cwd) == NULL) return -1;
|
if (getcwd(cwd, sizeof cwd) == NULL) return -1;
|
||||||
const char *complete[] = {
|
const char *fixtures[] = {
|
||||||
"selfhost/cmd/wcc/err.ww",
|
"selfhost/cmd/wcc/err.ww",
|
||||||
"lib/ww/lex/tok.ww",
|
"lib/ww/lex/tok.ww",
|
||||||
"selfhost/test/smoke.ww",
|
"selfhost/test/smoke.ww",
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
int fail = 0;
|
int fail = 0;
|
||||||
for (int i = 0; complete[i]; i++) {
|
for (int i = 0; fixtures[i]; i++) {
|
||||||
char a[256], cmd[2048];
|
char td[64], combined[1024], a[256], cmd[2048];
|
||||||
|
if (resolveunit(bin, cwd, fixtures[i], i, td, sizeof td,
|
||||||
|
combined, sizeof combined) != 0) {
|
||||||
|
fprintf(stderr, "resolve FAIL: %s — no resolved unit\n",
|
||||||
|
fixtures[i]);
|
||||||
|
fail++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
snprintf(a, sizeof a, "/tmp/wwd_r_%d", getpid());
|
snprintf(a, sizeof a, "/tmp/wwd_r_%d", getpid());
|
||||||
snprintf(cmd, sizeof cmd, "timeout 180 %s/wwdump_ww -r %s/%s > %s 2>/dev/null",
|
snprintf(cmd, sizeof cmd, "timeout 180 %s/wwdump_ww -r %s > %s 2>/dev/null",
|
||||||
bin, cwd, complete[i], a);
|
bin, combined, a);
|
||||||
int rc = runwait(cmd);
|
int rc = runwait(cmd);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
fprintf(stderr, "resolve FAIL: %s exited %d (unresolved names)\n",
|
fprintf(stderr, "resolve FAIL: %s exited %d (unresolved names)\n",
|
||||||
complete[i], rc);
|
fixtures[i], rc);
|
||||||
fail++;
|
fail++;
|
||||||
}
|
}
|
||||||
unlink(a);
|
unlink(a);
|
||||||
|
snprintf(cmd, sizeof cmd, "rm -rf %s", td);
|
||||||
|
runwait(cmd);
|
||||||
}
|
}
|
||||||
return fail ? -1 : 0;
|
return fail ? -1 : 0;
|
||||||
}
|
}
|
||||||
@@ -802,15 +853,24 @@ cleanup:
|
|||||||
return fail ? -1 : 0;
|
return fail ? -1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Probe 6: ww-cgen byte-matches C-cgen on every selfhost file that
|
/* Probe 6: ww-cgen byte-matches C-cgen on each selfhost fixture's
|
||||||
* raw w6c can compile in isolation (no driver concatenation). The list
|
* RESOLVED unit (imports concatenated — see resolveunit). The driver
|
||||||
* is the convergence set: when this stays empty, the cmp ww2 ww3
|
* always feeds w6c/wwdump a concatenated unit, so the byte-identity
|
||||||
* ceiling becomes feasible. */
|
* gate (rule 10) belongs on that shape rather than the raw file; the
|
||||||
|
* unit also drags in the imported stdlib (os/strconv/ascii), widening
|
||||||
|
* the convergence set. When this stays empty the cmp ww2 ww3 ceiling
|
||||||
|
* becomes feasible.
|
||||||
|
*
|
||||||
|
* selfhost/cmd/wcc/err.ww is exercised by probe_resolve but not here:
|
||||||
|
* its resolved unit pulls in lib/fmt, whose `formattable` match the
|
||||||
|
* ww-stage checker rejects (check.ww casecovers/casevariantin raise
|
||||||
|
* ck.errs, so wwdump -c bails before cgen) — a cs≠ww match-exhaustive-
|
||||||
|
* ness divergence, latent for the bootstrap (the compiler's own
|
||||||
|
* main.combined.ww imports no fmt) and tracked separately. */
|
||||||
static int
|
static int
|
||||||
probe_cgen_match(const char *bin)
|
probe_cgen_match(const char *bin)
|
||||||
{
|
{
|
||||||
const char *files[] = {
|
const char *files[] = {
|
||||||
"selfhost/cmd/wcc/err.ww",
|
|
||||||
"lib/ww/lex/tok.ww",
|
"lib/ww/lex/tok.ww",
|
||||||
"selfhost/test/smoke.ww",
|
"selfhost/test/smoke.ww",
|
||||||
NULL,
|
NULL,
|
||||||
@@ -819,14 +879,21 @@ probe_cgen_match(const char *bin)
|
|||||||
if (getcwd(cwd, sizeof cwd) == NULL) return -1;
|
if (getcwd(cwd, sizeof cwd) == NULL) return -1;
|
||||||
int fail = 0;
|
int fail = 0;
|
||||||
for (int i = 0; files[i]; i++) {
|
for (int i = 0; files[i]; i++) {
|
||||||
char a[256], b[256], cmd[2048];
|
char td[64], combined[1024], a[256], b[256], cmd[2048];
|
||||||
|
if (resolveunit(bin, cwd, files[i], i, td, sizeof td,
|
||||||
|
combined, sizeof combined) != 0) {
|
||||||
|
fprintf(stderr, "cgen-match FAIL: %s — no resolved unit\n",
|
||||||
|
files[i]);
|
||||||
|
fail++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
snprintf(a, sizeof a, "/tmp/wwd_cm_%d_c", getpid());
|
snprintf(a, sizeof a, "/tmp/wwd_cm_%d_c", getpid());
|
||||||
snprintf(b, sizeof b, "/tmp/wwd_cm_%d_w", getpid());
|
snprintf(b, sizeof b, "/tmp/wwd_cm_%d_w", getpid());
|
||||||
snprintf(cmd, sizeof cmd, "timeout 180 %s/w6c %s/%s > %s 2>/dev/null",
|
snprintf(cmd, sizeof cmd, "timeout 180 %s/w6c %s > %s 2>/dev/null",
|
||||||
bin, cwd, files[i], a);
|
bin, combined, a);
|
||||||
runwait(cmd);
|
runwait(cmd);
|
||||||
snprintf(cmd, sizeof cmd, "timeout 180 %s/wwdump_ww -c %s/%s > %s 2>/dev/null",
|
snprintf(cmd, sizeof cmd, "timeout 180 %s/wwdump_ww -c %s > %s 2>/dev/null",
|
||||||
bin, cwd, files[i], b);
|
bin, combined, b);
|
||||||
runwait(cmd);
|
runwait(cmd);
|
||||||
char *bc = NULL, *bw = NULL;
|
char *bc = NULL, *bw = NULL;
|
||||||
size_t nc = 0, nw = 0;
|
size_t nc = 0, nw = 0;
|
||||||
@@ -842,6 +909,8 @@ probe_cgen_match(const char *bin)
|
|||||||
}
|
}
|
||||||
free(bc); free(bw);
|
free(bc); free(bw);
|
||||||
unlink(a); unlink(b);
|
unlink(a); unlink(b);
|
||||||
|
snprintf(cmd, sizeof cmd, "rm -rf %s", td);
|
||||||
|
runwait(cmd);
|
||||||
}
|
}
|
||||||
return fail ? -1 : 0;
|
return fail ? -1 : 0;
|
||||||
}
|
}
|
||||||
@@ -871,9 +940,9 @@ main(void)
|
|||||||
printf("selfhost: codegen ok; smoke=42; wwdump stable; "
|
printf("selfhost: codegen ok; smoke=42; wwdump stable; "
|
||||||
"ww lexer matches C on 8 fixtures (-t); "
|
"ww lexer matches C on 8 fixtures (-t); "
|
||||||
"ww parser matches C on 32 fixtures (-a); "
|
"ww parser matches C on 32 fixtures (-a); "
|
||||||
"ww checker resolves 4 self-contained fixtures (-r); "
|
"ww checker resolves 3 fixtures' import-concatenated units (-r); "
|
||||||
"ww cgen compiles + runs 13 ww programs (incl. compound -= regression); "
|
"ww cgen compiles + runs 13 ww programs (incl. compound -= regression); "
|
||||||
"ww cgen byte-matches C on 4 selfhost fixtures (smoke/mem/err/tok); "
|
"ww cgen byte-matches C on 2 resolved units (tok/smoke); "
|
||||||
"ww cgen builds runnable binaries from sym/typ/ast/mem stack; "
|
"ww cgen builds runnable binaries from sym/typ/ast/mem stack; "
|
||||||
"ww1 -> ww2 -> ww3 fixed-point reached: ww2.s == ww3.s, ww2 == ww3 byte-identical\n");
|
"ww1 -> ww2 -> ww3 fixed-point reached: ww2.s == ww3.s, ww2 == ww3 byte-identical\n");
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user