From 391ef61d422900416e30925fa29440e6b57eac15 Mon Sep 17 00:00:00 2001 From: Hojun-Cho Date: Mon, 15 Jun 2026 01:46:16 +0900 Subject: [PATCH] wcc/ww: typeeqast identity fast-path for shared type nodes (#36) wwstage's typeeqast lacked the identity short-circuit cstage type_eq opens with (cmd/wcc/type.c:250 `if (a == b) return 1`). Enum/struct/ array type nodes are shared from their decl, so two references to the same type resolve to one node; without the fast-path the catch-all returns false. Exposed by #26's integer-mismatch reject, which fired on a same-enum binop like w6l's `os.flag.WRONLY|CREATE|TRUNC` that cstage accepts via this check. Corpus output unchanged (the w6c_ww/ wwdump_ww binaries move because check.ww regenerates combined.ww). --- selfhost/cmd/w6c/main.combined.ww | 8 ++++++++ selfhost/cmd/wcc/check.ww | 8 ++++++++ selfhost/cmd/wwdump/main.combined.ww | 8 ++++++++ 3 files changed, 24 insertions(+) diff --git a/selfhost/cmd/w6c/main.combined.ww b/selfhost/cmd/w6c/main.combined.ww index 4a634ff2..6b0ded0b 100644 --- a/selfhost/cmd/w6c/main.combined.ww +++ b/selfhost/cmd/w6c/main.combined.ww @@ -11424,6 +11424,14 @@ fn typeeqast(c: *checker, a: *node, b: *node) bool = { let bb: *node = unwrapbang(b); if (aa == nil) { return bb == nil; }; if (bb == nil) { return false; }; + // Identity fast-path, mirroring cstage type_eq's first line + // (cmd/wcc/type.c:250 `if (a == b) return 1`). Enum (and struct/ + // array) type nodes are shared from their decl, so two references to + // the SAME `os.flag` resolve to one N_TENUM node; without this the + // catch-all below returns false and the #26 reject fires on a + // same-enum binop like `os.flag.WRONLY | os.flag.CREATE` (w6l), which + // cstage accepts via this identity check. + if (aa == bb) { return true; }; if (aa.kind != bb.kind) { return false; }; let k: nkind = aa.kind; if (k == nkind.N_TNAME) { diff --git a/selfhost/cmd/wcc/check.ww b/selfhost/cmd/wcc/check.ww index e422cba9..2a91df31 100644 --- a/selfhost/cmd/wcc/check.ww +++ b/selfhost/cmd/wcc/check.ww @@ -954,6 +954,14 @@ fn typeeqast(c: *checker, a: *node, b: *node) bool = { let bb: *node = unwrapbang(b); if (aa == nil) { return bb == nil; }; if (bb == nil) { return false; }; + // Identity fast-path, mirroring cstage type_eq's first line + // (cmd/wcc/type.c:250 `if (a == b) return 1`). Enum (and struct/ + // array) type nodes are shared from their decl, so two references to + // the SAME `os.flag` resolve to one N_TENUM node; without this the + // catch-all below returns false and the #26 reject fires on a + // same-enum binop like `os.flag.WRONLY | os.flag.CREATE` (w6l), which + // cstage accepts via this identity check. + if (aa == bb) { return true; }; if (aa.kind != bb.kind) { return false; }; let k: nkind = aa.kind; if (k == nkind.N_TNAME) { diff --git a/selfhost/cmd/wwdump/main.combined.ww b/selfhost/cmd/wwdump/main.combined.ww index 8c5374f4..84e0ce85 100644 --- a/selfhost/cmd/wwdump/main.combined.ww +++ b/selfhost/cmd/wwdump/main.combined.ww @@ -11424,6 +11424,14 @@ fn typeeqast(c: *checker, a: *node, b: *node) bool = { let bb: *node = unwrapbang(b); if (aa == nil) { return bb == nil; }; if (bb == nil) { return false; }; + // Identity fast-path, mirroring cstage type_eq's first line + // (cmd/wcc/type.c:250 `if (a == b) return 1`). Enum (and struct/ + // array) type nodes are shared from their decl, so two references to + // the SAME `os.flag` resolve to one N_TENUM node; without this the + // catch-all below returns false and the #26 reject fires on a + // same-enum binop like `os.flag.WRONLY | os.flag.CREATE` (w6l), which + // cstage accepts via this identity check. + if (aa == bb) { return true; }; if (aa.kind != bb.kind) { return false; }; let k: nkind = aa.kind; if (k == nkind.N_TNAME) {