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:
@@ -14232,14 +14232,15 @@ fn exprtype(c: *checker, e: *syntax.node, hint: *syntax.node) *syntax.node = {
|
||||
// Module-qualified callee whose leaf isn't scope-keyed
|
||||
// under its module: align to cstage, which stamps ty_err
|
||||
// here and lets cgen emit the call (cmd/wcc/check.c:1834-
|
||||
// 1843; rule-10). The -T synth's `test.run` hits this in
|
||||
// BOTH combined and sep (Q2-confirmed): lib/test's `run` is
|
||||
// scope-keyed under "" not "test" — the directive-for-cgen
|
||||
// vs declmod-for-scope keying split, the module-qualified
|
||||
// arm of #27. cgen still emits the correct CALL test.run
|
||||
// from run's `//ww:module test` directive. Load-bearing
|
||||
// until #80 module-keys run under sep so the synth call
|
||||
// type-resolves; NOT an M4-transient.
|
||||
// 1843; rule-10). This now tolerates only a genuinely-
|
||||
// extern leaf (raw w6c on a single module-qualified file
|
||||
// with no driver concat), the module-qualified arm of #27.
|
||||
// The -T synth's `test.run` NO LONGER lands here: #80
|
||||
// PREPENDS the synth `use test;` before Pass 1, so declmod
|
||||
// keys lib/test's `run` under "test" (not "") and the synth
|
||||
// `test.run` type-resolves — the E1 bridge is closed. cgen
|
||||
// keys the CALL off run's `//ww:module test` directive
|
||||
// either way, so the resolution change is asm-neutral.
|
||||
if (s == nil) {
|
||||
e.type_ = c.tc.tyerr: *void;
|
||||
callee.type_ = c.tc.tyerr: *void; // N_DOT node itself (asserttyped checks it)
|
||||
@@ -17108,6 +17109,24 @@ export fn checkfile(c: *checker, file: *syntax.node) void = {
|
||||
if (file.kind != syntax.nkind.N_FILE) { return; };
|
||||
c.file = file;
|
||||
|
||||
// #80: under -T, PREPEND the synth `use test;` BEFORE Pass 1 so declmod
|
||||
// (called per-decl during install) sees a matching `use test` when it
|
||||
// keys lib/test's `run` — keying it under mod="test", not "". This is a
|
||||
// pure ORDER fix: the synth N_USE was appended AFTER install (below),
|
||||
// too late for declmod, so `run` keyed under "" — leaving the synth
|
||||
// `test.run` ty_err (the E1 bridge) and colliding with a user root
|
||||
// `fn run` (also mod=""). Decoupled from cgen: the symbol mangle keys
|
||||
// off d.module (the //ww:module directive, cgen mod_collect), NOT this
|
||||
// scope keying — cgen already emits the correct CALL test.run. Twin of
|
||||
// cstage cmd/wcc/check.c.
|
||||
if (c.istest != 0) {
|
||||
let usenode: *syntax.node = syntax.newnode(syntax.nkind.N_USE, file.file, file.line, file.col);
|
||||
usenode.str = "test";
|
||||
usenode.usepath = "test";
|
||||
usenode.next = file.list;
|
||||
file.list = usenode;
|
||||
};
|
||||
|
||||
// Pass 1: install all top-level names.
|
||||
let d: *syntax.node = file.list;
|
||||
for (d != nil) {
|
||||
@@ -17308,17 +17327,11 @@ export fn checkfile(c: *checker, file: *syntax.node) void = {
|
||||
let ret: *syntax.node = syntax.newnode(syntax.nkind.N_RETURN, pf, pl, pc);
|
||||
ret.lhs = call;
|
||||
body.list = ret;
|
||||
// synth `use test;` so the N_DOT base binds as a module
|
||||
// qualifier (SK_USE) and usepathfor maps `test` to its path.
|
||||
// Mirror installdecl's N_USE SK_USE install. Appended to
|
||||
// file.list below; emits no asm.
|
||||
let usenode: *syntax.node = syntax.newnode(syntax.nkind.N_USE, pf, pl, pc);
|
||||
usenode.str = "test";
|
||||
usenode.usepath = "test";
|
||||
syntax.scopedefine(c.top, "test", syntax.skind.SK_USE, nil, usenode);
|
||||
let ul: *syntax.node = file.list;
|
||||
if (ul == nil) { file.list = usenode; }
|
||||
else { for (ul.next != nil) { ul = ul.next; }; ul.next = usenode; };
|
||||
// #80: the synth `use test;` (the N_DOT base qualifier + the
|
||||
// usepathfor source mapping `test`→its path) is now PREPENDED
|
||||
// before Pass 1 at the top of checkfile, so declmod keys
|
||||
// lib/test's `run` under "test" and the synth `test.run`
|
||||
// type-resolves. It is installed (SK_USE) by Pass 1's N_USE arm.
|
||||
};
|
||||
let m: *syntax.node = syntax.newnode(syntax.nkind.N_FNDECL, pf, pl, pc);
|
||||
m.str = "main";
|
||||
|
||||
@@ -3489,14 +3489,15 @@ fn exprtype(c: *checker, e: *syntax.node, hint: *syntax.node) *syntax.node = {
|
||||
// Module-qualified callee whose leaf isn't scope-keyed
|
||||
// under its module: align to cstage, which stamps ty_err
|
||||
// here and lets cgen emit the call (cmd/wcc/check.c:1834-
|
||||
// 1843; rule-10). The -T synth's `test.run` hits this in
|
||||
// BOTH combined and sep (Q2-confirmed): lib/test's `run` is
|
||||
// scope-keyed under "" not "test" — the directive-for-cgen
|
||||
// vs declmod-for-scope keying split, the module-qualified
|
||||
// arm of #27. cgen still emits the correct CALL test.run
|
||||
// from run's `//ww:module test` directive. Load-bearing
|
||||
// until #80 module-keys run under sep so the synth call
|
||||
// type-resolves; NOT an M4-transient.
|
||||
// 1843; rule-10). This now tolerates only a genuinely-
|
||||
// extern leaf (raw w6c on a single module-qualified file
|
||||
// with no driver concat), the module-qualified arm of #27.
|
||||
// The -T synth's `test.run` NO LONGER lands here: #80
|
||||
// PREPENDS the synth `use test;` before Pass 1, so declmod
|
||||
// keys lib/test's `run` under "test" (not "") and the synth
|
||||
// `test.run` type-resolves — the E1 bridge is closed. cgen
|
||||
// keys the CALL off run's `//ww:module test` directive
|
||||
// either way, so the resolution change is asm-neutral.
|
||||
if (s == nil) {
|
||||
e.type_ = c.tc.tyerr: *void;
|
||||
callee.type_ = c.tc.tyerr: *void; // N_DOT node itself (asserttyped checks it)
|
||||
@@ -6365,6 +6366,24 @@ export fn checkfile(c: *checker, file: *syntax.node) void = {
|
||||
if (file.kind != syntax.nkind.N_FILE) { return; };
|
||||
c.file = file;
|
||||
|
||||
// #80: under -T, PREPEND the synth `use test;` BEFORE Pass 1 so declmod
|
||||
// (called per-decl during install) sees a matching `use test` when it
|
||||
// keys lib/test's `run` — keying it under mod="test", not "". This is a
|
||||
// pure ORDER fix: the synth N_USE was appended AFTER install (below),
|
||||
// too late for declmod, so `run` keyed under "" — leaving the synth
|
||||
// `test.run` ty_err (the E1 bridge) and colliding with a user root
|
||||
// `fn run` (also mod=""). Decoupled from cgen: the symbol mangle keys
|
||||
// off d.module (the //ww:module directive, cgen mod_collect), NOT this
|
||||
// scope keying — cgen already emits the correct CALL test.run. Twin of
|
||||
// cstage cmd/wcc/check.c.
|
||||
if (c.istest != 0) {
|
||||
let usenode: *syntax.node = syntax.newnode(syntax.nkind.N_USE, file.file, file.line, file.col);
|
||||
usenode.str = "test";
|
||||
usenode.usepath = "test";
|
||||
usenode.next = file.list;
|
||||
file.list = usenode;
|
||||
};
|
||||
|
||||
// Pass 1: install all top-level names.
|
||||
let d: *syntax.node = file.list;
|
||||
for (d != nil) {
|
||||
@@ -6565,17 +6584,11 @@ export fn checkfile(c: *checker, file: *syntax.node) void = {
|
||||
let ret: *syntax.node = syntax.newnode(syntax.nkind.N_RETURN, pf, pl, pc);
|
||||
ret.lhs = call;
|
||||
body.list = ret;
|
||||
// synth `use test;` so the N_DOT base binds as a module
|
||||
// qualifier (SK_USE) and usepathfor maps `test` to its path.
|
||||
// Mirror installdecl's N_USE SK_USE install. Appended to
|
||||
// file.list below; emits no asm.
|
||||
let usenode: *syntax.node = syntax.newnode(syntax.nkind.N_USE, pf, pl, pc);
|
||||
usenode.str = "test";
|
||||
usenode.usepath = "test";
|
||||
syntax.scopedefine(c.top, "test", syntax.skind.SK_USE, nil, usenode);
|
||||
let ul: *syntax.node = file.list;
|
||||
if (ul == nil) { file.list = usenode; }
|
||||
else { for (ul.next != nil) { ul = ul.next; }; ul.next = usenode; };
|
||||
// #80: the synth `use test;` (the N_DOT base qualifier + the
|
||||
// usepathfor source mapping `test`→its path) is now PREPENDED
|
||||
// before Pass 1 at the top of checkfile, so declmod keys
|
||||
// lib/test's `run` under "test" and the synth `test.run`
|
||||
// type-resolves. It is installed (SK_USE) by Pass 1's N_USE arm.
|
||||
};
|
||||
let m: *syntax.node = syntax.newnode(syntax.nkind.N_FNDECL, pf, pl, pc);
|
||||
m.str = "main";
|
||||
|
||||
@@ -14232,14 +14232,15 @@ fn exprtype(c: *checker, e: *syntax.node, hint: *syntax.node) *syntax.node = {
|
||||
// Module-qualified callee whose leaf isn't scope-keyed
|
||||
// under its module: align to cstage, which stamps ty_err
|
||||
// here and lets cgen emit the call (cmd/wcc/check.c:1834-
|
||||
// 1843; rule-10). The -T synth's `test.run` hits this in
|
||||
// BOTH combined and sep (Q2-confirmed): lib/test's `run` is
|
||||
// scope-keyed under "" not "test" — the directive-for-cgen
|
||||
// vs declmod-for-scope keying split, the module-qualified
|
||||
// arm of #27. cgen still emits the correct CALL test.run
|
||||
// from run's `//ww:module test` directive. Load-bearing
|
||||
// until #80 module-keys run under sep so the synth call
|
||||
// type-resolves; NOT an M4-transient.
|
||||
// 1843; rule-10). This now tolerates only a genuinely-
|
||||
// extern leaf (raw w6c on a single module-qualified file
|
||||
// with no driver concat), the module-qualified arm of #27.
|
||||
// The -T synth's `test.run` NO LONGER lands here: #80
|
||||
// PREPENDS the synth `use test;` before Pass 1, so declmod
|
||||
// keys lib/test's `run` under "test" (not "") and the synth
|
||||
// `test.run` type-resolves — the E1 bridge is closed. cgen
|
||||
// keys the CALL off run's `//ww:module test` directive
|
||||
// either way, so the resolution change is asm-neutral.
|
||||
if (s == nil) {
|
||||
e.type_ = c.tc.tyerr: *void;
|
||||
callee.type_ = c.tc.tyerr: *void; // N_DOT node itself (asserttyped checks it)
|
||||
@@ -17108,6 +17109,24 @@ export fn checkfile(c: *checker, file: *syntax.node) void = {
|
||||
if (file.kind != syntax.nkind.N_FILE) { return; };
|
||||
c.file = file;
|
||||
|
||||
// #80: under -T, PREPEND the synth `use test;` BEFORE Pass 1 so declmod
|
||||
// (called per-decl during install) sees a matching `use test` when it
|
||||
// keys lib/test's `run` — keying it under mod="test", not "". This is a
|
||||
// pure ORDER fix: the synth N_USE was appended AFTER install (below),
|
||||
// too late for declmod, so `run` keyed under "" — leaving the synth
|
||||
// `test.run` ty_err (the E1 bridge) and colliding with a user root
|
||||
// `fn run` (also mod=""). Decoupled from cgen: the symbol mangle keys
|
||||
// off d.module (the //ww:module directive, cgen mod_collect), NOT this
|
||||
// scope keying — cgen already emits the correct CALL test.run. Twin of
|
||||
// cstage cmd/wcc/check.c.
|
||||
if (c.istest != 0) {
|
||||
let usenode: *syntax.node = syntax.newnode(syntax.nkind.N_USE, file.file, file.line, file.col);
|
||||
usenode.str = "test";
|
||||
usenode.usepath = "test";
|
||||
usenode.next = file.list;
|
||||
file.list = usenode;
|
||||
};
|
||||
|
||||
// Pass 1: install all top-level names.
|
||||
let d: *syntax.node = file.list;
|
||||
for (d != nil) {
|
||||
@@ -17308,17 +17327,11 @@ export fn checkfile(c: *checker, file: *syntax.node) void = {
|
||||
let ret: *syntax.node = syntax.newnode(syntax.nkind.N_RETURN, pf, pl, pc);
|
||||
ret.lhs = call;
|
||||
body.list = ret;
|
||||
// synth `use test;` so the N_DOT base binds as a module
|
||||
// qualifier (SK_USE) and usepathfor maps `test` to its path.
|
||||
// Mirror installdecl's N_USE SK_USE install. Appended to
|
||||
// file.list below; emits no asm.
|
||||
let usenode: *syntax.node = syntax.newnode(syntax.nkind.N_USE, pf, pl, pc);
|
||||
usenode.str = "test";
|
||||
usenode.usepath = "test";
|
||||
syntax.scopedefine(c.top, "test", syntax.skind.SK_USE, nil, usenode);
|
||||
let ul: *syntax.node = file.list;
|
||||
if (ul == nil) { file.list = usenode; }
|
||||
else { for (ul.next != nil) { ul = ul.next; }; ul.next = usenode; };
|
||||
// #80: the synth `use test;` (the N_DOT base qualifier + the
|
||||
// usepathfor source mapping `test`→its path) is now PREPENDED
|
||||
// before Pass 1 at the top of checkfile, so declmod keys
|
||||
// lib/test's `run` under "test" and the synth `test.run`
|
||||
// type-resolves. It is installed (SK_USE) by Pass 1's N_USE arm.
|
||||
};
|
||||
let m: *syntax.node = syntax.newnode(syntax.nkind.N_FNDECL, pf, pl, pc);
|
||||
m.str = "main";
|
||||
|
||||
Reference in New Issue
Block a user