wcc/ww: str-to-slice cap synth keys on the source type

Casting a global str to []u8 dropped the cap=len synth (the trailing
MOVQ BX,CX) — the synth was gated on a local-ident source shape.
Key it on the source type so local/global/field/call sources all get
the header. Review item #19.
This commit is contained in:
2026-06-12 21:00:59 +09:00
parent c405e777d3
commit 850746cfa8
5 changed files with 249 additions and 36 deletions

View File

@@ -24161,19 +24161,13 @@ fn cgcast(c: *cgen, n: *node) void = {
// str → []T: cgexpr left (AX=ptr, BX=len). Slice register
// convention is (AX=ptr, BX=len, CX=cap); synthesise cap = len
// so downstream arg-push / let-init paths see the canonical
// triple. Detect via dst-is-slice + src-ident's local-tnode
// being str (the common shape; non-ident sources rare).
// triple. Type-keyed on the stamped src/dst types (dst-is-slice +
// src-is-str), mirroring cstage cgen.c N_CAST (type_chase_named →
// TY_SLICE/TY_STR). The prior local-ident-source gate (#19) missed
// every non-local str source — global ident, struct field, call
// result — leaving CX = the str's stale word-16 garbage cap.
if (isslicetype(c, n.rhs)) {
let srcstr: bool = false;
if (n.lhs != nil) {
if (n.lhs.kind == nkind.N_IDENT) {
let lc: *local = localfindnode(c, n.lhs.str);
if (lc != nil) {
if (isstrtype(c, lc.tnode)) { srcstr = true; };
};
};
};
if (srcstr) { emitline("\tMOVQ\tBX, CX\n"); };
if (isstrtype(c, n.lhs)) { emitline("\tMOVQ\tBX, CX\n"); };
};
// 0=int, 1=f32, 2=f64. CVT picks one direction per combo;
// int↔int casts narrow via an explicit clamp before the early