From f45360bbeca68a32cf4f4540e0d4cb980a4b7276 Mon Sep 17 00:00:00 2001 From: Hojun-Cho Date: Sat, 8 Aug 2026 14:28:50 +0900 Subject: [PATCH] test: port 696/697/699 resolver carriers to corpus fixtures MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 696_modtype_leaf_collision.c -> r696_modtype_leaf_pos (run-exit 26), r696_modtype_leaf_neg (staged error; w6c 'no field', w6c_ww asserttyped: dot — the old no-wwstage-checkfile comment is stale) 697_samemod_prefer.c -> r697_samemod_prefer (compile) 699_use_promote_alias.c -> r699_usepromote_{type,fn,def,var} (run-exit 42 each) Single-file multi-package form folds the modcollision/samemodprefer/ usepromote data trees into the fixtures; the trees retire with their carriers. The dir-tree .wwi transport of colliding type decls is owned by test/byteid/wwi_test.ww. Coverage upgrades: 697 and the 699 rows gain the wwstage leg the carriers gated or skipped, and all positive rows enter the blanket test-data-byteid net. --- internal/wwfixture/types.ww | 12 +- test/wcc/696_modtype_leaf_collision.c | 178 -------------------- test/wcc/697_samemod_prefer.c | 119 ------------- test/wcc/699_use_promote_alias.c | 152 ----------------- test/wcc/data/modcollision/mod1/mod1.ww | 10 -- test/wcc/data/modcollision/mod2/mod2.ww | 14 -- test/wcc/data/modcollision/neg.ww | 21 --- test/wcc/data/modcollision/pos.ww | 20 --- test/wcc/data/r696_modtype_leaf_neg/case.ww | 19 +++ test/wcc/data/r696_modtype_leaf_pos/case.ww | 24 +++ test/wcc/data/r697_samemod_prefer/case.ww | 22 +++ test/wcc/data/r699_usepromote_def/case.ww | 14 ++ test/wcc/data/r699_usepromote_fn/case.ww | 16 ++ test/wcc/data/r699_usepromote_type/case.ww | 16 ++ test/wcc/data/r699_usepromote_var/case.ww | 14 ++ test/wcc/data/samemodprefer/mod1/mod1.ww | 20 --- test/wcc/data/samemodprefer/mod2/mod2.ww | 20 --- test/wcc/data/samemodprefer/pos.ww | 22 --- test/wcc/data/usepromote/defmod/defmod.ww | 15 -- test/wcc/data/usepromote/fnmod/fnmod.ww | 19 --- test/wcc/data/usepromote/pos_def.ww | 14 -- test/wcc/data/usepromote/pos_fn.ww | 17 -- test/wcc/data/usepromote/pos_type.ww | 16 -- test/wcc/data/usepromote/pos_var.ww | 14 -- test/wcc/data/usepromote/typmod/typmod.ww | 19 --- test/wcc/data/usepromote/varmod/varmod.ww | 14 -- 26 files changed, 131 insertions(+), 710 deletions(-) delete mode 100644 test/wcc/696_modtype_leaf_collision.c delete mode 100644 test/wcc/697_samemod_prefer.c delete mode 100644 test/wcc/699_use_promote_alias.c delete mode 100644 test/wcc/data/modcollision/mod1/mod1.ww delete mode 100644 test/wcc/data/modcollision/mod2/mod2.ww delete mode 100644 test/wcc/data/modcollision/neg.ww delete mode 100644 test/wcc/data/modcollision/pos.ww create mode 100644 test/wcc/data/r696_modtype_leaf_neg/case.ww create mode 100644 test/wcc/data/r696_modtype_leaf_pos/case.ww create mode 100644 test/wcc/data/r697_samemod_prefer/case.ww create mode 100644 test/wcc/data/r699_usepromote_def/case.ww create mode 100644 test/wcc/data/r699_usepromote_fn/case.ww create mode 100644 test/wcc/data/r699_usepromote_type/case.ww create mode 100644 test/wcc/data/r699_usepromote_var/case.ww delete mode 100644 test/wcc/data/samemodprefer/mod1/mod1.ww delete mode 100644 test/wcc/data/samemodprefer/mod2/mod2.ww delete mode 100644 test/wcc/data/samemodprefer/pos.ww delete mode 100644 test/wcc/data/usepromote/defmod/defmod.ww delete mode 100644 test/wcc/data/usepromote/fnmod/fnmod.ww delete mode 100644 test/wcc/data/usepromote/pos_def.ww delete mode 100644 test/wcc/data/usepromote/pos_fn.ww delete mode 100644 test/wcc/data/usepromote/pos_type.ww delete mode 100644 test/wcc/data/usepromote/pos_var.ww delete mode 100644 test/wcc/data/usepromote/typmod/typmod.ww delete mode 100644 test/wcc/data/usepromote/varmod/varmod.ww diff --git a/internal/wwfixture/types.ww b/internal/wwfixture/types.ww index adc26ec8..431872f4 100644 --- a/internal/wwfixture/types.ww +++ b/internal/wwfixture/types.ww @@ -1,13 +1,13 @@ package wwfixture; def protocolversion: i32 = 1; -def corpuscount: i32 = 1634; -def errorcount: i32 = 336; -def compilecount: i32 = 17; +def corpuscount: i32 = 1641; +def errorcount: i32 = 337; +def compilecount: i32 = 18; def runcount: i32 = 198; -def runexitcount: i32 = 1083; -def nativecount: i32 = 3268; -def corpushash: str = "cb7cf09decc2f64b40c1f06b836c5b2aec0a4f1b9b2a78665f228606a0245a1f"; +def runexitcount: i32 = 1088; +def nativecount: i32 = 3282; +def corpushash: str = "d518a094a11081af773549c53a6830c510685ef44548c8ea01400e0661c37e65"; type directive = enum i32 { ERROR = 0, diff --git a/test/wcc/696_modtype_leaf_collision.c b/test/wcc/696_modtype_leaf_collision.c deleted file mode 100644 index 21947601..00000000 --- a/test/wcc/696_modtype_leaf_collision.c +++ /dev/null @@ -1,178 +0,0 @@ -/* - * 696_modtype_leaf_collision — same-leaf-name cross-module type - * disambiguation. Two modules each export `type stream` with - * intentionally distinct field sets; the consumer pins both via - * `mod1.stream` / `mod2.stream`. - * - * Pre-fix (before sym.mod tagging + scope_lookup_in_module): the - * second `type stream` registration in pass-1 failed with - * "duplicate type stream", or when both did survive they collapsed - * to whichever sym was first in the bucket chain. The negative case - * (`b: mod1.stream; return b.c;`) used to silently bind through the - * wrong type and the bogus field read would either crash at run - * time or return the wrong byte. Post-fix it must surface as a - * compile-time "no field 'c' in stream" error. - * - * Fixtures live in test/wcc/data/modcollision/. mod1/mod1.ww and - * mod2/mod2.ww are deliberately *new* source files so the test - * stays self-contained — independent of lib/bufio (now that - * `bufio.stream` and `io.stream` coexist on the post-#15 surface). - */ -#include -#include -#include -#include -#include -#include -#include - -static int -runwait(const char *cmd) -{ - int rc = system(cmd); - if (rc == -1) return -1; - if (WIFEXITED(rc)) return WEXITSTATUS(rc); - return -1; -} - -static int -run_pos(const char *driver, const char *fixdir, const char *tag) -{ - char td[1024], bin[1024], sepwork[1100]; - snprintf(td, sizeof td, "/tmp/modcol_pos_%d_%s", getpid(), tag); - if (mkdir(td, 0755) != 0) { - fprintf(stderr, "modtype_leaf[%s]: mkdir %s failed\n", tag, td); - return 1; - } - snprintf(bin, sizeof bin, "%s/pos", td); - snprintf(sepwork, sizeof sepwork, "%s/pos.sepwork", td); - - char cmd[2048]; - /* cd into the fixture dir so the driver's source-dir-first import - * search resolves `use mod1; use mod2;`; -o puts the binary and the - * caller-owned .sepwork under the directory acquired above. */ - snprintf(cmd, sizeof cmd, - "cd %s && %s build -o %s/pos pos.ww >/dev/null 2>&1", - fixdir, driver, td); - int fail = 0; - if (runwait(cmd) != 0) { - fprintf(stderr, "modtype_leaf[%s]: pos.ww build failed\n", tag); - fail = 1; - } else { - int got = runwait(bin); - /* 3 + 5 (mod1.stream) + 7 + 11 (mod2.stream) = 26. */ - if (got != 26) { - fprintf(stderr, - "modtype_leaf[%s]: pos.ww exit=%d want=26\n", tag, got); - fail = 1; - } - } - - snprintf(cmd, sizeof cmd, "rm -rf %s", sepwork); - if (runwait(cmd) != 0) { - fprintf(stderr, "modtype_leaf[%s]: cleanup %s failed\n", - tag, sepwork); - fail = 1; - } - if (unlink(bin) != 0 && errno != ENOENT) { - fprintf(stderr, "modtype_leaf[%s]: cleanup %s failed\n", tag, bin); - fail = 1; - } - if (rmdir(td) != 0) { - fprintf(stderr, "modtype_leaf[%s]: cleanup %s failed\n", tag, td); - fail = 1; - } - return fail; -} - -static int -run_neg(const char *driver, const char *fixdir, const char *tag) -{ - char td[1024], bin[1024], sepwork[1100]; - snprintf(td, sizeof td, "/tmp/modcol_neg_%d_%s", getpid(), tag); - if (mkdir(td, 0755) != 0) { - fprintf(stderr, "modtype_leaf[%s]: mkdir %s failed\n", tag, td); - return 1; - } - snprintf(bin, sizeof bin, "%s/neg", td); - snprintf(sepwork, sizeof sepwork, "%s/neg.sepwork", td); - - char cmd[2048]; - /* Build must fail with a field-resolution error: the `c` field - * lives on mod2.stream, not mod1.stream. If pre-fix sym-binding - * smashed mod1.stream's identity into mod2.stream's slot, this - * would silently succeed. -o puts the binary and its caller-owned - * .sepwork (created even on the expected build failure) under the - * directory acquired above. */ - snprintf(cmd, sizeof cmd, - "cd %s && %s build -o %s/neg neg.ww >/dev/null 2>&1", - fixdir, driver, td); - int rc = runwait(cmd); - int fail = 0; - if (rc == 0) { - fprintf(stderr, - "modtype_leaf[%s]: neg.ww built but should have errored\n", - tag); - fail = 1; - } - - snprintf(cmd, sizeof cmd, "rm -rf %s", sepwork); - if (runwait(cmd) != 0) { - fprintf(stderr, "modtype_leaf[%s]: cleanup %s failed\n", - tag, sepwork); - fail = 1; - } - if (unlink(bin) != 0 && errno != ENOENT) { - fprintf(stderr, "modtype_leaf[%s]: cleanup %s failed\n", tag, bin); - fail = 1; - } - if (rmdir(td) != 0) { - fprintf(stderr, "modtype_leaf[%s]: cleanup %s failed\n", tag, td); - fail = 1; - } - return fail; -} - -int -main(void) -{ - const char *bin = getenv("BIN"); - if (!bin) bin = "out/bin"; - char absbin[1024]; - if (bin[0] != '/') { - char cwd[1024]; - if (getcwd(cwd, sizeof cwd) == NULL) return 1; - snprintf(absbin, sizeof absbin, "%s/%s", cwd, bin); - bin = absbin; - } - - char cdrv[1024]; - snprintf(cdrv, sizeof cdrv, "%s/ww", bin); - char wdrv[1024]; - snprintf(wdrv, sizeof wdrv, "%s/ww_ww", bin); - - char fixdir[1024]; - if (getcwd(fixdir, sizeof fixdir) == NULL) return 1; - size_t cwd_n = strlen(fixdir); - const char *rel = "/test/wcc/data/modcollision"; - if (cwd_n + strlen(rel) + 1 >= sizeof fixdir) return 1; - memcpy(fixdir + cwd_n, rel, strlen(rel) + 1); - - int fail = 0; - fail += run_pos(cdrv, fixdir, "cstage"); - fail += run_neg(cdrv, fixdir, "cstage"); - fail += run_pos(wdrv, fixdir, "wwstage"); - /* No wwstage neg case: w6c_ww has no checkfile pass, so a - * missing-field reference doesn't surface as a build error. - * The positive case alone pins the structlookup mod-filter - * (without it, `mod2.stream` would either fail to resolve or - * silently bind to mod1.stream and miscompute the exit). */ - - if (fail) { - fprintf(stderr, - "modtype_leaf_collision: %d case(s) failed\n", fail); - return 1; - } - printf("modtype_leaf_collision: 3/3 ok\n"); - return 0; -} diff --git a/test/wcc/697_samemod_prefer.c b/test/wcc/697_samemod_prefer.c deleted file mode 100644 index ee8737e6..00000000 --- a/test/wcc/697_samemod_prefer.c +++ /dev/null @@ -1,119 +0,0 @@ -/* - * 697_samemod_prefer — same-module preference for bare-leaf lookup. - * - * Two modules each export `read` with intentionally distinct - * signatures (mod1: i32 → i32, mod2: str → i32). Each module's - * `caller()` invokes bare `read(...)` with its own arg type. The - * bare-leaf lookup must resolve to the SAME-MODULE `read`; otherwise - * the call is a check-time signature mismatch. - * - * Pre-fix (flat scope, first-wins by hash order): one of the bare - * lookups picked the wrong module's `read` and the build failed with - * "argument type not assignable". Post-fix (scope_lookup_prefer): each - * bare-leaf inside its own module binds to the same-module entry, both - * calls type-check, and the build succeeds. - * - * Runtime exit codes aren't asserted here because cgen still emits - * unmangled `TEXT read` labels for both modules and the linker - * collapses them. Mangling fn labels by module is a separate codegen - * sweep; this test pins the resolver fix alone. - * - * Fixtures live in test/wcc/data/samemodprefer/. Same shape as - * 696_modtype_leaf_collision.c. - */ -#include -#include -#include -#include -#include -#include -#include - -static int -runwait(const char *cmd) -{ - int rc = system(cmd); - if (rc == -1) return -1; - if (WIFEXITED(rc)) return WEXITSTATUS(rc); - return -1; -} - -static int -run_pos(const char *driver, const char *fixdir, const char *tag) -{ - /* -o puts the binary and caller-owned `.sepwork/` under the - * acquired directory; the cd keeps source-dir-first import search - * resolving `use mod1; use mod2;`. */ - char td[1024], outbin[1024], sepwork[1100]; - snprintf(td, sizeof td, "/tmp/smprefer_%d_%s", getpid(), tag); - if (mkdir(td, 0755) != 0) { - fprintf(stderr, "samemod_prefer[%s]: mkdir %s failed\n", tag, td); - return 1; - } - snprintf(outbin, sizeof outbin, "%s/pos", td); - snprintf(sepwork, sizeof sepwork, "%s/pos.sepwork", td); - - char cmd[2048]; - snprintf(cmd, sizeof cmd, - "cd %s && %s build -o %s/pos pos.ww >/dev/null 2>&1", - fixdir, driver, td); - int fail = 0; - if (runwait(cmd) != 0) { - fprintf(stderr, - "samemod_prefer[%s]: pos.ww build failed — bare-leaf " - "`read` lookup likely cross-bound\n", tag); - fail = 1; - } - - snprintf(cmd, sizeof cmd, "rm -rf %s", sepwork); - if (runwait(cmd) != 0) { - fprintf(stderr, "samemod_prefer[%s]: cleanup %s failed\n", - tag, sepwork); - fail = 1; - } - if (unlink(outbin) != 0 && errno != ENOENT) { - fprintf(stderr, "samemod_prefer[%s]: cleanup %s failed\n", - tag, outbin); - fail = 1; - } - if (rmdir(td) != 0) { - fprintf(stderr, "samemod_prefer[%s]: cleanup %s failed\n", tag, td); - fail = 1; - } - return fail; -} - -int -main(void) -{ - const char *bin = getenv("BIN"); - if (!bin) bin = "out/bin"; - char absbin[1024]; - if (bin[0] != '/') { - char cwd[1024]; - if (getcwd(cwd, sizeof cwd) == NULL) return 1; - snprintf(absbin, sizeof absbin, "%s/%s", cwd, bin); - bin = absbin; - } - - char cdrv[1024]; - snprintf(cdrv, sizeof cdrv, "%s/ww", bin); - - char fixdir[1024]; - if (getcwd(fixdir, sizeof fixdir) == NULL) return 1; - size_t cwd_n = strlen(fixdir); - const char *rel = "/test/wcc/data/samemodprefer"; - if (cwd_n + strlen(rel) + 1 >= sizeof fixdir) return 1; - memcpy(fixdir + cwd_n, rel, strlen(rel) + 1); - - int fail = 0; - fail += run_pos(cdrv, fixdir, "cstage"); - - if (fail) { - fprintf(stderr, - "samemod_prefer: %d case(s) failed\n", fail); - return 1; - } - printf("samemod_prefer: 1/1 ok\n"); - return 0; -} diff --git a/test/wcc/699_use_promote_alias.c b/test/wcc/699_use_promote_alias.c deleted file mode 100644 index 9e11a3ee..00000000 --- a/test/wcc/699_use_promote_alias.c +++ /dev/null @@ -1,152 +0,0 @@ -/* - * 699_use_promote_alias — SK_USE→SK_X promotion preserves use_alias. - * - * Sweep of every reachable promotion site in cmd/wcc/check.c where an - * SK_USE leaf gets in-place-promoted to a same-named decl. With driver - * concatenation, the imported module's top-level decls appear in - * file.list BEFORE the primary's `use foo;`, so pass-1 (N_USE + - * N_TYPEDECL only) installs an SK_USE("foo") that pass-1.5 later - * promotes when it walks the imported N_DEF / N_FNDECL / N_LET of the - * same name. Each promotion must set `prev->use_alias = 1` so the - * dot-prefixed lookups in resolve_typename (L77) and N_DOT (L709) - * continue to walk the leaf as a module head. - * - * The fnmatch.flag-style "unknown type" failure that surfaced this is - * the SK_FN row; the SK_TYPE row pins the random.random precedent - * against regression; SK_DEF / SK_VAR are the same structural shape - * with `def` / top-level `let` standing in for `fn`. - * - * row | imported decl shape | path | check.c line - * -----+-----------------------------+----------+------------- - * type | `type typmod = struct {...}`| L1660/77 | regression pin - * fn | `fn fnmod() i32 = ...` | L1722 | the bug - * def | `def defmod: i32 = 0` | L1709 | same shape - * var | `let varmod: i32 = 0` | L1736 | same shape - * - * Fixtures: test/wcc/data/usepromote/{type,fn,def,var}mod/.ww - * primary: test/wcc/data/usepromote/pos_{type,fn,def,var}.ww - * - * Each primary returns `flag.A` (= 42) so a successful build + run + - * exit=42 proves the lookup chain end-to-end. Cstage-only: wwstage - * uses a coexistence-not-promotion model in selfhost/cmd/wcc/check.ww - * (separate sym entries differentiated by `mod`, no use_alias flag at - * all), so the bug is structurally non-reachable on that side — see - * the architectural note at installdecl in check.ww. Task #11 will - * revisit when wwstage grows a real check pass on the cgen path. - */ -#include -#include -#include -#include -#include -#include -#include - -static int -runwait(const char *cmd) -{ - int rc = system(cmd); - if (rc == -1) return -1; - if (WIFEXITED(rc)) return WEXITSTATUS(rc); - return -1; -} - -static int -run_row(const char *driver, const char *fixdir, const char *tag) -{ - /* Keep the output and its caller-owned `.sepwork/` in one - * invocation-owned directory outside the repository. */ - char td[64]; - snprintf(td, sizeof td, "/tmp/usepr_%d_%s", getpid(), tag); - if (mkdir(td, 0755) != 0) { - fprintf(stderr, "use_promote_alias[%s]: mkdir %s: %s\n", - tag, td, strerror(errno)); - return 1; - } - - char src[64]; - snprintf(src, sizeof src, "pos_%s.ww", tag); - char bin[2048], sepdir[2048], rmcmd[2112]; - snprintf(bin, sizeof bin, "%s/out", td); - snprintf(sepdir, sizeof sepdir, "%s.sepwork", bin); - snprintf(rmcmd, sizeof rmcmd, "rm -rf %s", sepdir); - char cmd[2048]; - int failed = 0, got; - /* cd into the fixture dir so the driver's source-dir-first - * import search resolves `use mod;`; -o points OUT of the repo. */ - snprintf(cmd, sizeof cmd, - "cd %s && %s build -o %s %s >/dev/null 2>&1", fixdir, driver, bin, src); - if (runwait(cmd) != 0) { - fprintf(stderr, - "use_promote_alias[%s]: build failed — SK_USE→SK_X " - "promotion likely dropped use_alias\n", tag); - failed = 1; - goto cleanup; - } - got = runwait(bin); - if (got != 42) { - fprintf(stderr, - "use_promote_alias[%s]: exit=%d want=42\n", tag, got); - failed = 1; - } - -cleanup: - { - int cleanup_failed = 0; - if (runwait(rmcmd) != 0) { - fprintf(stderr, "use_promote_alias[%s]: remove %s failed\n", - tag, sepdir); - cleanup_failed = 1; - } - if (unlink(bin) != 0 && errno != ENOENT) { - fprintf(stderr, "use_promote_alias[%s]: unlink %s: %s\n", - tag, bin, strerror(errno)); - cleanup_failed = 1; - } - if (rmdir(td) != 0) { - fprintf(stderr, "use_promote_alias[%s]: rmdir %s: %s\n", - tag, td, strerror(errno)); - cleanup_failed = 1; - } - if (!failed && cleanup_failed) failed = 1; - } - return failed; -} - -int -main(void) -{ - const char *bin = getenv("BIN"); - if (!bin) bin = "out/bin"; - char absbin[1024]; - if (bin[0] != '/') { - char cwd[1024]; - if (getcwd(cwd, sizeof cwd) == NULL) return 1; - snprintf(absbin, sizeof absbin, "%s/%s", cwd, bin); - bin = absbin; - } - - char cdrv[1024]; - snprintf(cdrv, sizeof cdrv, "%s/ww", bin); - - char fixdir[1024]; - if (getcwd(fixdir, sizeof fixdir) == NULL) return 1; - size_t cwd_n = strlen(fixdir); - const char *rel = "/test/wcc/data/usepromote"; - if (cwd_n + strlen(rel) + 1 >= sizeof fixdir) return 1; - memcpy(fixdir + cwd_n, rel, strlen(rel) + 1); - - int fail = 0; - fail += run_row(cdrv, fixdir, "type"); - fail += run_row(cdrv, fixdir, "fn"); - fail += run_row(cdrv, fixdir, "def"); - fail += run_row(cdrv, fixdir, "var"); - - if (fail) { - fprintf(stderr, - "use_promote_alias: %d row(s) failed\n", fail); - return 1; - } - printf("use_promote_alias: 4/4 ok\n"); - return 0; -} diff --git a/test/wcc/data/modcollision/mod1/mod1.ww b/test/wcc/data/modcollision/mod1/mod1.ww deleted file mode 100644 index 9fa8f9ef..00000000 --- a/test/wcc/data/modcollision/mod1/mod1.ww +++ /dev/null @@ -1,10 +0,0 @@ -// modcollision/mod1 — exports `type stream` with mod1-shaped fields. -// Paired with mod2/mod2.ww to exercise same-leaf-name cross-module -// type disambiguation. Test driver: 696_modtype_leaf_collision.c. - -package mod1; - -export type stream = struct { - a: i32, - b: i32, -}; diff --git a/test/wcc/data/modcollision/mod2/mod2.ww b/test/wcc/data/modcollision/mod2/mod2.ww deleted file mode 100644 index 56fcc3a5..00000000 --- a/test/wcc/data/modcollision/mod2/mod2.ww +++ /dev/null @@ -1,14 +0,0 @@ -// modcollision/mod2 — exports `type stream` with mod2-shaped fields. -// Paired with mod1/mod1.ww to exercise same-leaf-name cross-module -// type disambiguation. Test driver: 696_modtype_leaf_collision.c. -// -// Fields are intentionally named distinctly from mod1's (c/d vs a/b) -// so the negative test (`b: mod1.stream` accessed via mod2-only field -// 'c') surfaces as a compile-time field-resolution error. - -package mod2; - -export type stream = struct { - c: i32, - d: i32, -}; diff --git a/test/wcc/data/modcollision/neg.ww b/test/wcc/data/modcollision/neg.ww deleted file mode 100644 index 21c65232..00000000 --- a/test/wcc/data/modcollision/neg.ww +++ /dev/null @@ -1,21 +0,0 @@ -// Negative case: declare `b: mod1.stream` then access a mod2-only -// field. With the mod-tagged scope lookup `b` resolves to mod1.stream -// (fields a, b), so the field access `b.c` must be a compile-time -// error rather than silently binding to mod2.stream and succeeding. -// -// No cross-module call is made: a missing mod1.make would itself -// trigger a link-time error that could mask the field-resolution -// error this test is actually pinning. `let b: mod1.stream;` is -// enough — we read b.c before initializing it, which is fine because -// the field-resolution error fires at check, long before any reach -// analysis or codegen runs. - -package modcollision; - -import mod1; -import mod2; - -fn main() i32 = { - let b: mod1.stream; - return b.c; // mod1.stream has no `c`; expect a compile error. -}; diff --git a/test/wcc/data/modcollision/pos.ww b/test/wcc/data/modcollision/pos.ww deleted file mode 100644 index 31699a6e..00000000 --- a/test/wcc/data/modcollision/pos.ww +++ /dev/null @@ -1,20 +0,0 @@ -// Positive case: two modules each export `type stream`. The consumer -// imports both and disambiguates via the module qualifier. mod1.stream -// has fields (a, b); mod2.stream has fields (c, d). The exit code -// encodes a sum of all four fields, so any cross-binding would either -// fail to compile or return the wrong value. - -package modcollision; - -import mod1; -import mod2; - -fn main() i32 = { - let s1: mod1.stream; - s1.a = 3: i32; - s1.b = 5: i32; - let s2: mod2.stream; - s2.c = 7: i32; - s2.d = 11: i32; - return s1.a + s1.b + s2.c + s2.d; -}; diff --git a/test/wcc/data/r696_modtype_leaf_neg/case.ww b/test/wcc/data/r696_modtype_leaf_neg/case.ww new file mode 100644 index 00000000..cbec94b4 --- /dev/null +++ b/test/wcc/data/r696_modtype_leaf_neg/case.ww @@ -0,0 +1,19 @@ +//ww:error c "no field 'c' in stream" ww "asserttyped: dot" +// migrated from test/wcc/696_modtype_leaf_collision.c: field `c` lives only on mod2.stream; pre-fix the read silently bound through the wrong type. +package mod1; +export type stream = struct { + a: i32, + b: i32, +}; +package mod2; +export type stream = struct { + c: i32, + d: i32, +}; +package main; +import mod1; +import mod2; +fn main() i32 = { + let b: mod1.stream; + return b.c; +}; diff --git a/test/wcc/data/r696_modtype_leaf_pos/case.ww b/test/wcc/data/r696_modtype_leaf_pos/case.ww new file mode 100644 index 00000000..a6c8a62a --- /dev/null +++ b/test/wcc/data/r696_modtype_leaf_pos/case.ww @@ -0,0 +1,24 @@ +//ww:run-exit 26 +// migrated from test/wcc/696_modtype_leaf_collision.c: same-leaf cross-module `type stream` must stay mod-tagged (pre-fix sym smash cross-bound the fields). +package mod1; +export type stream = struct { + a: i32, + b: i32, +}; +package mod2; +export type stream = struct { + c: i32, + d: i32, +}; +package main; +import mod1; +import mod2; +fn main() i32 = { + let s1: mod1.stream; + s1.a = 3: i32; + s1.b = 5: i32; + let s2: mod2.stream; + s2.c = 7: i32; + s2.d = 11: i32; + return s1.a + s1.b + s2.c + s2.d; +}; diff --git a/test/wcc/data/r697_samemod_prefer/case.ww b/test/wcc/data/r697_samemod_prefer/case.ww new file mode 100644 index 00000000..c38dda8d --- /dev/null +++ b/test/wcc/data/r697_samemod_prefer/case.ww @@ -0,0 +1,22 @@ +//ww:compile +// migrated from test/wcc/697_samemod_prefer.c: bare-leaf `read` binds same-module first; compile-only (unmangled TEXT read labels still collapse in the linker). +package mod1; +export fn read(x: i32) i32 = { + return x + 100i32; +}; +export fn caller() i32 = { + return read(1i32); +}; +package mod2; +export fn read(x: str) i32 = { + return x.len + 200i32; +}; +export fn caller() i32 = { + return read("ok"); +}; +package main; +import mod1; +import mod2; +fn main() i32 = { + return 0i32; +}; diff --git a/test/wcc/data/r699_usepromote_def/case.ww b/test/wcc/data/r699_usepromote_def/case.ww new file mode 100644 index 00000000..b0863169 --- /dev/null +++ b/test/wcc/data/r699_usepromote_def/case.ww @@ -0,0 +1,14 @@ +//ww:run-exit 42 +// migrated from test/wcc/699_use_promote_alias.c: SK_USE->SK_DEF promotion must keep use_alias so `defmod.flag` resolves. +package defmod; +export def defmod: i32 = 0i32; +export type flag = enum i32 { + NONE = 0, + A = 42, +}; +package main; +import defmod; +fn main() i32 = { + let m: defmod.flag = defmod.flag.A; + return m: i32; +}; diff --git a/test/wcc/data/r699_usepromote_fn/case.ww b/test/wcc/data/r699_usepromote_fn/case.ww new file mode 100644 index 00000000..9f38383f --- /dev/null +++ b/test/wcc/data/r699_usepromote_fn/case.ww @@ -0,0 +1,16 @@ +//ww:run-exit 42 +// migrated from test/wcc/699_use_promote_alias.c: SK_USE->SK_FN promotion (the original bug) must keep use_alias or `fnmod.flag` fails "unknown type". +package fnmod; +export type flag = enum i32 { + NONE = 0, + A = 42, +}; +export fn fnmod() i32 = { + return 0i32; +}; +package main; +import fnmod; +fn main() i32 = { + let m: fnmod.flag = fnmod.flag.A; + return m: i32; +}; diff --git a/test/wcc/data/r699_usepromote_type/case.ww b/test/wcc/data/r699_usepromote_type/case.ww new file mode 100644 index 00000000..5d9ed93a --- /dev/null +++ b/test/wcc/data/r699_usepromote_type/case.ww @@ -0,0 +1,16 @@ +//ww:run-exit 42 +// migrated from test/wcc/699_use_promote_alias.c: SK_USE->SK_TYPE in-place promotion keeps use_alias so `typmod.flag` resolves (check.c self-import branch). +package typmod; +export type typmod = struct { + x: i32, +}; +export type flag = enum i32 { + NONE = 0, + A = 42, +}; +package main; +import typmod; +fn main() i32 = { + let m: typmod.flag = typmod.flag.A; + return m: i32; +}; diff --git a/test/wcc/data/r699_usepromote_var/case.ww b/test/wcc/data/r699_usepromote_var/case.ww new file mode 100644 index 00000000..0d6b0c64 --- /dev/null +++ b/test/wcc/data/r699_usepromote_var/case.ww @@ -0,0 +1,14 @@ +//ww:run-exit 42 +// migrated from test/wcc/699_use_promote_alias.c: SK_USE->SK_VAR promotion must keep use_alias so `varmod.flag` resolves. +package varmod; +export let varmod: i32 = 0i32; +export type flag = enum i32 { + NONE = 0, + A = 42, +}; +package main; +import varmod; +fn main() i32 = { + let m: varmod.flag = varmod.flag.A; + return m: i32; +}; diff --git a/test/wcc/data/samemodprefer/mod1/mod1.ww b/test/wcc/data/samemodprefer/mod1/mod1.ww deleted file mode 100644 index 6e563efa..00000000 --- a/test/wcc/data/samemodprefer/mod1/mod1.ww +++ /dev/null @@ -1,20 +0,0 @@ -// samemodprefer/mod1 — exports a `read` that takes an i32 plus a -// `caller` that invokes bare `read(1i32)`. The bare-leaf lookup must -// resolve to mod1.read (i32 → i32) rather than mod2.read (str → i32), -// which coexists in the flat scope. Pre-fix the lookup picked -// whichever entry hashed earliest into the bucket; a wrong bind would -// surface as a check-time signature mismatch. Paired with mod2/mod2.ww -// and test/wcc/697_samemod_prefer.c. - -package mod1; - -export fn read(x: i32) i32 = { - return x + 100i32; -}; - -export fn caller() i32 = { - // Bare-leaf call inside mod1: must bind to mod1.read (i32 arg). - // If preference doesn't kick in this fails check: mod2.read - // expects a str, so `read(1i32)` would be a signature mismatch. - return read(1i32); -}; diff --git a/test/wcc/data/samemodprefer/mod2/mod2.ww b/test/wcc/data/samemodprefer/mod2/mod2.ww deleted file mode 100644 index 0b93d26a..00000000 --- a/test/wcc/data/samemodprefer/mod2/mod2.ww +++ /dev/null @@ -1,20 +0,0 @@ -// samemodprefer/mod2 — exports a `read` that takes a str plus a -// `caller` that invokes bare `read("ok")`. The bare-leaf lookup must -// resolve to mod2.read (str → i32) rather than mod1.read (i32 → i32), -// which coexists in the flat scope. Pre-fix the lookup picked -// whichever entry hashed earliest into the bucket; a wrong bind would -// surface as a check-time signature mismatch. Paired with mod1/mod1.ww -// and test/wcc/697_samemod_prefer.c. - -package mod2; - -export fn read(x: str) i32 = { - return x.len + 200i32; -}; - -export fn caller() i32 = { - // Bare-leaf call inside mod2: must bind to mod2.read (str arg). - // If preference doesn't kick in this fails check: mod1.read - // expects an i32, so `read("ok")` would be a signature mismatch. - return read("ok"); -}; diff --git a/test/wcc/data/samemodprefer/pos.ww b/test/wcc/data/samemodprefer/pos.ww deleted file mode 100644 index e70ba0de..00000000 --- a/test/wcc/data/samemodprefer/pos.ww +++ /dev/null @@ -1,22 +0,0 @@ -// Positive case: two modules each export `read` with DIFFERENT -// signatures (mod1: i32 → i32, mod2: str → i32). Each module also -// exports a `caller` that invokes bare `read(...)` with its own arg -// type. The bare-leaf inside mod1 must bind to mod1.read; inside mod2 -// to mod2.read. If preference doesn't kick in and the bare lookup -// picks the other module's `read`, the build fails with a signature -// mismatch at check-time. The driver test asserts that this fixture -// builds successfully. -// -// We don't assert runtime exit codes here because cgen still emits -// unmangled `TEXT read` labels for both modules and the linker -// collapses them — that's a separate codegen sweep, orthogonal to the -// resolver fix this test pins. - -package samemodprefer; - -import mod1; -import mod2; - -fn main() i32 = { - return 0i32; -}; diff --git a/test/wcc/data/usepromote/defmod/defmod.ww b/test/wcc/data/usepromote/defmod/defmod.ww deleted file mode 100644 index e59e596a..00000000 --- a/test/wcc/data/usepromote/defmod/defmod.ww +++ /dev/null @@ -1,15 +0,0 @@ -// usepromote/defmod — exports a `def defmod` with the same leaf as -// the module name. Paired with pos_def.ww to exercise the SK_USE→ -// SK_DEF promotion (cmd/wcc/check.c L1709). Mirrors the SK_FN bug -// shape: without `use_alias = 1`, the consumer's `defmod.flag` lookup -// fails because the promoted-in-place SK_DEF leaf no longer advertises -// itself as a module head. - -package defmod; - -export def defmod: i32 = 0i32; - -export type flag = enum i32 { - NONE = 0, - A = 42, -}; diff --git a/test/wcc/data/usepromote/fnmod/fnmod.ww b/test/wcc/data/usepromote/fnmod/fnmod.ww deleted file mode 100644 index cf5ecdeb..00000000 --- a/test/wcc/data/usepromote/fnmod/fnmod.ww +++ /dev/null @@ -1,19 +0,0 @@ -// usepromote/fnmod — exports a `fn fnmod()` with the same leaf as the -// module name. Paired with pos_fn.ww to exercise the bug fix at -// cmd/wcc/check.c L1722 (SK_USE→SK_FN promotion was missing the -// `use_alias = 1` line, so the consumer's `fnmod.flag` lookup walked -// resolve_typename's dot branch, found head `fnmod` as SK_FN, and -// skipped the module-filtered leaf path → "unknown type fnmod.flag". -// -// lib/fnmatch is the real-world instance that surfaced this. - -package fnmod; - -export type flag = enum i32 { - NONE = 0, - A = 42, -}; - -export fn fnmod() i32 = { - return 0i32; -}; diff --git a/test/wcc/data/usepromote/pos_def.ww b/test/wcc/data/usepromote/pos_def.ww deleted file mode 100644 index b3ecae41..00000000 --- a/test/wcc/data/usepromote/pos_def.ww +++ /dev/null @@ -1,14 +0,0 @@ -// SK_USE→SK_DEF promotion. Same shape as pos_fn.ww but the imported -// module exports `def defmod: i32 = 0` instead of `fn defmod()`. -// Pass-1.5 N_DEF case (check.c L1709) promotes the SK_USE leaf to -// SK_DEF. Pre-fix it forgot use_alias=1, so `defmod.flag` resolution -// failed. Post-fix the build succeeds and exit code = flag.A = 42. - -package usepromote; - -import defmod; - -fn main() i32 = { - let m: defmod.flag = defmod.flag.A; - return m: i32; -}; diff --git a/test/wcc/data/usepromote/pos_fn.ww b/test/wcc/data/usepromote/pos_fn.ww deleted file mode 100644 index 2428a181..00000000 --- a/test/wcc/data/usepromote/pos_fn.ww +++ /dev/null @@ -1,17 +0,0 @@ -// SK_USE→SK_FN promotion (the bug). fnmod exports `fn fnmod()` and -// `type flag = enum`. Pass-1 installs SK_TYPE("flag", mod="fnmod") and -// SK_USE("fnmod") (the `fn fnmod` isn't installed in pass-1; pass-1 -// only handles N_USE + N_TYPEDECL). Pass-1.5 then sees the N_FNDECL -// "fnmod", finds the SK_USE local, and promotes in place to SK_FN. -// Pre-fix that promotion forgot `use_alias = 1`, so `fnmod.flag` -// resolution failed with "unknown type fnmod.flag". Post-fix the -// build succeeds and exit code = flag.A = 42. - -package usepromote; - -import fnmod; - -fn main() i32 = { - let m: fnmod.flag = fnmod.flag.A; - return m: i32; -}; diff --git a/test/wcc/data/usepromote/pos_type.ww b/test/wcc/data/usepromote/pos_type.ww deleted file mode 100644 index 1d9f5bb1..00000000 --- a/test/wcc/data/usepromote/pos_type.ww +++ /dev/null @@ -1,16 +0,0 @@ -// SK_USE→SK_TYPE regression pin. typmod exports `type typmod = ...` -// AND `type flag = enum`. Driver concatenation puts imported decls -// first, so pass-1 installs SK_TYPE("typmod") first; the primary's -// `use typmod` then hits the self-import branch (check.c L1660) and -// sets use_alias=1 on the SK_TYPE entry. We rely on use_alias=1 here -// so the dot-prefixed `typmod.flag` lookup resolves to mod="typmod"'s -// flag entry. Exit code = flag.A = 42 verifies end-to-end. - -package usepromote; - -import typmod; - -fn main() i32 = { - let m: typmod.flag = typmod.flag.A; - return m: i32; -}; diff --git a/test/wcc/data/usepromote/pos_var.ww b/test/wcc/data/usepromote/pos_var.ww deleted file mode 100644 index 15258412..00000000 --- a/test/wcc/data/usepromote/pos_var.ww +++ /dev/null @@ -1,14 +0,0 @@ -// SK_USE→SK_VAR promotion. Imported module exports a top-level -// `let varmod: i32 = 0`. Pass-1.5 N_LET case (check.c L1736) promotes -// the SK_USE leaf to SK_VAR. Pre-fix it forgot use_alias=1, so -// `varmod.flag` resolution failed. Post-fix the build succeeds and -// exit code = flag.A = 42. - -package usepromote; - -import varmod; - -fn main() i32 = { - let m: varmod.flag = varmod.flag.A; - return m: i32; -}; diff --git a/test/wcc/data/usepromote/typmod/typmod.ww b/test/wcc/data/usepromote/typmod/typmod.ww deleted file mode 100644 index 3acad7f3..00000000 --- a/test/wcc/data/usepromote/typmod/typmod.ww +++ /dev/null @@ -1,19 +0,0 @@ -// usepromote/typmod — exports a `type typmod` with the same leaf as -// the module name. Paired with pos_type.ww to pin the SK_USE→SK_TYPE -// promotion's use_alias=1 behaviour (cmd/wcc/check.c L1660 / L1677): -// the consumer's `typmod.flag` lookup must walk through the alias -// even though the leaf sym is SK_TYPE, not SK_USE. -// -// random.random in lib/ is the canonical real-world instance of this -// shape; this fixture replays it as a regression pin. - -package typmod; - -export type typmod = struct { - x: i32, -}; - -export type flag = enum i32 { - NONE = 0, - A = 42, -}; diff --git a/test/wcc/data/usepromote/varmod/varmod.ww b/test/wcc/data/usepromote/varmod/varmod.ww deleted file mode 100644 index 96597854..00000000 --- a/test/wcc/data/usepromote/varmod/varmod.ww +++ /dev/null @@ -1,14 +0,0 @@ -// usepromote/varmod — exports a top-level `let varmod` with the same -// leaf as the module name. Paired with pos_var.ww to exercise the -// SK_USE→SK_VAR promotion at cmd/wcc/check.c L1736. Same shape as -// SK_DEF / SK_FN — without `use_alias = 1`, the consumer's -// `varmod.flag` lookup fails. - -package varmod; - -export let varmod: i32 = 0i32; - -export type flag = enum i32 { - NONE = 0, - A = 42, -};