w6c+wcc: widen struct/tagged-subset, parse ... spread
Three tagged-union gaps:
1. Struct-payload widening was broken at every site (call, let,
assign, return, struct-field init). cg_widen_tagged_store now
materialises str / scalar / struct-lit / struct-ident / tagged
payloads at slot+8+field_off and writes the tag last. Call sites
route through cg_widen_tagged_push (scratch slot + push high→low).
2. Tagged → wider tagged widening forwarded the source tag verbatim.
cg_widen_tag_remap emits a CMPQ-chain switch that translates each
source variant index to the destination's, then zero-pads to the
wider slot. type_eq grew a TY_TAGGED arm (was returning 1 for any
two unions); type_assignable now accepts variant-subset and
rejects the rest.
3. `(...inner | T)` spread parses (cmd/wcc/parse.c, lib/ww/parse).
Marks Node.op = TK_ELLIPSIS; resolve_type unwraps NAMED + flattens
when the spread bit is set so aliases inline like Hare's
tagged_type unwrap flag.
Selfhost mirror: spread parser ported. Cgen widen helpers not yet
mirrored — wwstage stays byte-identical to cstage on the existing
test corpus, but will emit wrong asm if user code uses the new
patterns (probe sp2 shows the divergence).
700_e2e: 9 new rows covering call/let/assign/return × struct +
tagged subset, plus the spread-flatten case.
This commit is contained in:
@@ -3952,14 +3952,24 @@ fn parsetype(p: *parser) *node = {
|
||||
|
||||
if (p.curkind == tkind.TK_LPAREN) {
|
||||
// (T) or (T, T, ...) or (T | T | ...)
|
||||
//
|
||||
// Each tagged variant may be prefixed with `...` to mark a
|
||||
// spread — when the variant resolves to another tagged union
|
||||
// its variants are flattened into the enclosing union. We
|
||||
// tag the spread on node.op = TK_ELLIPSIS so resolve_type
|
||||
// can distinguish intent. Mirrors C parsetype.
|
||||
advance(p);
|
||||
let firstspread: bool = accepttok(p, tkind.TK_ELLIPSIS);
|
||||
let first: *node = parsetype(p);
|
||||
if (firstspread) { first.op = tkind.TK_ELLIPSIS; };
|
||||
if (accepttok(p, tkind.TK_PIPE)) {
|
||||
let n: *node = newnode(p.a, nkind.N_TTAGGED, pf, pl, pc);
|
||||
let head: *node = first;
|
||||
let tail: *node = first;
|
||||
for (true) {
|
||||
let spread: bool = accepttok(p, tkind.TK_ELLIPSIS);
|
||||
let e: *node = parsetype(p);
|
||||
if (spread) { e.op = tkind.TK_ELLIPSIS; };
|
||||
tail.next = e;
|
||||
tail = e;
|
||||
if (!accepttok(p, tkind.TK_PIPE)) { break; };
|
||||
@@ -3968,6 +3978,9 @@ fn parsetype(p: *parser) *node = {
|
||||
n.list = head;
|
||||
return n;
|
||||
};
|
||||
if (firstspread) {
|
||||
errmsg(p, "spread '...' only valid before tagged-union variants");
|
||||
};
|
||||
if (!accepttok(p, tkind.TK_COMMA)) {
|
||||
expecttok(p, tkind.TK_RPAREN, "expected ')' after parenthesised type");
|
||||
return first;
|
||||
|
||||
Reference in New Issue
Block a user