w6c: variant-tag miss is loud, never tag 0 (rule 7)

Every variant-index lookup miss (-1) was silently clamped to tag 0
across both stages: tagged return (value + bare-void), widen store
(struct/slice/str/float/scalar arms + push fast path + field store),
widen tag-remap (identity scan + emit loop), match case compare,
is/as typetest, tryprop error remap, and the alloc-nomem propagation
(clamped to 1). All misses are checker-rejected upstream today, so
the clamps were dead -- but any future checker/cgen seam gap would
mis-tag silently (wrong arm, wrong error, false success). Rule 7:
each site now hard-stops with a per-construct diagnostic; nullable
arms keep their raw -1 by design (a miss encodes the void polarity
for `case null`). Corpus asm byte-unchanged; bootstrap fixed point
holds.
This commit is contained in:
2026-08-09 00:12:21 +09:00
parent 94928470bc
commit 57d33acd1f
4 changed files with 140 additions and 34 deletions

View File

@@ -4016,7 +4016,11 @@ fn cgwidentagremap(c: *cgen, du: *syntax.tinfo, su: *syntax.tinfo, slot_off: i32
let idx: i32 = 0;
for (p != nil) {
let di: i32 = flatvariantidxt(dt, p.type_, false);
if (di < 0) { di = 0; };
if (di < 0) {
let mrm: str = "tagged widen: source variant missing from dst union (rule 7)\n";
os.write(2, mrm.ptr, mrm.len: u64);
os.exit(1);
};
if (di != idx) { identity = false; p = nil; }
else { p = p.tnext; idx += 1; };
};
@@ -4030,7 +4034,11 @@ fn cgwidentagremap(c: *cgen, du: *syntax.tinfo, su: *syntax.tinfo, slot_off: i32
for (p != nil) {
let next: str = mklabel(c, "remap_next");
let di: i32 = flatvariantidxt(dt, p.type_, false);
if (di < 0) { di = 0; };
if (di < 0) {
let mrm: str = "tagged widen: source variant missing from dst union (rule 7)\n";
os.write(2, mrm.ptr, mrm.len: u64);
os.exit(1);
};
emitline("\tCMPQ\t$");
emitint(idx: i64);
emitline(", AX\n");
@@ -5126,7 +5134,11 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *syntax.tinfo, src: *syntax.node, slot_of
zoff += 8;
};
let tag: i32 = taggedvariantindext(c, dt, src);
if (tag < 0) { tag = 0; };
if (tag < 0) {
let mws: str = "tagged widen: no variant tag for source (rule 7)\n";
os.write(2, mws.ptr, mws.len: u64);
os.exit(1);
};
if (src.kind == syntax.nkind.N_STRUCTLIT) {
// #23: delegate to the single fill path. The
// inline field loop this replaces was a
@@ -5206,7 +5218,11 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *syntax.tinfo, src: *syntax.node, slot_of
emitoff((slot_off + 24): i64);
emitline("(BP)\n");
let tag: i32 = taggedvariantindext(c, dt, src);
if (tag < 0) { tag = 0; };
if (tag < 0) {
let mws: str = "tagged widen: no variant tag for source (rule 7)\n";
os.write(2, mws.ptr, mws.len: u64);
os.exit(1);
};
emitline("\tMOVQ\t$");
emitint(tag: i64);
emitline(", ");
@@ -5309,7 +5325,11 @@ fn cgwidentaggedstorebp(c: *cgen, dst: *syntax.tinfo, src: *syntax.node, slot_of
};
};
let tag: i32 = taggedvariantindext(c, dt, src);
if (tag < 0) { tag = 0; };
if (tag < 0) {
let mws: str = "tagged widen: no variant tag for source (rule 7)\n";
os.write(2, mws.ptr, mws.len: u64);
os.exit(1);
};
emitline("\tMOVQ\t$");
emitint(tag: i64);
emitline(", ");