test: port 696/697/699 resolver carriers to corpus fixtures

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.
This commit is contained in:
2026-08-08 14:28:50 +09:00
parent 08cae16a0a
commit f45360bbec
26 changed files with 131 additions and 710 deletions

View File

@@ -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,
};

View File

@@ -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,
};

View File

@@ -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.
};

View File

@@ -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;
};

View File

@@ -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;
};

View File

@@ -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;
};

View File

@@ -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;
};

View File

@@ -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;
};

View File

@@ -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;
};

View File

@@ -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;
};

View File

@@ -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;
};

View File

@@ -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);
};

View File

@@ -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");
};

View File

@@ -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;
};

View File

@@ -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,
};

View File

@@ -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;
};

View File

@@ -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;
};

View File

@@ -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;
};

View File

@@ -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;
};

View File

@@ -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;
};

View File

@@ -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,
};

View File

@@ -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,
};