selfhost+test: route N_DOT base through indexvaluetnode + scanlocals for N_INDEX-lhs cgassign chain (#28+#30)
Wwstage's N_INDEX-lhs cgassign dispatch chain had a triple-site N_DOT base gap (sister latents filed during #24 / #27 review): Read (#28): `obj.mat[i][k]` over a struct field mat: **u8. cgindex routes the outer N_INDEX's N_INDEX base through indexvaluetnode; the recursion bottomed out at the inner N_INDEX's N_DOT base with bt=nil. esz fell through to 8 + signed_elem to false — wwstage emitted a stray outer `MOVQ $8, CX; IMULQ CX, AX` plus `MOVQ (AX), AX` (8-byte read over a 1-byte u8) instead of cstage's bare `MOVZBQ (AX), AX`. Write (#30): `obj.arr[i] = v` over a struct field arr: [N]Tagged (e.g. (i64|str)). cgassign's N_DOT-base arm computed esz via indexbaseesz but never set elemtn, so the tagged-element store gate missed and the 24-byte tagged slot was overwritten by a single scalar MOVQ — wrong-width store + tag/payload junk in the upper 16 bytes. Cstage walks `n->lhs->type` directly via the typed AST (cmd/w6c/cgen.c idx_eff + the N_INDEX-lhs N_ASSIGN branch). Wwstage now mirrors via indexvaluetnode, which #24 (aa8ca47) introduced for the N_INDEX-base case; #28/#30 graduate it for N_DOT base via the existing dotfieldtnode helper. Bundle graduates N_DOT base for the entire N_INDEX-lhs cgassign chain: (a) indexvaluetnode in cgenutil.ww handles N_DOT base via dotfieldtnode; (b) cgassign N_DOT-base arm in cgenexpr.ww calls indexvaluetnode for elemtn; (c) scanlocals N_DOT-base arm in cgendecl.ww parallels the existing N_IDENT arm for tagscr-bump. Splits are bisect-incoherent: (b)-alone clobbers locals via under-sized frame, (a)-alone leaves the write path with wrong elemtn, (c)-alone has no consumer. Only the triple delivers a complete N_DOT-base graduation matching #24's N_INDEX-base pattern. Cstage's first-use+fail-loud strategy for @tagscr (#26 commit069548d) handles the N_DOT-base shape naturally; the scanlocals N_DOT arm is wwstage-specific. Long-term rule-10 convergence (wwstage DOWN from scanlocals to first-use+fail-loud on BOTH stages) is filed as task #15. Class A wwstage cgen UNDER. No in-tree consumer; sister latents filed during #24 + #27 reviews. Test 741_dotbase_chained pins the dispatch + cstage-byte-identical asm for both rows. Sister latent (filed): indexbaseesz has no N_TARRAY arm for scalar struct-field array writes — `s.arr: [N]i32` scalar write falls through to esz=8 on wwstage. No in-tree exerciser; tight scope kept here. 115/115 ok. ww2 == ww3 == ww4 byte-id.
This commit is contained in:
@@ -3518,6 +3518,16 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
};
|
||||
} else { if (base.kind == nkind.N_DOT) {
|
||||
esz = indexbaseesz(c, base);
|
||||
// Without this, the tagged-element gate
|
||||
// below (keyed on elemtn) misses for
|
||||
// `obj.arr[i] = v` over an [N]Tagged field
|
||||
// and the store falls through to scalar —
|
||||
// task #30, sister of the cgindex N_INDEX-
|
||||
// base fix #24. indexvaluetnode now handles
|
||||
// N_DOT base, so the element type drops out
|
||||
// of the same helper.
|
||||
let bt: *node = indexvaluetnode(c, lhs);
|
||||
if (bt != nil) { elemtn = bt; };
|
||||
} else { if (base.kind == nkind.N_INDEX) {
|
||||
// Chained-write write-side parallel of the
|
||||
// cgindex N_INDEX-base arm graduated in #24:
|
||||
|
||||
Reference in New Issue
Block a user