wcc,ww: prepend synth use test; user fn run coexists with runner (M4 E2, #80)

The -T harness synthesized `use test;` after name-binding, so the lib/test runner run keyed the bare scope and collided with a user-defined bare fn run — a spurious "duplicate fn run" reject (the E1 tolerance seam). Prepending the synth use before binding keys the runner as test.run in the test module namespace, distinct from the user bare run; the two coexist. Hare-faithful: the runner is its own test module (ref/hare/test/+test.ha:97). Inverts attest_userrun.ww from the #23-mandated reject to a coexist fixture; gate asserts exactly 1 TEXT run + 1 TEXT test.run on the -T asm (distinct symbols, not a dead-dup). Closes #80.
This commit is contained in:
2026-06-17 23:54:21 +09:00
parent 08cfb5b2dd
commit 939c984f51
8 changed files with 308 additions and 112 deletions

View File

@@ -53,13 +53,14 @@ import os;
// lib/test symbol isolation, every -T build flat-bundles this module into
// the SAME bare-leaf scope as the test's own modules, so an un-prefixed
// `puts`/`runone` collides with a same-named module-private fn (lib/dirs
// and lib/temp both ship a private `puts(off, s)`). `run` stays the bound
// runner name (the synth's callee). A user `fn run` (or `const __wwtests`)
// in a @test unit collides with the synth: cstage — the shipping `ww test`
// path — rejects it loudly ("duplicate fn run" / type mismatch, rc!=0).
// wwstage TOLERATES the duplicate (#23, pre-existing rule-10 gap: cstage
// rejects a duplicate fn, wwstage does not), so the collision is loud on
// the reference stage but silent on wwstage until #23 lands.
// and lib/temp both ship a private `puts(off, s)`). `run` is the bound
// runner name (the synth's callee), reached module-qualified as `test.run`:
// the -T synth prepends `use test;` before name-binding (#80), so this
// runner keys into the `test` module namespace — a symbol distinct from any
// bare user `fn run` in the @test unit. The two COEXIST: `run` and
// `test.run` are separate symbols (ref/hare/test/+test.ha:97 — the runner
// is its own `test` module), so a user `fn run` is no longer a duplicate and
// both stages accept it under @test/-T.
export fn run(tests: [](str, *fn() void)) i32 = {
let av: []str = os.args();
let nfail: i32 = 0;