selfhost/cmd/wcc: matchscrutt returns scrutinee node, gate on istaggedtype (#67)

matchscrutt's N_DOT branch resolved the field type via the dotfieldtnode
AST walk + resolvetagged; post-#66 the N_DOT node carries the field tinfo
on .type_, so return the scrutinee node directly and let cgmatch gate on
istaggedtype(scrutt) instead of scrutt.kind == N_TTAGGED. All six scrutt
consumers read .type_ (peeling TY_NAMED), none reads node structure, so a
value node vs a type node is invisible downstream; the istaggedtype guard
preserves the old nil-for-non-tagged contract.

Symmetry-improving (rule 10): cstage derives the dispatch type from s->type
with one unconditional NAMED-peel (cmd/w6c/cgen.c:4847-4850; the N_IDENT
check at :4854 is only the slot-offset fast-path). The old dotfieldtnode
required base.kind == N_IDENT -- a restriction cstage never had -- so the
chained-dot widening this enables matches cstage (out-of-corpus, #14).

Drops matchscrutt's dotfieldtnode caller (external callers 2->1; the
indexvaluetnode:1084 internal recursion remains, and the cgassign tagged-
store sites still need the node-keyed resolvetagged machinery, so neither
walker is deletable yet -- store-migration + #61d follow). N_DOT-match
coverage: 693/694/695/700/744 (runtime). byte-id 990-997 unchanged, 134/134.
This commit is contained in:
2026-05-23 21:55:52 +09:00
parent 3036ba766d
commit aec48e8c13
4 changed files with 42 additions and 12 deletions

View File

@@ -12436,9 +12436,15 @@ fn matchscrutt(c: *cgen, scrut: *node) *node = {
return resolvetagged(c, etn);
};
if (k == nkind.N_DOT) {
let ft: *node = dotfieldtnode(c, scrut);
if (ft == nil) { return nil; };
return resolvetagged(c, ft);
// #67: read the field's stamped tinfo off the N_DOT node
// (post-#66 N_DOT carries the field type) instead of the
// dotfieldtnode AST walk. cgmatch's gate reads scrutt.type_
// via istaggedtype, so the resolved N_TTAGGED node the walk
// produced is no longer the carrier; the istaggedtype guard
// preserves the nil-for-non-tagged contract the sibling
// N_CALL/N_INDEX branches get from resolvetagged.
if (!istaggedtype(c, scrut)) { return nil; };
return scrut;
};
return nil;
};
@@ -15115,7 +15121,11 @@ fn cgmatch(c: *cgen, n: *node) void = {
} else {
let want: i32 = 0;
if (scrutt != nil) {
if (scrutt.kind == nkind.N_TTAGGED) {
// #67: gate on the stamped tinfo, not the node kind
// — matchscrutt now returns the scrutinee node itself
// for an N_DOT field (its .type_ is the tagged tinfo)
// rather than the resolved N_TTAGGED node.
if (istaggedtype(c, scrutt)) {
let r: i32 = -1;
if (pat.kind == nkind.N_TNAME) {
r = flatvariantidx(c, scrutt, pat);

View File

@@ -1116,7 +1116,11 @@ fn cgmatch(c: *cgen, n: *node) void = {
} else {
let want: i32 = 0;
if (scrutt != nil) {
if (scrutt.kind == nkind.N_TTAGGED) {
// #67: gate on the stamped tinfo, not the node kind
// — matchscrutt now returns the scrutinee node itself
// for an N_DOT field (its .type_ is the tagged tinfo)
// rather than the resolved N_TTAGGED node.
if (istaggedtype(c, scrutt)) {
let r: i32 = -1;
if (pat.kind == nkind.N_TNAME) {
r = flatvariantidx(c, scrutt, pat);

View File

@@ -1891,9 +1891,15 @@ fn matchscrutt(c: *cgen, scrut: *node) *node = {
return resolvetagged(c, etn);
};
if (k == nkind.N_DOT) {
let ft: *node = dotfieldtnode(c, scrut);
if (ft == nil) { return nil; };
return resolvetagged(c, ft);
// #67: read the field's stamped tinfo off the N_DOT node
// (post-#66 N_DOT carries the field type) instead of the
// dotfieldtnode AST walk. cgmatch's gate reads scrutt.type_
// via istaggedtype, so the resolved N_TTAGGED node the walk
// produced is no longer the carrier; the istaggedtype guard
// preserves the nil-for-non-tagged contract the sibling
// N_CALL/N_INDEX branches get from resolvetagged.
if (!istaggedtype(c, scrut)) { return nil; };
return scrut;
};
return nil;
};

View File

@@ -12436,9 +12436,15 @@ fn matchscrutt(c: *cgen, scrut: *node) *node = {
return resolvetagged(c, etn);
};
if (k == nkind.N_DOT) {
let ft: *node = dotfieldtnode(c, scrut);
if (ft == nil) { return nil; };
return resolvetagged(c, ft);
// #67: read the field's stamped tinfo off the N_DOT node
// (post-#66 N_DOT carries the field type) instead of the
// dotfieldtnode AST walk. cgmatch's gate reads scrutt.type_
// via istaggedtype, so the resolved N_TTAGGED node the walk
// produced is no longer the carrier; the istaggedtype guard
// preserves the nil-for-non-tagged contract the sibling
// N_CALL/N_INDEX branches get from resolvetagged.
if (!istaggedtype(c, scrut)) { return nil; };
return scrut;
};
return nil;
};
@@ -15115,7 +15121,11 @@ fn cgmatch(c: *cgen, n: *node) void = {
} else {
let want: i32 = 0;
if (scrutt != nil) {
if (scrutt.kind == nkind.N_TTAGGED) {
// #67: gate on the stamped tinfo, not the node kind
// — matchscrutt now returns the scrutinee node itself
// for an N_DOT field (its .type_ is the tagged tinfo)
// rather than the resolved N_TTAGGED node.
if (istaggedtype(c, scrutt)) {
let r: i32 = -1;
if (pat.kind == nkind.N_TNAME) {
r = flatvariantidx(c, scrutt, pat);