19fb3a3b3ccc14eaaec594e2e9a9d2ab2de2483a
Typed-int literal assigned into a tagged-union slot (`h.e = 42i64;` where
e: (i32 | i64)) wrote tag = 0 (the i32 slot) instead of tag = 1 (the i64
slot). Cstage was correct: parse.c parseprimary copies tok.tsuffix onto
N_INTLIT, check.c stamps node.type = ty_i64, and cg_widen_tagged_store →
cg_tag_for_variant walks variants matching by structural type_eq —
ty_i64 lands at index 1. Wwstage had two gaps:
1. The parser (lib/ww/parse/expr.ww parseprimary) read p.curuval and
p.curtext from the current token but never the tsuffix field. Token-
side capture has been in place since the lexer's `i8/i16/.../u64/f32/
f64` glue suffix landed (lib/ww/lex/lex.ww sets out.tsuffix); the
parser side was missed. So an N_INTLIT for `42i64` carried tsuffix=""
into cgen. Mirror of cmd/wcc/parse.c parseprimary's `n->tsuffix =
t.tsuffix` line. Same plumb for N_FLOATLIT.
2. Wwstage has no checker stage to stamp N_UN's type from its inner
expression's type. `-42i64` parses as N_UN(MINUS, N_INTLIT(42,
tsuffix="i64")) and rhstargetname stopped at N_UN, returning "" and
falling through to taggedvariantindex's "first non-str variant"
fallback — which picked tag 0 (i32) for any numeric rhs in an
(i32|i64) union. Cstage's cunop returns the inner type for
TK_MINUS / TK_PLUS / TK_TILDE so the N_UN gets ty_i64 stamped
naturally; wwstage gets the equivalent via an explicit peel in
rhstargetname, recursing into rhs.lhs for these three ops. The
recursion also covers nested unary (`- -42i64`), which parseunary
builds as N_UN over N_UN over N_INTLIT.
The lib/ww/parse change is mirrored in selfhost/cmd/{w6c,wwdump}/
main.combined.ww so the bootstrap snapshot stays consistent with the
working frontend source. parser.curtsuffix is a new str field; refill
copies t.tsuffix into it; parseprimary TK_INT / TK_FLOAT copy it onto
the new node before advance.
Cstage handled both `42i64` and `-42i64` correctly already; no cstage
mirror needed.
Test 694_tagged_store_intlit — eleven rows running on both stages: i64
lit in (i32|i64); i32 lit (existing-working pin); i64 lit in
(i32|i64|str) with the str fallback at tail; u8 lit at head of
(u8|i32|i64); i64 lit at tail of (u8|i32|i64) with a +100 marker so
mis-binding into u8 can't masquerade as success; negative-i64 lit
(N_UN MINUS peel + sign extension through match-arm bind);
unary-plus i64 lit (N_UN PLUS peel); bitwise-not i64 lit (N_UN TILDE
peel; `~0i64 == -1i64`); nested unary `- -42i64` (recursion through
two N_UN levels); direct `let x: ev = 42i64;` (cglet's tagged-init
code path, separate write site from cgassign's field-write);
negative-control str field (pins the existing str-fallback path
through rhstargetname).
Pre-fix run on wwstage: 8/11 rows fail (every typed-i64 case including
all three unary operators, nested unary, and the direct let-init);
cstage 11/11 pass. Post-fix: 22/22 across both stages. make test
41/41. Bootstrap ww2 == ww3 == ww4 byte-identical.
Description
No description provided
Languages
C
89.4%
Python
7.2%
Makefile
2.3%
Shell
0.8%
Assembly
0.3%