diff --git a/selfhost/cmd/w6c/main.combined.ww b/selfhost/cmd/w6c/main.combined.ww index 14a37d0d..092cdd44 100644 --- a/selfhost/cmd/w6c/main.combined.ww +++ b/selfhost/cmd/w6c/main.combined.ww @@ -8139,9 +8139,10 @@ fn enumvalfold(body: *node, until: *node, e: *node, out: *u64) bool = { // fallback arm). fn tupleelemslot(pt: *tinfo) u64 = { if (pt == nil) { return 8u64; }; - // #63 Phase-N step 1: peel TY_NAMED before this structural query; - // wrappers are built in step 2 (#64). No-op today (tinfofornode - // still collapses aliases → no TY_NAMED), so byte-id is unchanged. + // #63 Phase-N step 1: peel TY_NAMED before this structural query. + // #64 builds per-decl NAMED wrappers (tinfofornode), so the peel + // now fires on aliased operands; byte-id holds because it collapses + // NAMED to the alias-invariant underlying this read consumes. let t: *tinfo = pt; for (t != nil && t.kind == tykind.TY_NAMED) { t = t.under; }; if (t == nil) { return 8u64; }; @@ -8170,9 +8171,10 @@ fn tupleelemslot(pt: *tinfo) u64 = { // pad-to-8); arrays use their slot-padded element-stride * elen. fn fieldslotsize(ft: *tinfo) u64 = { if (ft == nil) { return 8u64; }; - // #63 Phase-N step 1: peel TY_NAMED before this structural query; - // wrappers are built in step 2 (#64). No-op today (tinfofornode - // still collapses aliases → no TY_NAMED), so byte-id is unchanged. + // #63 Phase-N step 1: peel TY_NAMED before this structural query. + // #64 builds per-decl NAMED wrappers (tinfofornode), so the peel + // now fires on aliased operands; byte-id holds because it collapses + // NAMED to the alias-invariant underlying this read consumes. let t: *tinfo = ft; for (t != nil && t.kind == tykind.TY_NAMED) { t = t.under; }; if (t == nil) { return 8u64; }; @@ -11271,6 +11273,15 @@ fn elemissignedc(c: *cgen, t: *node) bool = { if (t == nil) { return false; }; let ti: *tinfo = t.type_: *tinfo; if (ti == nil) { return false; }; + // #65 Phase-N step-2 cleanup: peel TY_NAMED before the .sub read. + // #64 now flows per-decl NAMED wrappers, so a NAMED-of-(`*T`/`[]T`/ + // `[N]T`) reaching here would read NAMED.sub (nil) instead of the + // element. Mirrors cstage idx_eff's type_unwrap (cmd/w6c/cgen.c:790) + // before the eff->sub read (:3518-3520). Byte-id-neutral: every + // aliased indexable in-tree has a u8 element (typeissigned=false + // either way). Transitive peel matches the #63 idiom. + for (ti != nil && ti.kind == tykind.TY_NAMED) { ti = ti.under; }; + if (ti == nil) { return false; }; return typeissigned(ti.sub); }; @@ -12195,9 +12206,10 @@ fn slotsize(c: *cgen, typn: *node) i32 = { if (typn == nil) { return 8; }; let ti: *tinfo = typn.type_: *tinfo; if (ti == nil) { return 8; }; - // #63 Phase-N step 1: peel TY_NAMED before this structural query; - // wrappers are built in step 2 (#64). No-op today (tinfofornode - // still collapses aliases → no TY_NAMED), so byte-id is unchanged. + // #63 Phase-N step 1: peel TY_NAMED before this structural query. + // #64 builds per-decl NAMED wrappers (tinfofornode), so the peel + // now fires on aliased operands; byte-id holds because it collapses + // NAMED to the alias-invariant underlying this read consumes. for (ti != nil && ti.kind == tykind.TY_NAMED) { ti = ti.under; }; if (ti == nil) { return 8; }; let kk: tykind = ti.kind; @@ -12232,9 +12244,10 @@ fn fieldsize(c: *cgen, tnode: *node) i32 = { if (tnode == nil) { return 8; }; let ti: *tinfo = tnode.type_: *tinfo; if (ti == nil) { return 8; }; - // #63 Phase-N step 1: peel TY_NAMED before this structural query; - // wrappers are built in step 2 (#64). No-op today (tinfofornode - // still collapses aliases → no TY_NAMED), so byte-id is unchanged. + // #63 Phase-N step 1: peel TY_NAMED before this structural query. + // #64 builds per-decl NAMED wrappers (tinfofornode), so the peel + // now fires on aliased operands; byte-id holds because it collapses + // NAMED to the alias-invariant underlying this read consumes. for (ti != nil && ti.kind == tykind.TY_NAMED) { ti = ti.under; }; if (ti == nil) { return 8; }; let k: tykind = ti.kind; @@ -12581,9 +12594,10 @@ export fn nullableptrtag(t: *node) i32 = { if (t == nil) { return 0; }; let ti: *tinfo = t.type_: *tinfo; if (ti == nil) { return 0; }; - // #63 Phase-N step 1: peel TY_NAMED before this structural query; - // wrappers are built in step 2 (#64). No-op today (tinfofornode - // still collapses aliases → no TY_NAMED), so byte-id is unchanged. + // #63 Phase-N step 1: peel TY_NAMED before this structural query. + // #64 builds per-decl NAMED wrappers (tinfofornode), so the peel + // now fires on aliased operands; byte-id holds because it collapses + // NAMED to the alias-invariant underlying this read consumes. for (ti != nil && ti.kind == tykind.TY_NAMED) { ti = ti.under; }; if (ti == nil) { return 0; }; if (ti.kind != tykind.TY_TAGGED) { return 0; }; diff --git a/selfhost/cmd/wcc/cgenutil.ww b/selfhost/cmd/wcc/cgenutil.ww index 9fdd5147..47898dd1 100644 --- a/selfhost/cmd/wcc/cgenutil.ww +++ b/selfhost/cmd/wcc/cgenutil.ww @@ -747,6 +747,15 @@ fn elemissignedc(c: *cgen, t: *node) bool = { if (t == nil) { return false; }; let ti: *tinfo = t.type_: *tinfo; if (ti == nil) { return false; }; + // #65 Phase-N step-2 cleanup: peel TY_NAMED before the .sub read. + // #64 now flows per-decl NAMED wrappers, so a NAMED-of-(`*T`/`[]T`/ + // `[N]T`) reaching here would read NAMED.sub (nil) instead of the + // element. Mirrors cstage idx_eff's type_unwrap (cmd/w6c/cgen.c:790) + // before the eff->sub read (:3518-3520). Byte-id-neutral: every + // aliased indexable in-tree has a u8 element (typeissigned=false + // either way). Transitive peel matches the #63 idiom. + for (ti != nil && ti.kind == tykind.TY_NAMED) { ti = ti.under; }; + if (ti == nil) { return false; }; return typeissigned(ti.sub); }; @@ -1671,9 +1680,10 @@ fn slotsize(c: *cgen, typn: *node) i32 = { if (typn == nil) { return 8; }; let ti: *tinfo = typn.type_: *tinfo; if (ti == nil) { return 8; }; - // #63 Phase-N step 1: peel TY_NAMED before this structural query; - // wrappers are built in step 2 (#64). No-op today (tinfofornode - // still collapses aliases → no TY_NAMED), so byte-id is unchanged. + // #63 Phase-N step 1: peel TY_NAMED before this structural query. + // #64 builds per-decl NAMED wrappers (tinfofornode), so the peel + // now fires on aliased operands; byte-id holds because it collapses + // NAMED to the alias-invariant underlying this read consumes. for (ti != nil && ti.kind == tykind.TY_NAMED) { ti = ti.under; }; if (ti == nil) { return 8; }; let kk: tykind = ti.kind; @@ -1708,9 +1718,10 @@ fn fieldsize(c: *cgen, tnode: *node) i32 = { if (tnode == nil) { return 8; }; let ti: *tinfo = tnode.type_: *tinfo; if (ti == nil) { return 8; }; - // #63 Phase-N step 1: peel TY_NAMED before this structural query; - // wrappers are built in step 2 (#64). No-op today (tinfofornode - // still collapses aliases → no TY_NAMED), so byte-id is unchanged. + // #63 Phase-N step 1: peel TY_NAMED before this structural query. + // #64 builds per-decl NAMED wrappers (tinfofornode), so the peel + // now fires on aliased operands; byte-id holds because it collapses + // NAMED to the alias-invariant underlying this read consumes. for (ti != nil && ti.kind == tykind.TY_NAMED) { ti = ti.under; }; if (ti == nil) { return 8; }; let k: tykind = ti.kind; @@ -2057,9 +2068,10 @@ export fn nullableptrtag(t: *node) i32 = { if (t == nil) { return 0; }; let ti: *tinfo = t.type_: *tinfo; if (ti == nil) { return 0; }; - // #63 Phase-N step 1: peel TY_NAMED before this structural query; - // wrappers are built in step 2 (#64). No-op today (tinfofornode - // still collapses aliases → no TY_NAMED), so byte-id is unchanged. + // #63 Phase-N step 1: peel TY_NAMED before this structural query. + // #64 builds per-decl NAMED wrappers (tinfofornode), so the peel + // now fires on aliased operands; byte-id holds because it collapses + // NAMED to the alias-invariant underlying this read consumes. for (ti != nil && ti.kind == tykind.TY_NAMED) { ti = ti.under; }; if (ti == nil) { return 0; }; if (ti.kind != tykind.TY_TAGGED) { return 0; }; diff --git a/selfhost/cmd/wcc/check.ww b/selfhost/cmd/wcc/check.ww index c53a2fe2..b94c5c5d 100644 --- a/selfhost/cmd/wcc/check.ww +++ b/selfhost/cmd/wcc/check.ww @@ -1042,9 +1042,10 @@ fn enumvalfold(body: *node, until: *node, e: *node, out: *u64) bool = { // fallback arm). fn tupleelemslot(pt: *tinfo) u64 = { if (pt == nil) { return 8u64; }; - // #63 Phase-N step 1: peel TY_NAMED before this structural query; - // wrappers are built in step 2 (#64). No-op today (tinfofornode - // still collapses aliases → no TY_NAMED), so byte-id is unchanged. + // #63 Phase-N step 1: peel TY_NAMED before this structural query. + // #64 builds per-decl NAMED wrappers (tinfofornode), so the peel + // now fires on aliased operands; byte-id holds because it collapses + // NAMED to the alias-invariant underlying this read consumes. let t: *tinfo = pt; for (t != nil && t.kind == tykind.TY_NAMED) { t = t.under; }; if (t == nil) { return 8u64; }; @@ -1073,9 +1074,10 @@ fn tupleelemslot(pt: *tinfo) u64 = { // pad-to-8); arrays use their slot-padded element-stride * elen. fn fieldslotsize(ft: *tinfo) u64 = { if (ft == nil) { return 8u64; }; - // #63 Phase-N step 1: peel TY_NAMED before this structural query; - // wrappers are built in step 2 (#64). No-op today (tinfofornode - // still collapses aliases → no TY_NAMED), so byte-id is unchanged. + // #63 Phase-N step 1: peel TY_NAMED before this structural query. + // #64 builds per-decl NAMED wrappers (tinfofornode), so the peel + // now fires on aliased operands; byte-id holds because it collapses + // NAMED to the alias-invariant underlying this read consumes. let t: *tinfo = ft; for (t != nil && t.kind == tykind.TY_NAMED) { t = t.under; }; if (t == nil) { return 8u64; }; diff --git a/selfhost/cmd/wwdump/main.combined.ww b/selfhost/cmd/wwdump/main.combined.ww index 2b3278ca..49a24f82 100644 --- a/selfhost/cmd/wwdump/main.combined.ww +++ b/selfhost/cmd/wwdump/main.combined.ww @@ -8139,9 +8139,10 @@ fn enumvalfold(body: *node, until: *node, e: *node, out: *u64) bool = { // fallback arm). fn tupleelemslot(pt: *tinfo) u64 = { if (pt == nil) { return 8u64; }; - // #63 Phase-N step 1: peel TY_NAMED before this structural query; - // wrappers are built in step 2 (#64). No-op today (tinfofornode - // still collapses aliases → no TY_NAMED), so byte-id is unchanged. + // #63 Phase-N step 1: peel TY_NAMED before this structural query. + // #64 builds per-decl NAMED wrappers (tinfofornode), so the peel + // now fires on aliased operands; byte-id holds because it collapses + // NAMED to the alias-invariant underlying this read consumes. let t: *tinfo = pt; for (t != nil && t.kind == tykind.TY_NAMED) { t = t.under; }; if (t == nil) { return 8u64; }; @@ -8170,9 +8171,10 @@ fn tupleelemslot(pt: *tinfo) u64 = { // pad-to-8); arrays use their slot-padded element-stride * elen. fn fieldslotsize(ft: *tinfo) u64 = { if (ft == nil) { return 8u64; }; - // #63 Phase-N step 1: peel TY_NAMED before this structural query; - // wrappers are built in step 2 (#64). No-op today (tinfofornode - // still collapses aliases → no TY_NAMED), so byte-id is unchanged. + // #63 Phase-N step 1: peel TY_NAMED before this structural query. + // #64 builds per-decl NAMED wrappers (tinfofornode), so the peel + // now fires on aliased operands; byte-id holds because it collapses + // NAMED to the alias-invariant underlying this read consumes. let t: *tinfo = ft; for (t != nil && t.kind == tykind.TY_NAMED) { t = t.under; }; if (t == nil) { return 8u64; }; @@ -11271,6 +11273,15 @@ fn elemissignedc(c: *cgen, t: *node) bool = { if (t == nil) { return false; }; let ti: *tinfo = t.type_: *tinfo; if (ti == nil) { return false; }; + // #65 Phase-N step-2 cleanup: peel TY_NAMED before the .sub read. + // #64 now flows per-decl NAMED wrappers, so a NAMED-of-(`*T`/`[]T`/ + // `[N]T`) reaching here would read NAMED.sub (nil) instead of the + // element. Mirrors cstage idx_eff's type_unwrap (cmd/w6c/cgen.c:790) + // before the eff->sub read (:3518-3520). Byte-id-neutral: every + // aliased indexable in-tree has a u8 element (typeissigned=false + // either way). Transitive peel matches the #63 idiom. + for (ti != nil && ti.kind == tykind.TY_NAMED) { ti = ti.under; }; + if (ti == nil) { return false; }; return typeissigned(ti.sub); }; @@ -12195,9 +12206,10 @@ fn slotsize(c: *cgen, typn: *node) i32 = { if (typn == nil) { return 8; }; let ti: *tinfo = typn.type_: *tinfo; if (ti == nil) { return 8; }; - // #63 Phase-N step 1: peel TY_NAMED before this structural query; - // wrappers are built in step 2 (#64). No-op today (tinfofornode - // still collapses aliases → no TY_NAMED), so byte-id is unchanged. + // #63 Phase-N step 1: peel TY_NAMED before this structural query. + // #64 builds per-decl NAMED wrappers (tinfofornode), so the peel + // now fires on aliased operands; byte-id holds because it collapses + // NAMED to the alias-invariant underlying this read consumes. for (ti != nil && ti.kind == tykind.TY_NAMED) { ti = ti.under; }; if (ti == nil) { return 8; }; let kk: tykind = ti.kind; @@ -12232,9 +12244,10 @@ fn fieldsize(c: *cgen, tnode: *node) i32 = { if (tnode == nil) { return 8; }; let ti: *tinfo = tnode.type_: *tinfo; if (ti == nil) { return 8; }; - // #63 Phase-N step 1: peel TY_NAMED before this structural query; - // wrappers are built in step 2 (#64). No-op today (tinfofornode - // still collapses aliases → no TY_NAMED), so byte-id is unchanged. + // #63 Phase-N step 1: peel TY_NAMED before this structural query. + // #64 builds per-decl NAMED wrappers (tinfofornode), so the peel + // now fires on aliased operands; byte-id holds because it collapses + // NAMED to the alias-invariant underlying this read consumes. for (ti != nil && ti.kind == tykind.TY_NAMED) { ti = ti.under; }; if (ti == nil) { return 8; }; let k: tykind = ti.kind; @@ -12581,9 +12594,10 @@ export fn nullableptrtag(t: *node) i32 = { if (t == nil) { return 0; }; let ti: *tinfo = t.type_: *tinfo; if (ti == nil) { return 0; }; - // #63 Phase-N step 1: peel TY_NAMED before this structural query; - // wrappers are built in step 2 (#64). No-op today (tinfofornode - // still collapses aliases → no TY_NAMED), so byte-id is unchanged. + // #63 Phase-N step 1: peel TY_NAMED before this structural query. + // #64 builds per-decl NAMED wrappers (tinfofornode), so the peel + // now fires on aliased operands; byte-id holds because it collapses + // NAMED to the alias-invariant underlying this read consumes. for (ti != nil && ti.kind == tykind.TY_NAMED) { ti = ti.under; }; if (ti == nil) { return 0; }; if (ti.kind != tykind.TY_TAGGED) { return 0; };