selfhost+lib/ww: N_TPARAM wrapper for tuple chains (A.6.2.0b-pre)
A.6.2.0b worker hit a real shared-`.next`-aliasing bug and stopped
per rule 7. Wwstage's N_TTUPLE chained element type ASTs via the
nodes' own `.next` field. `exprtype` routinely returns shared
nodes (sym.decl.lhs, struct field's `.lhs`, another N_TTUPLE's
`.list` element). Naive chain construction in the checker
corrupts source ASTs.
Introduce N_TPARAM = 67 as a chain wrapper for N_TTUPLE.list:
- `.lhs` holds the (possibly-shared) element type AST.
- `.next` chains within the parent N_TTUPLE.
- Other fields unused; never appears outside N_TTUPLE.list.
Mirrors cstage's Tparam at cmd/wcc/check.c:1437-1451. Cstage
keeps it at the Type layer; wwstage has no separate type layer
for tuple chains so the wrapper sits at the AST. Hare's design
intent at ref/hare/hare/ast/type.ha:117 uses `[]*_type` slice-of-
pointer — same principle, slice-flavored.
Migrations:
- lib/ww/ast.ww: kind + nkname + pr() unwrap (transparent for
the 990 -a astprint byte-diff).
- lib/ww/parse/parse.ww: parsetype N_TTUPLE construction wraps
each element in N_TPARAM (sole construction site).
- selfhost/cmd/wcc/check.ww: 4 readers (astalign, astsize,
tinfofornode TY_TUPLE, exprtype N_DOT-tuple-positional). The
last change retires the latent A.6.1.5b shared-`p` return.
- selfhost/cmd/wcc/cgenutil.ww: slotsize TY_TUPLE arm.
- selfhost/cmd/wcc/cgenexpr.ww: cgdot tuple-positional
(size/load op + str-check).
- selfhost/cmd/wcc/cgenstmt.ww: cglet TTUPLE init, cgmlet
call-return walk, cgforrange elem-size + bind-walk.
Out of scope: N_TFN params, N_TTAGGED variants, N_TSTRUCT fields.
N_TFIELD already wraps struct fields; N_TFN/N_TTAGGED aren't
currently chain-mutated by checker synthesis. If they ever are,
the same pattern applies.
Unblocks A.6.2.0b stamp on a clean foundation. Retires task #16.
Verified 132/132 incl. 990 AST byte-diff (astprint unwrap) + 995
self-rebuild byte-identity.
This commit is contained in:
@@ -98,7 +98,20 @@ type nkind = enum i32 {
|
||||
N_TENUM = 65,
|
||||
N_TENUMMEMBER = 66,
|
||||
|
||||
N_LAST = 67,
|
||||
// N_TPARAM — chain wrapper for N_TTUPLE.list elements. Mirror of
|
||||
// cstage's Tparam (cmd/wcc/check.c:1437-1451) lifted to the AST so
|
||||
// `exprtype` can return shared element-type nodes (sym.decl.lhs,
|
||||
// struct field's .lhs, another N_TTUPLE's .list element) without
|
||||
// corrupting source ASTs by reusing their .next. .lhs holds the
|
||||
// element type AST (possibly shared); .next chains within the
|
||||
// parent N_TTUPLE.list. Cstage keeps Tparam at the Type-layer; ww
|
||||
// has no separate type layer for tuple chains, so the wrapper sits
|
||||
// at the AST layer. Other node fields are unused. Never appears
|
||||
// outside an N_TTUPLE.list; astprint unwraps transparently to keep
|
||||
// the 990 -a byte-diff against cstage.
|
||||
N_TPARAM = 67,
|
||||
|
||||
N_LAST = 68,
|
||||
};
|
||||
|
||||
// ---- Node -------------------------------------------------------------
|
||||
@@ -204,6 +217,7 @@ fn nkname(k: nkind) str = {
|
||||
if (k == nkind.N_YIELD) { return "yield"; };
|
||||
if (k == nkind.N_TENUM) { return "tenum"; };
|
||||
if (k == nkind.N_TENUMMEMBER) { return "tenummember"; };
|
||||
if (k == nkind.N_TPARAM) { return "tparam"; };
|
||||
if (k == nkind.N_LAST) { return "last"; };
|
||||
return "?";
|
||||
};
|
||||
@@ -262,6 +276,14 @@ fn pr(fd: i32, n: *node, d: i32) void = {
|
||||
os.write(fd, "()\n".ptr, 3u64);
|
||||
return;
|
||||
};
|
||||
// N_TPARAM wraps an N_TTUPLE.list element so exprtype can return
|
||||
// shared element-type nodes without corrupting their .next chain.
|
||||
// Cstage has no AST-level wrapper, so unwrap here to keep the 990
|
||||
// -a byte-diff with cstage's astprint.
|
||||
if (n.kind == nkind.N_TPARAM) {
|
||||
pr(fd, n.lhs, d);
|
||||
return;
|
||||
};
|
||||
ind(fd, d);
|
||||
putc1(fd, 40u8); // '('
|
||||
let nm: str = nkname(n.kind);
|
||||
|
||||
@@ -299,13 +299,23 @@ fn parsetype(p: *parser) *node = {
|
||||
expecttok(p, tkind.TK_RPAREN, "expected ')' after parenthesised type");
|
||||
return first;
|
||||
};
|
||||
// Wrap each element in N_TPARAM so the chain owns its .next.
|
||||
// Mirrors cstage's Tparam (cmd/wcc/check.c:1437-1451); lifted
|
||||
// to the AST layer here because wwstage has no separate type
|
||||
// layer, and exprtype must return shared element-type nodes
|
||||
// (sym.decl.lhs, struct field's .lhs, another N_TTUPLE element)
|
||||
// without corrupting source ASTs.
|
||||
let n: *node = newnode(nkind.N_TTUPLE, pf, pl, pc);
|
||||
let head: *node = first;
|
||||
let tail: *node = first;
|
||||
let firstwrap: *node = newnode(nkind.N_TPARAM, pf, pl, pc);
|
||||
firstwrap.lhs = first;
|
||||
let head: *node = firstwrap;
|
||||
let tail: *node = firstwrap;
|
||||
for (true) {
|
||||
let e: *node = parsetype(p);
|
||||
tail.next = e;
|
||||
tail = e;
|
||||
let w: *node = newnode(nkind.N_TPARAM, e.file, e.line, e.col);
|
||||
w.lhs = e;
|
||||
tail.next = w;
|
||||
tail = w;
|
||||
if (!accepttok(p, tkind.TK_COMMA)) { break; };
|
||||
if (p.curkind == tkind.TK_RPAREN) { break; };
|
||||
};
|
||||
|
||||
@@ -4518,7 +4518,20 @@ type nkind = enum i32 {
|
||||
N_TENUM = 65,
|
||||
N_TENUMMEMBER = 66,
|
||||
|
||||
N_LAST = 67,
|
||||
// N_TPARAM — chain wrapper for N_TTUPLE.list elements. Mirror of
|
||||
// cstage's Tparam (cmd/wcc/check.c:1437-1451) lifted to the AST so
|
||||
// `exprtype` can return shared element-type nodes (sym.decl.lhs,
|
||||
// struct field's .lhs, another N_TTUPLE's .list element) without
|
||||
// corrupting source ASTs by reusing their .next. .lhs holds the
|
||||
// element type AST (possibly shared); .next chains within the
|
||||
// parent N_TTUPLE.list. Cstage keeps Tparam at the Type-layer; ww
|
||||
// has no separate type layer for tuple chains, so the wrapper sits
|
||||
// at the AST layer. Other node fields are unused. Never appears
|
||||
// outside an N_TTUPLE.list; astprint unwraps transparently to keep
|
||||
// the 990 -a byte-diff against cstage.
|
||||
N_TPARAM = 67,
|
||||
|
||||
N_LAST = 68,
|
||||
};
|
||||
|
||||
// ---- Node -------------------------------------------------------------
|
||||
@@ -4624,6 +4637,7 @@ fn nkname(k: nkind) str = {
|
||||
if (k == nkind.N_YIELD) { return "yield"; };
|
||||
if (k == nkind.N_TENUM) { return "tenum"; };
|
||||
if (k == nkind.N_TENUMMEMBER) { return "tenummember"; };
|
||||
if (k == nkind.N_TPARAM) { return "tparam"; };
|
||||
if (k == nkind.N_LAST) { return "last"; };
|
||||
return "?";
|
||||
};
|
||||
@@ -4682,6 +4696,14 @@ fn pr(fd: i32, n: *node, d: i32) void = {
|
||||
os.write(fd, "()\n".ptr, 3u64);
|
||||
return;
|
||||
};
|
||||
// N_TPARAM wraps an N_TTUPLE.list element so exprtype can return
|
||||
// shared element-type nodes without corrupting their .next chain.
|
||||
// Cstage has no AST-level wrapper, so unwrap here to keep the 990
|
||||
// -a byte-diff with cstage's astprint.
|
||||
if (n.kind == nkind.N_TPARAM) {
|
||||
pr(fd, n.lhs, d);
|
||||
return;
|
||||
};
|
||||
ind(fd, d);
|
||||
putc1(fd, 40u8); // '('
|
||||
let nm: str = nkname(n.kind);
|
||||
@@ -5723,13 +5745,23 @@ fn parsetype(p: *parser) *node = {
|
||||
expecttok(p, tkind.TK_RPAREN, "expected ')' after parenthesised type");
|
||||
return first;
|
||||
};
|
||||
// Wrap each element in N_TPARAM so the chain owns its .next.
|
||||
// Mirrors cstage's Tparam (cmd/wcc/check.c:1437-1451); lifted
|
||||
// to the AST layer here because wwstage has no separate type
|
||||
// layer, and exprtype must return shared element-type nodes
|
||||
// (sym.decl.lhs, struct field's .lhs, another N_TTUPLE element)
|
||||
// without corrupting source ASTs.
|
||||
let n: *node = newnode(nkind.N_TTUPLE, pf, pl, pc);
|
||||
let head: *node = first;
|
||||
let tail: *node = first;
|
||||
let firstwrap: *node = newnode(nkind.N_TPARAM, pf, pl, pc);
|
||||
firstwrap.lhs = first;
|
||||
let head: *node = firstwrap;
|
||||
let tail: *node = firstwrap;
|
||||
for (true) {
|
||||
let e: *node = parsetype(p);
|
||||
tail.next = e;
|
||||
tail = e;
|
||||
let w: *node = newnode(nkind.N_TPARAM, e.file, e.line, e.col);
|
||||
w.lhs = e;
|
||||
tail.next = w;
|
||||
tail = w;
|
||||
if (!accepttok(p, tkind.TK_COMMA)) { break; };
|
||||
if (p.curkind == tkind.TK_RPAREN) { break; };
|
||||
};
|
||||
@@ -7650,7 +7682,7 @@ fn astalign(c: *checker, t: *node) i64 = {
|
||||
let m: i64 = 1i64;
|
||||
let p: *node = t.list;
|
||||
for (p != nil) {
|
||||
let pa: i64 = astalign(c, p);
|
||||
let pa: i64 = astalign(c, p.lhs);
|
||||
if (pa > m) { m = pa; };
|
||||
p = p.next;
|
||||
};
|
||||
@@ -7705,7 +7737,7 @@ fn astsize(c: *checker, t: *node) i64 = {
|
||||
let total: i64 = 0i64;
|
||||
let p: *node = t.list;
|
||||
for (p != nil) {
|
||||
total += astsize(c, p);
|
||||
total += astsize(c, p.lhs);
|
||||
p = p.next;
|
||||
};
|
||||
return total;
|
||||
@@ -8029,7 +8061,7 @@ fn tinfofornode(c: *checker, n: *node) *tinfo = {
|
||||
let maxal: u64 = 1u64;
|
||||
let p: *node = n.list;
|
||||
for (p != nil) {
|
||||
let pt: *tinfo = tinfofornode(c, p);
|
||||
let pt: *tinfo = tinfofornode(c, p.lhs);
|
||||
if (pt != nil) {
|
||||
if (pt.align > maxal) { maxal = pt.align; };
|
||||
total += pt.size;
|
||||
@@ -8691,8 +8723,9 @@ fn exprtype(c: *checker, e: *node, hint: *node) *node = {
|
||||
idx -= 1;
|
||||
};
|
||||
if (p != nil) {
|
||||
e.type_ = tinfofornode(c, p): *void;
|
||||
return p;
|
||||
let pt: *node = p.lhs;
|
||||
e.type_ = tinfofornode(c, pt): *void;
|
||||
return pt;
|
||||
};
|
||||
};
|
||||
}; };
|
||||
@@ -11801,7 +11834,7 @@ fn slotsize(c: *cgen, typn: *node) i32 = {
|
||||
let total: i32 = 0;
|
||||
let p: *node = typn.list;
|
||||
for (p != nil) {
|
||||
total += slotsize(c, p);
|
||||
total += slotsize(c, p.lhs);
|
||||
p = p.next;
|
||||
};
|
||||
return total;
|
||||
@@ -15269,13 +15302,14 @@ fn cgdot(c: *cgen, n: *node) void = {
|
||||
for (i < idx) {
|
||||
if (tp == nil) { i = idx; }
|
||||
else {
|
||||
foff += slotsize(c, tp);
|
||||
foff += slotsize(c, tp.lhs);
|
||||
tp = tp.next;
|
||||
i += 1;
|
||||
};
|
||||
};
|
||||
if (tp != nil) {
|
||||
if (isstrtyperaw(tp)) {
|
||||
let tpt: *node = tp.lhs;
|
||||
if (isstrtyperaw(tpt)) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff((lc.off + foff + 0): i64);
|
||||
emitline("(BP), AX\n");
|
||||
@@ -15284,8 +15318,8 @@ fn cgdot(c: *cgen, n: *node) void = {
|
||||
emitline("(BP), BX\n");
|
||||
return;
|
||||
};
|
||||
let sz: i32 = slotsize(c, tp);
|
||||
let op: str = tnodeloadop(c, tp, sz);
|
||||
let sz: i32 = slotsize(c, tpt);
|
||||
let op: str = tnodeloadop(c, tpt, sz);
|
||||
emitline("\t");
|
||||
emitline(op);
|
||||
emitline("\t");
|
||||
@@ -20298,8 +20332,12 @@ fn cglet(c: *cgen, n: *node) void = {
|
||||
let p0: *node = n.lhs.list;
|
||||
let p1: *node = nil;
|
||||
if (p0 != nil) { p1 = p0.next; };
|
||||
let s0_is_str: bool = isstrtyperaw(p0);
|
||||
let s1_is_str: bool = isstrtyperaw(p1);
|
||||
let p0t: *node = nil;
|
||||
let p1t: *node = nil;
|
||||
if (p0 != nil) { p0t = p0.lhs; };
|
||||
if (p1 != nil) { p1t = p1.lhs; };
|
||||
let s0_is_str: bool = isstrtyperaw(p0t);
|
||||
let s1_is_str: bool = isstrtyperaw(p1t);
|
||||
if (p0 != nil) {
|
||||
if (p1 != nil) {
|
||||
if (s0_is_str != s1_is_str) {
|
||||
@@ -20817,8 +20855,13 @@ fn cgmlet(c: *cgen, n: *node) void = {
|
||||
let rtyp: *node = fnretlookupmod(c, cnm, cmod);
|
||||
if (rtyp != nil) {
|
||||
if (rtyp.kind == nkind.N_TTUPLE) {
|
||||
p0t = rtyp.list;
|
||||
if (p0t != nil) { p1t = p0t.next; };
|
||||
let pp: *node = rtyp.list;
|
||||
if (pp != nil) {
|
||||
p0t = pp.lhs;
|
||||
if (pp.next != nil) {
|
||||
p1t = pp.next.lhs;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -20953,7 +20996,7 @@ fn cgforrange(c: *cgen, n: *node) void = {
|
||||
let total: i32 = 0;
|
||||
let p: *node = elemt.list;
|
||||
for (p != nil) {
|
||||
total += paramfieldsize(p);
|
||||
total += paramfieldsize(p.lhs);
|
||||
p = p.next;
|
||||
};
|
||||
esz = total;
|
||||
@@ -20987,9 +21030,13 @@ fn cgforrange(c: *cgen, n: *node) void = {
|
||||
else {
|
||||
let fsz: i32 = 8;
|
||||
let signf: bool = false;
|
||||
if (tp != nil) {
|
||||
fsz = paramfieldsize(tp);
|
||||
signf = paramissigned(c, tp);
|
||||
// tp walks the N_TPARAM wrapper chain; tpt is the
|
||||
// actual element type AST.
|
||||
let tpt: *node = nil;
|
||||
if (tp != nil) { tpt = tp.lhs; };
|
||||
if (tpt != nil) {
|
||||
fsz = paramfieldsize(tpt);
|
||||
signf = paramissigned(c, tpt);
|
||||
};
|
||||
let slot_sz: i32 = fsz;
|
||||
if (slot_sz < 8) { slot_sz = 8; };
|
||||
@@ -20998,9 +21045,9 @@ fn cgforrange(c: *cgen, n: *node) void = {
|
||||
bind_signed[nbinds] = signf;
|
||||
let bnm: str = m.str;
|
||||
if (bnm.len > 0) {
|
||||
bind_off[nbinds] = localadd(c, bnm, slot_sz, tp);
|
||||
bind_off[nbinds] = localadd(c, bnm, slot_sz, tpt);
|
||||
} else {
|
||||
bind_off[nbinds] = localalloc(c, mkscratchname(c, "fr"), slot_sz, tp);
|
||||
bind_off[nbinds] = localalloc(c, mkscratchname(c, "fr"), slot_sz, tpt);
|
||||
};
|
||||
field_off += fsz;
|
||||
nbinds += 1;
|
||||
|
||||
@@ -1478,13 +1478,14 @@ fn cgdot(c: *cgen, n: *node) void = {
|
||||
for (i < idx) {
|
||||
if (tp == nil) { i = idx; }
|
||||
else {
|
||||
foff += slotsize(c, tp);
|
||||
foff += slotsize(c, tp.lhs);
|
||||
tp = tp.next;
|
||||
i += 1;
|
||||
};
|
||||
};
|
||||
if (tp != nil) {
|
||||
if (isstrtyperaw(tp)) {
|
||||
let tpt: *node = tp.lhs;
|
||||
if (isstrtyperaw(tpt)) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff((lc.off + foff + 0): i64);
|
||||
emitline("(BP), AX\n");
|
||||
@@ -1493,8 +1494,8 @@ fn cgdot(c: *cgen, n: *node) void = {
|
||||
emitline("(BP), BX\n");
|
||||
return;
|
||||
};
|
||||
let sz: i32 = slotsize(c, tp);
|
||||
let op: str = tnodeloadop(c, tp, sz);
|
||||
let sz: i32 = slotsize(c, tpt);
|
||||
let op: str = tnodeloadop(c, tpt, sz);
|
||||
emitline("\t");
|
||||
emitline(op);
|
||||
emitline("\t");
|
||||
|
||||
@@ -708,8 +708,12 @@ fn cglet(c: *cgen, n: *node) void = {
|
||||
let p0: *node = n.lhs.list;
|
||||
let p1: *node = nil;
|
||||
if (p0 != nil) { p1 = p0.next; };
|
||||
let s0_is_str: bool = isstrtyperaw(p0);
|
||||
let s1_is_str: bool = isstrtyperaw(p1);
|
||||
let p0t: *node = nil;
|
||||
let p1t: *node = nil;
|
||||
if (p0 != nil) { p0t = p0.lhs; };
|
||||
if (p1 != nil) { p1t = p1.lhs; };
|
||||
let s0_is_str: bool = isstrtyperaw(p0t);
|
||||
let s1_is_str: bool = isstrtyperaw(p1t);
|
||||
if (p0 != nil) {
|
||||
if (p1 != nil) {
|
||||
if (s0_is_str != s1_is_str) {
|
||||
@@ -1227,8 +1231,13 @@ fn cgmlet(c: *cgen, n: *node) void = {
|
||||
let rtyp: *node = fnretlookupmod(c, cnm, cmod);
|
||||
if (rtyp != nil) {
|
||||
if (rtyp.kind == nkind.N_TTUPLE) {
|
||||
p0t = rtyp.list;
|
||||
if (p0t != nil) { p1t = p0t.next; };
|
||||
let pp: *node = rtyp.list;
|
||||
if (pp != nil) {
|
||||
p0t = pp.lhs;
|
||||
if (pp.next != nil) {
|
||||
p1t = pp.next.lhs;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -1363,7 +1372,7 @@ fn cgforrange(c: *cgen, n: *node) void = {
|
||||
let total: i32 = 0;
|
||||
let p: *node = elemt.list;
|
||||
for (p != nil) {
|
||||
total += paramfieldsize(p);
|
||||
total += paramfieldsize(p.lhs);
|
||||
p = p.next;
|
||||
};
|
||||
esz = total;
|
||||
@@ -1397,9 +1406,13 @@ fn cgforrange(c: *cgen, n: *node) void = {
|
||||
else {
|
||||
let fsz: i32 = 8;
|
||||
let signf: bool = false;
|
||||
if (tp != nil) {
|
||||
fsz = paramfieldsize(tp);
|
||||
signf = paramissigned(c, tp);
|
||||
// tp walks the N_TPARAM wrapper chain; tpt is the
|
||||
// actual element type AST.
|
||||
let tpt: *node = nil;
|
||||
if (tp != nil) { tpt = tp.lhs; };
|
||||
if (tpt != nil) {
|
||||
fsz = paramfieldsize(tpt);
|
||||
signf = paramissigned(c, tpt);
|
||||
};
|
||||
let slot_sz: i32 = fsz;
|
||||
if (slot_sz < 8) { slot_sz = 8; };
|
||||
@@ -1408,9 +1421,9 @@ fn cgforrange(c: *cgen, n: *node) void = {
|
||||
bind_signed[nbinds] = signf;
|
||||
let bnm: str = m.str;
|
||||
if (bnm.len > 0) {
|
||||
bind_off[nbinds] = localadd(c, bnm, slot_sz, tp);
|
||||
bind_off[nbinds] = localadd(c, bnm, slot_sz, tpt);
|
||||
} else {
|
||||
bind_off[nbinds] = localalloc(c, mkscratchname(c, "fr"), slot_sz, tp);
|
||||
bind_off[nbinds] = localalloc(c, mkscratchname(c, "fr"), slot_sz, tpt);
|
||||
};
|
||||
field_off += fsz;
|
||||
nbinds += 1;
|
||||
|
||||
@@ -2007,7 +2007,7 @@ fn slotsize(c: *cgen, typn: *node) i32 = {
|
||||
let total: i32 = 0;
|
||||
let p: *node = typn.list;
|
||||
for (p != nil) {
|
||||
total += slotsize(c, p);
|
||||
total += slotsize(c, p.lhs);
|
||||
p = p.next;
|
||||
};
|
||||
return total;
|
||||
|
||||
@@ -718,7 +718,7 @@ fn astalign(c: *checker, t: *node) i64 = {
|
||||
let m: i64 = 1i64;
|
||||
let p: *node = t.list;
|
||||
for (p != nil) {
|
||||
let pa: i64 = astalign(c, p);
|
||||
let pa: i64 = astalign(c, p.lhs);
|
||||
if (pa > m) { m = pa; };
|
||||
p = p.next;
|
||||
};
|
||||
@@ -773,7 +773,7 @@ fn astsize(c: *checker, t: *node) i64 = {
|
||||
let total: i64 = 0i64;
|
||||
let p: *node = t.list;
|
||||
for (p != nil) {
|
||||
total += astsize(c, p);
|
||||
total += astsize(c, p.lhs);
|
||||
p = p.next;
|
||||
};
|
||||
return total;
|
||||
@@ -1097,7 +1097,7 @@ fn tinfofornode(c: *checker, n: *node) *tinfo = {
|
||||
let maxal: u64 = 1u64;
|
||||
let p: *node = n.list;
|
||||
for (p != nil) {
|
||||
let pt: *tinfo = tinfofornode(c, p);
|
||||
let pt: *tinfo = tinfofornode(c, p.lhs);
|
||||
if (pt != nil) {
|
||||
if (pt.align > maxal) { maxal = pt.align; };
|
||||
total += pt.size;
|
||||
@@ -1759,8 +1759,9 @@ fn exprtype(c: *checker, e: *node, hint: *node) *node = {
|
||||
idx -= 1;
|
||||
};
|
||||
if (p != nil) {
|
||||
e.type_ = tinfofornode(c, p): *void;
|
||||
return p;
|
||||
let pt: *node = p.lhs;
|
||||
e.type_ = tinfofornode(c, pt): *void;
|
||||
return pt;
|
||||
};
|
||||
};
|
||||
}; };
|
||||
|
||||
@@ -4518,7 +4518,20 @@ type nkind = enum i32 {
|
||||
N_TENUM = 65,
|
||||
N_TENUMMEMBER = 66,
|
||||
|
||||
N_LAST = 67,
|
||||
// N_TPARAM — chain wrapper for N_TTUPLE.list elements. Mirror of
|
||||
// cstage's Tparam (cmd/wcc/check.c:1437-1451) lifted to the AST so
|
||||
// `exprtype` can return shared element-type nodes (sym.decl.lhs,
|
||||
// struct field's .lhs, another N_TTUPLE's .list element) without
|
||||
// corrupting source ASTs by reusing their .next. .lhs holds the
|
||||
// element type AST (possibly shared); .next chains within the
|
||||
// parent N_TTUPLE.list. Cstage keeps Tparam at the Type-layer; ww
|
||||
// has no separate type layer for tuple chains, so the wrapper sits
|
||||
// at the AST layer. Other node fields are unused. Never appears
|
||||
// outside an N_TTUPLE.list; astprint unwraps transparently to keep
|
||||
// the 990 -a byte-diff against cstage.
|
||||
N_TPARAM = 67,
|
||||
|
||||
N_LAST = 68,
|
||||
};
|
||||
|
||||
// ---- Node -------------------------------------------------------------
|
||||
@@ -4624,6 +4637,7 @@ fn nkname(k: nkind) str = {
|
||||
if (k == nkind.N_YIELD) { return "yield"; };
|
||||
if (k == nkind.N_TENUM) { return "tenum"; };
|
||||
if (k == nkind.N_TENUMMEMBER) { return "tenummember"; };
|
||||
if (k == nkind.N_TPARAM) { return "tparam"; };
|
||||
if (k == nkind.N_LAST) { return "last"; };
|
||||
return "?";
|
||||
};
|
||||
@@ -4682,6 +4696,14 @@ fn pr(fd: i32, n: *node, d: i32) void = {
|
||||
os.write(fd, "()\n".ptr, 3u64);
|
||||
return;
|
||||
};
|
||||
// N_TPARAM wraps an N_TTUPLE.list element so exprtype can return
|
||||
// shared element-type nodes without corrupting their .next chain.
|
||||
// Cstage has no AST-level wrapper, so unwrap here to keep the 990
|
||||
// -a byte-diff with cstage's astprint.
|
||||
if (n.kind == nkind.N_TPARAM) {
|
||||
pr(fd, n.lhs, d);
|
||||
return;
|
||||
};
|
||||
ind(fd, d);
|
||||
putc1(fd, 40u8); // '('
|
||||
let nm: str = nkname(n.kind);
|
||||
@@ -5723,13 +5745,23 @@ fn parsetype(p: *parser) *node = {
|
||||
expecttok(p, tkind.TK_RPAREN, "expected ')' after parenthesised type");
|
||||
return first;
|
||||
};
|
||||
// Wrap each element in N_TPARAM so the chain owns its .next.
|
||||
// Mirrors cstage's Tparam (cmd/wcc/check.c:1437-1451); lifted
|
||||
// to the AST layer here because wwstage has no separate type
|
||||
// layer, and exprtype must return shared element-type nodes
|
||||
// (sym.decl.lhs, struct field's .lhs, another N_TTUPLE element)
|
||||
// without corrupting source ASTs.
|
||||
let n: *node = newnode(nkind.N_TTUPLE, pf, pl, pc);
|
||||
let head: *node = first;
|
||||
let tail: *node = first;
|
||||
let firstwrap: *node = newnode(nkind.N_TPARAM, pf, pl, pc);
|
||||
firstwrap.lhs = first;
|
||||
let head: *node = firstwrap;
|
||||
let tail: *node = firstwrap;
|
||||
for (true) {
|
||||
let e: *node = parsetype(p);
|
||||
tail.next = e;
|
||||
tail = e;
|
||||
let w: *node = newnode(nkind.N_TPARAM, e.file, e.line, e.col);
|
||||
w.lhs = e;
|
||||
tail.next = w;
|
||||
tail = w;
|
||||
if (!accepttok(p, tkind.TK_COMMA)) { break; };
|
||||
if (p.curkind == tkind.TK_RPAREN) { break; };
|
||||
};
|
||||
@@ -7650,7 +7682,7 @@ fn astalign(c: *checker, t: *node) i64 = {
|
||||
let m: i64 = 1i64;
|
||||
let p: *node = t.list;
|
||||
for (p != nil) {
|
||||
let pa: i64 = astalign(c, p);
|
||||
let pa: i64 = astalign(c, p.lhs);
|
||||
if (pa > m) { m = pa; };
|
||||
p = p.next;
|
||||
};
|
||||
@@ -7705,7 +7737,7 @@ fn astsize(c: *checker, t: *node) i64 = {
|
||||
let total: i64 = 0i64;
|
||||
let p: *node = t.list;
|
||||
for (p != nil) {
|
||||
total += astsize(c, p);
|
||||
total += astsize(c, p.lhs);
|
||||
p = p.next;
|
||||
};
|
||||
return total;
|
||||
@@ -8029,7 +8061,7 @@ fn tinfofornode(c: *checker, n: *node) *tinfo = {
|
||||
let maxal: u64 = 1u64;
|
||||
let p: *node = n.list;
|
||||
for (p != nil) {
|
||||
let pt: *tinfo = tinfofornode(c, p);
|
||||
let pt: *tinfo = tinfofornode(c, p.lhs);
|
||||
if (pt != nil) {
|
||||
if (pt.align > maxal) { maxal = pt.align; };
|
||||
total += pt.size;
|
||||
@@ -8691,8 +8723,9 @@ fn exprtype(c: *checker, e: *node, hint: *node) *node = {
|
||||
idx -= 1;
|
||||
};
|
||||
if (p != nil) {
|
||||
e.type_ = tinfofornode(c, p): *void;
|
||||
return p;
|
||||
let pt: *node = p.lhs;
|
||||
e.type_ = tinfofornode(c, pt): *void;
|
||||
return pt;
|
||||
};
|
||||
};
|
||||
}; };
|
||||
@@ -11801,7 +11834,7 @@ fn slotsize(c: *cgen, typn: *node) i32 = {
|
||||
let total: i32 = 0;
|
||||
let p: *node = typn.list;
|
||||
for (p != nil) {
|
||||
total += slotsize(c, p);
|
||||
total += slotsize(c, p.lhs);
|
||||
p = p.next;
|
||||
};
|
||||
return total;
|
||||
@@ -15269,13 +15302,14 @@ fn cgdot(c: *cgen, n: *node) void = {
|
||||
for (i < idx) {
|
||||
if (tp == nil) { i = idx; }
|
||||
else {
|
||||
foff += slotsize(c, tp);
|
||||
foff += slotsize(c, tp.lhs);
|
||||
tp = tp.next;
|
||||
i += 1;
|
||||
};
|
||||
};
|
||||
if (tp != nil) {
|
||||
if (isstrtyperaw(tp)) {
|
||||
let tpt: *node = tp.lhs;
|
||||
if (isstrtyperaw(tpt)) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff((lc.off + foff + 0): i64);
|
||||
emitline("(BP), AX\n");
|
||||
@@ -15284,8 +15318,8 @@ fn cgdot(c: *cgen, n: *node) void = {
|
||||
emitline("(BP), BX\n");
|
||||
return;
|
||||
};
|
||||
let sz: i32 = slotsize(c, tp);
|
||||
let op: str = tnodeloadop(c, tp, sz);
|
||||
let sz: i32 = slotsize(c, tpt);
|
||||
let op: str = tnodeloadop(c, tpt, sz);
|
||||
emitline("\t");
|
||||
emitline(op);
|
||||
emitline("\t");
|
||||
@@ -20298,8 +20332,12 @@ fn cglet(c: *cgen, n: *node) void = {
|
||||
let p0: *node = n.lhs.list;
|
||||
let p1: *node = nil;
|
||||
if (p0 != nil) { p1 = p0.next; };
|
||||
let s0_is_str: bool = isstrtyperaw(p0);
|
||||
let s1_is_str: bool = isstrtyperaw(p1);
|
||||
let p0t: *node = nil;
|
||||
let p1t: *node = nil;
|
||||
if (p0 != nil) { p0t = p0.lhs; };
|
||||
if (p1 != nil) { p1t = p1.lhs; };
|
||||
let s0_is_str: bool = isstrtyperaw(p0t);
|
||||
let s1_is_str: bool = isstrtyperaw(p1t);
|
||||
if (p0 != nil) {
|
||||
if (p1 != nil) {
|
||||
if (s0_is_str != s1_is_str) {
|
||||
@@ -20817,8 +20855,13 @@ fn cgmlet(c: *cgen, n: *node) void = {
|
||||
let rtyp: *node = fnretlookupmod(c, cnm, cmod);
|
||||
if (rtyp != nil) {
|
||||
if (rtyp.kind == nkind.N_TTUPLE) {
|
||||
p0t = rtyp.list;
|
||||
if (p0t != nil) { p1t = p0t.next; };
|
||||
let pp: *node = rtyp.list;
|
||||
if (pp != nil) {
|
||||
p0t = pp.lhs;
|
||||
if (pp.next != nil) {
|
||||
p1t = pp.next.lhs;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -20953,7 +20996,7 @@ fn cgforrange(c: *cgen, n: *node) void = {
|
||||
let total: i32 = 0;
|
||||
let p: *node = elemt.list;
|
||||
for (p != nil) {
|
||||
total += paramfieldsize(p);
|
||||
total += paramfieldsize(p.lhs);
|
||||
p = p.next;
|
||||
};
|
||||
esz = total;
|
||||
@@ -20987,9 +21030,13 @@ fn cgforrange(c: *cgen, n: *node) void = {
|
||||
else {
|
||||
let fsz: i32 = 8;
|
||||
let signf: bool = false;
|
||||
if (tp != nil) {
|
||||
fsz = paramfieldsize(tp);
|
||||
signf = paramissigned(c, tp);
|
||||
// tp walks the N_TPARAM wrapper chain; tpt is the
|
||||
// actual element type AST.
|
||||
let tpt: *node = nil;
|
||||
if (tp != nil) { tpt = tp.lhs; };
|
||||
if (tpt != nil) {
|
||||
fsz = paramfieldsize(tpt);
|
||||
signf = paramissigned(c, tpt);
|
||||
};
|
||||
let slot_sz: i32 = fsz;
|
||||
if (slot_sz < 8) { slot_sz = 8; };
|
||||
@@ -20998,9 +21045,9 @@ fn cgforrange(c: *cgen, n: *node) void = {
|
||||
bind_signed[nbinds] = signf;
|
||||
let bnm: str = m.str;
|
||||
if (bnm.len > 0) {
|
||||
bind_off[nbinds] = localadd(c, bnm, slot_sz, tp);
|
||||
bind_off[nbinds] = localadd(c, bnm, slot_sz, tpt);
|
||||
} else {
|
||||
bind_off[nbinds] = localalloc(c, mkscratchname(c, "fr"), slot_sz, tp);
|
||||
bind_off[nbinds] = localalloc(c, mkscratchname(c, "fr"), slot_sz, tpt);
|
||||
};
|
||||
field_off += fsz;
|
||||
nbinds += 1;
|
||||
|
||||
Reference in New Issue
Block a user