wcc/ww: nodeisslice/nodeisstr local idents read the checker stamp

Collapse the localfindnode tnode read to the stamped n.type_ — a
zero-delta mechanic validation for the F7 predicate type-keying arc:
self-compile byte-id holds on all four bootstrap combineds, proving
n.type_ matches the local-table truth on every corpus local before
any behavior-changing conversion lands. The localfindnode gate stays
so a global-not-def ident still routes false.
This commit is contained in:
2026-06-12 00:01:01 +09:00
parent 556a65ee86
commit 6afa72afea
3 changed files with 60 additions and 24 deletions

View File

@@ -18521,7 +18521,15 @@ fn nodeisslice(c: *cgen, n: *node) bool = {
if (k == nkind.N_IDENT) {
let nm: str = n.str;
let lc: *local = localfindnode(c, nm);
if (lc != nil) { return isslicetype(c, lc.tnode); };
// F7-c1: the local read collapses onto the checker-stamped
// n.type_, the same shape cstage's node_isslice uses
// (cmd/w6c/cgen.c:182 type_isslice(n->type)). lc.tnode.type_
// (what isslicetype read) and n.type_ are the same tinfo for a
// local ident (exprtype N_IDENT stamps n.type_ off the same
// decl localfindnode keys on); the localfindnode gate stays to
// keep the global-var-not-def case routing to false (out of F7
// scope), so this is a zero-delta mechanic validation.
if (lc != nil) { return typeisslice(n.type_: *tinfo); };
// #21: a module-level `def g: []T` ident is not a frame
// slot (localfindnode→nil), so the local arm above misses
// it and it would fall to the scalar single-PUSHQ default,
@@ -18605,13 +18613,17 @@ fn nodeisstr(c: *cgen, n: *node) bool = {
if (k == nkind.N_IDENT) {
let nm: str = n.str;
let lc: *local = localfindnode(c, nm);
if (lc != nil) {
// Use isstrtype so `!str` aliases (parserr = !str) and
// `type foo = str;` chains resolve through. The bare
// `streq("str", ...)` test missed them and dropped the
// MOVQ BX,CX shuffle on returns of str-aliased locals.
if (isstrtype(c, lc.tnode)) { return true; };
};
// F7-c1: the local read collapses onto the checker-stamped
// n.type_, the same shape cstage's node_isstr uses (cmd/w6c/
// cgen.c:213 type_isstr(n->type)). typeisstr chases TY_NAMED so
// `!str` aliases (parserr = !str) and `type foo = str;` chains
// resolve through exactly as isstrtype(lc.tnode) did — n.type_
// and lc.tnode.type_ are the same tinfo for a local ident
// (exprtype N_IDENT stamps n.type_ off the same decl
// localfindnode keys on). The localfindnode gate stays to keep
// the global-var-not-def case routing to false (out of F7
// scope), so this is a zero-delta mechanic validation.
if (lc != nil) { return typeisstr(n.type_: *tinfo); };
// #21: a module-level `def s: str` ident is not a frame slot
// (localfindnode→nil), so the local arm above misses it and
// it would fall to the scalar single-PUSHQ default, dropping

View File

@@ -1148,7 +1148,15 @@ fn nodeisslice(c: *cgen, n: *node) bool = {
if (k == nkind.N_IDENT) {
let nm: str = n.str;
let lc: *local = localfindnode(c, nm);
if (lc != nil) { return isslicetype(c, lc.tnode); };
// F7-c1: the local read collapses onto the checker-stamped
// n.type_, the same shape cstage's node_isslice uses
// (cmd/w6c/cgen.c:182 type_isslice(n->type)). lc.tnode.type_
// (what isslicetype read) and n.type_ are the same tinfo for a
// local ident (exprtype N_IDENT stamps n.type_ off the same
// decl localfindnode keys on); the localfindnode gate stays to
// keep the global-var-not-def case routing to false (out of F7
// scope), so this is a zero-delta mechanic validation.
if (lc != nil) { return typeisslice(n.type_: *tinfo); };
// #21: a module-level `def g: []T` ident is not a frame
// slot (localfindnode→nil), so the local arm above misses
// it and it would fall to the scalar single-PUSHQ default,
@@ -1232,13 +1240,17 @@ fn nodeisstr(c: *cgen, n: *node) bool = {
if (k == nkind.N_IDENT) {
let nm: str = n.str;
let lc: *local = localfindnode(c, nm);
if (lc != nil) {
// Use isstrtype so `!str` aliases (parserr = !str) and
// `type foo = str;` chains resolve through. The bare
// `streq("str", ...)` test missed them and dropped the
// MOVQ BX,CX shuffle on returns of str-aliased locals.
if (isstrtype(c, lc.tnode)) { return true; };
};
// F7-c1: the local read collapses onto the checker-stamped
// n.type_, the same shape cstage's node_isstr uses (cmd/w6c/
// cgen.c:213 type_isstr(n->type)). typeisstr chases TY_NAMED so
// `!str` aliases (parserr = !str) and `type foo = str;` chains
// resolve through exactly as isstrtype(lc.tnode) did — n.type_
// and lc.tnode.type_ are the same tinfo for a local ident
// (exprtype N_IDENT stamps n.type_ off the same decl
// localfindnode keys on). The localfindnode gate stays to keep
// the global-var-not-def case routing to false (out of F7
// scope), so this is a zero-delta mechanic validation.
if (lc != nil) { return typeisstr(n.type_: *tinfo); };
// #21: a module-level `def s: str` ident is not a frame slot
// (localfindnode→nil), so the local arm above misses it and
// it would fall to the scalar single-PUSHQ default, dropping

View File

@@ -18521,7 +18521,15 @@ fn nodeisslice(c: *cgen, n: *node) bool = {
if (k == nkind.N_IDENT) {
let nm: str = n.str;
let lc: *local = localfindnode(c, nm);
if (lc != nil) { return isslicetype(c, lc.tnode); };
// F7-c1: the local read collapses onto the checker-stamped
// n.type_, the same shape cstage's node_isslice uses
// (cmd/w6c/cgen.c:182 type_isslice(n->type)). lc.tnode.type_
// (what isslicetype read) and n.type_ are the same tinfo for a
// local ident (exprtype N_IDENT stamps n.type_ off the same
// decl localfindnode keys on); the localfindnode gate stays to
// keep the global-var-not-def case routing to false (out of F7
// scope), so this is a zero-delta mechanic validation.
if (lc != nil) { return typeisslice(n.type_: *tinfo); };
// #21: a module-level `def g: []T` ident is not a frame
// slot (localfindnode→nil), so the local arm above misses
// it and it would fall to the scalar single-PUSHQ default,
@@ -18605,13 +18613,17 @@ fn nodeisstr(c: *cgen, n: *node) bool = {
if (k == nkind.N_IDENT) {
let nm: str = n.str;
let lc: *local = localfindnode(c, nm);
if (lc != nil) {
// Use isstrtype so `!str` aliases (parserr = !str) and
// `type foo = str;` chains resolve through. The bare
// `streq("str", ...)` test missed them and dropped the
// MOVQ BX,CX shuffle on returns of str-aliased locals.
if (isstrtype(c, lc.tnode)) { return true; };
};
// F7-c1: the local read collapses onto the checker-stamped
// n.type_, the same shape cstage's node_isstr uses (cmd/w6c/
// cgen.c:213 type_isstr(n->type)). typeisstr chases TY_NAMED so
// `!str` aliases (parserr = !str) and `type foo = str;` chains
// resolve through exactly as isstrtype(lc.tnode) did — n.type_
// and lc.tnode.type_ are the same tinfo for a local ident
// (exprtype N_IDENT stamps n.type_ off the same decl
// localfindnode keys on). The localfindnode gate stays to keep
// the global-var-not-def case routing to false (out of F7
// scope), so this is a zero-delta mechanic validation.
if (lc != nil) { return typeisstr(n.type_: *tinfo); };
// #21: a module-level `def s: str` ident is not a frame slot
// (localfindnode→nil), so the local arm above misses it and
// it would fall to the scalar single-PUSHQ default, dropping