diff --git a/lib/ww/ast.ww b/lib/ww/ast.ww index a09956fc..163b7b36 100644 --- a/lib/ww/ast.ww +++ b/lib/ww/ast.ww @@ -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); diff --git a/lib/ww/parse/parse.ww b/lib/ww/parse/parse.ww index 11891ae2..8b038511 100644 --- a/lib/ww/parse/parse.ww +++ b/lib/ww/parse/parse.ww @@ -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; }; }; diff --git a/selfhost/cmd/w6c/main.combined.ww b/selfhost/cmd/w6c/main.combined.ww index c095d49c..11029e1e 100644 --- a/selfhost/cmd/w6c/main.combined.ww +++ b/selfhost/cmd/w6c/main.combined.ww @@ -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; diff --git a/selfhost/cmd/wcc/cgenexpr.ww b/selfhost/cmd/wcc/cgenexpr.ww index 5457c1e4..723a1044 100644 --- a/selfhost/cmd/wcc/cgenexpr.ww +++ b/selfhost/cmd/wcc/cgenexpr.ww @@ -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"); diff --git a/selfhost/cmd/wcc/cgenstmt.ww b/selfhost/cmd/wcc/cgenstmt.ww index 1faa30ee..6a6600de 100644 --- a/selfhost/cmd/wcc/cgenstmt.ww +++ b/selfhost/cmd/wcc/cgenstmt.ww @@ -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; diff --git a/selfhost/cmd/wcc/cgenutil.ww b/selfhost/cmd/wcc/cgenutil.ww index e4041263..48e6e005 100644 --- a/selfhost/cmd/wcc/cgenutil.ww +++ b/selfhost/cmd/wcc/cgenutil.ww @@ -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; diff --git a/selfhost/cmd/wcc/check.ww b/selfhost/cmd/wcc/check.ww index fbf2abfd..714f4f20 100644 --- a/selfhost/cmd/wcc/check.ww +++ b/selfhost/cmd/wcc/check.ww @@ -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; }; }; }; }; diff --git a/selfhost/cmd/wwdump/main.combined.ww b/selfhost/cmd/wwdump/main.combined.ww index 5f1b0d56..3ff4de33 100644 --- a/selfhost/cmd/wwdump/main.combined.ww +++ b/selfhost/cmd/wwdump/main.combined.ww @@ -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;