diff --git a/selfhost/cmd/w6c/main.combined.ww b/selfhost/cmd/w6c/main.combined.ww index 4c0af8fe..46bcafa7 100644 --- a/selfhost/cmd/w6c/main.combined.ww +++ b/selfhost/cmd/w6c/main.combined.ww @@ -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 diff --git a/selfhost/cmd/wcc/cgenutil.ww b/selfhost/cmd/wcc/cgenutil.ww index 5f2bb547..86fb8026 100644 --- a/selfhost/cmd/wcc/cgenutil.ww +++ b/selfhost/cmd/wcc/cgenutil.ww @@ -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 diff --git a/selfhost/cmd/wwdump/main.combined.ww b/selfhost/cmd/wwdump/main.combined.ww index 10bb2905..01798111 100644 --- a/selfhost/cmd/wwdump/main.combined.ww +++ b/selfhost/cmd/wwdump/main.combined.ww @@ -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