wcc+w6c_ww: aggregate-field stores via cgplaceaddr (C1.25)
Wire struct/array/tuple field STORE through the C1 assign-resolver (task #23): structlit rhs materialises into a FRESH-per-use @placescr slot (the @slicescr discipline — a cached slot is the #31 multi-live trap) then word-copies to the resolved address; addressable rhs (ident/global/dot/deref) sources via aggarg_srcaddr with the dest spilled around the dispatch (#270-1b order). Kept loud: compound on aggregate, sret call rhs (#234-tail), <=24B call rhs (task #24), unaddressable literal rhs, ww-only anonymous-struct structinfo miss. test/wcc/805: +6 rows (40B structlit incl ... autofill, ident+deref source, nested literal, [3]u8 MOVW/MOVB and [3]u32 MOVL tails, two same-size stores in one fn pinning fresh-per-use) +3 exact-text reject rows. Tuple-field row blocked by the pre-existing tuple param/let-init word-2 drops (tasks #32/#33, documented in-row). p7b_capstore_only graduates byte-id and runs; p7_composed builds and runs on cstage, wwstage stays behind the pre-existing #29 asserttyped bail (verified identical at master with w6c_ww).
This commit is contained in:
108
cmd/w6c/cgen.c
108
cmd/w6c/cgen.c
@@ -6074,11 +6074,113 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
if (fu && fu->kind == TY_TAGGED)
|
||||
fatal("assign-resolver: tagged field not "
|
||||
"wired (rule-7)");
|
||||
/* C1.25 (#23): aggregate field STORE through the
|
||||
* resolver — run_thread's 40B capture store
|
||||
* `(*ts)[i].root_capture = capture{...}`. Dest address
|
||||
* from cgplaceaddr (BX), source address in SI per rhs
|
||||
* shape, then the #270-1b word-copy tail (SI)→(BX).
|
||||
* Pre-C1 this was a SILENT no-op; C1 made it loud;
|
||||
* this wires it (loud-first, wire-next). Compound on
|
||||
* an aggregate is meaningless and stays loud. */
|
||||
if (fu && (fu->kind == TY_STRUCT
|
||||
|| fu->kind == TY_ARRAY
|
||||
|| fu->kind == TY_TUPLE))
|
||||
fatal("assign-resolver: aggregate field not "
|
||||
"wired (rule-7)");
|
||||
|| fu->kind == TY_TUPLE)) {
|
||||
if (n->op != TK_ASSIGN)
|
||||
fatal("assign-resolver: compound on "
|
||||
"aggregate field not wired "
|
||||
"(rule-7)");
|
||||
if (n->rhs && n->rhs->kind == N_CALL) {
|
||||
/* sret-class needs a runtime-RDI dest
|
||||
* (the #234-tail deferral); the ≤24B
|
||||
* reg-return receive is task #24. */
|
||||
if (cg_sret_retsize(ft) > 0)
|
||||
fatal("assign-resolver: sret "
|
||||
"call into aggregate field "
|
||||
"unwired (#234-tail/"
|
||||
"rule-7)");
|
||||
fatal("assign-resolver: call result "
|
||||
"into aggregate field unwired "
|
||||
"(task #24/rule-7)");
|
||||
}
|
||||
int placed = 0;
|
||||
if (n->rhs && n->rhs->kind == N_STRUCTLIT
|
||||
&& fu->kind == TY_STRUCT) {
|
||||
/* @placescr — FRESH slot PER USE (the
|
||||
* @slicescr discipline, NOT the cached
|
||||
* @tagscr table: a cached slot is the
|
||||
* #31 multi-live corruption trap; rob
|
||||
* ruling). Funnel contract, #44
|
||||
* discipline: this arm is the ONLY
|
||||
* @placescr alloc site. Fill handles
|
||||
* nested literals (#18), tagged
|
||||
* fields, TK_ELLIPSIS autofill; the
|
||||
* value sits in memory, so the
|
||||
* resolver below may clobber AX/CX
|
||||
* freely. */
|
||||
int scr = local_alloc(c, &locals,
|
||||
"@placescr", fsz, cg_frame);
|
||||
cg_structlit_fill_bp(c, &locals, fu,
|
||||
n->rhs, scr);
|
||||
placed = cgplaceaddr(c, n->lhs, D_BX,
|
||||
locals);
|
||||
if (placed)
|
||||
ins2(c, A_LEAQ,
|
||||
amem(D_BP, scr),
|
||||
areg(D_SI));
|
||||
} else {
|
||||
/* Addressable source — ident / global
|
||||
* / N_DOT chain / deref — via the
|
||||
* closed #265/#268 dispatch. Its
|
||||
* N_INDEX arm clobbers BX, so the dest
|
||||
* spills around it (the #270-1b
|
||||
* order). Literal arrays/tuples have
|
||||
* no storage address and stay loud. */
|
||||
placed = cgplaceaddr(c, n->lhs, D_BX,
|
||||
locals);
|
||||
if (placed) {
|
||||
ins1(c, A_PUSHQ, areg(D_BX));
|
||||
if (!aggarg_srcaddr(c, n->rhs,
|
||||
D_SI, locals))
|
||||
fatal("assign-resolver"
|
||||
": aggregate rhs "
|
||||
"shape unwired "
|
||||
"(rule-7)");
|
||||
ins1(c, A_POPQ, areg(D_BX));
|
||||
}
|
||||
}
|
||||
if (!placed)
|
||||
fatal("unsupported assign target "
|
||||
"shape");
|
||||
int k = 0;
|
||||
for (; k + 8 <= fsz; k += 8) {
|
||||
ins2(c, A_MOVQ, amem(D_SI, k),
|
||||
areg(D_AX));
|
||||
ins2(c, A_MOVQ, areg(D_AX),
|
||||
amem(D_BX, k));
|
||||
}
|
||||
if (k + 4 <= fsz) {
|
||||
ins2(c, A_MOVL, amem(D_SI, k),
|
||||
areg(D_AX));
|
||||
ins2(c, A_MOVL, areg(D_AX),
|
||||
amem(D_BX, k));
|
||||
k += 4;
|
||||
}
|
||||
if (k + 2 <= fsz) {
|
||||
ins2(c, A_MOVW, amem(D_SI, k),
|
||||
areg(D_AX));
|
||||
ins2(c, A_MOVW, areg(D_AX),
|
||||
amem(D_BX, k));
|
||||
k += 2;
|
||||
}
|
||||
if (k + 1 <= fsz) {
|
||||
ins2(c, A_MOVB, amem(D_SI, k),
|
||||
areg(D_AX));
|
||||
ins2(c, A_MOVB, areg(D_AX),
|
||||
amem(D_BX, k));
|
||||
k += 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (fu && (fu->kind == TY_STR
|
||||
|| fu->kind == TY_SLICE)) {
|
||||
if (n->op != TK_ASSIGN)
|
||||
|
||||
@@ -20015,7 +20015,8 @@ fn cgstructlitfill(c: *cgen, si: *structinfo, lit: *node,
|
||||
};
|
||||
|
||||
// Thin wrapper preserving the BP-rel call shape used by cglet,
|
||||
// cgreturn, and cgassign N_IDENT-lhs N_STRUCTLIT.
|
||||
// cgreturn, cgassign N_IDENT-lhs N_STRUCTLIT, and the C1.25
|
||||
// @placescr materialise (cg_structlit_fill_bp's named twin).
|
||||
fn cgstructlitfillbp(c: *cgen, si: *structinfo, lit: *node, bpoff: i32) void = {
|
||||
if (si == nil) { return; };
|
||||
cgstructlitfill(c, si, lit, 0, 0, "", bpoff);
|
||||
@@ -29029,12 +29030,152 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
os.write(2, mt.ptr, mt.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
// C1.25 (#23): aggregate field STORE through the
|
||||
// resolver — run_thread's 40B capture store
|
||||
// `(*ts)[i].root_capture = capture{...}`. Dest
|
||||
// address from cgplaceaddr (BX), source address
|
||||
// in SI per rhs shape, then the #270-1b
|
||||
// word-copy tail (SI)→(BX). Pre-C1 a SILENT
|
||||
// no-op; C1 made it loud; this wires it
|
||||
// (loud-first, wire-next). Compound on an
|
||||
// aggregate is meaningless and stays loud.
|
||||
// Mirror of the cstage cgen.c C1.25 arm.
|
||||
if (fu.kind == tykind.TY_STRUCT
|
||||
|| fu.kind == tykind.TY_ARRAY
|
||||
|| fu.kind == tykind.TY_TUPLE) {
|
||||
let ma: str = "assign-resolver: aggregate field not wired (rule-7)\n";
|
||||
os.write(2, ma.ptr, ma.len: u64);
|
||||
os.exit(1);
|
||||
if (n.op != tkind.TK_ASSIGN) {
|
||||
let mac: str = "assign-resolver: compound on aggregate field not wired (rule-7)\n";
|
||||
os.write(2, mac.ptr, mac.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
if (n.rhs != nil) {
|
||||
if (n.rhs.kind == nkind.N_CALL) {
|
||||
// sret-class needs a runtime-RDI dest
|
||||
// (the #234-tail deferral); the ≤24B
|
||||
// reg-return receive is task #24. The
|
||||
// callee return type equals the field
|
||||
// type (checker-guaranteed), so
|
||||
// callsretsize gives cstage's
|
||||
// cg_sret_retsize(ft) verdict.
|
||||
if (callsretsize(c, n.rhs) > 0) {
|
||||
let mas: str = "assign-resolver: sret call into aggregate field unwired (#234-tail/rule-7)\n";
|
||||
os.write(2, mas.ptr, mas.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
let ma24: str = "assign-resolver: call result into aggregate field unwired (task #24/rule-7)\n";
|
||||
os.write(2, ma24.ptr, ma24.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
};
|
||||
let placed: bool = false;
|
||||
let isslit: bool = false;
|
||||
if (n.rhs != nil) {
|
||||
if (n.rhs.kind == nkind.N_STRUCTLIT
|
||||
&& fu.kind == tykind.TY_STRUCT) {
|
||||
isslit = true;
|
||||
};
|
||||
};
|
||||
if (isslit) {
|
||||
// @placescr — FRESH slot PER USE (the
|
||||
// @slicescr discipline via localalloc,
|
||||
// NOT the cached @tagscr table: a
|
||||
// cached slot is the #31 multi-live
|
||||
// corruption trap; rob ruling). Funnel
|
||||
// contract, #44 discipline: this arm is
|
||||
// the ONLY @placescr alloc site. Fill
|
||||
// handles nested literals (#18), tagged
|
||||
// fields, TK_ELLIPSIS autofill; the
|
||||
// value sits in memory, so the resolver
|
||||
// below may clobber AX/CX freely.
|
||||
let sname: str;
|
||||
sname.ptr = nil; sname.len = 0;
|
||||
if (ft.kind == tykind.TY_NAMED) {
|
||||
sname = ft.name;
|
||||
};
|
||||
let si: *structinfo = nil;
|
||||
if (sname.len > 0) {
|
||||
si = structlookup(c, sname);
|
||||
};
|
||||
if (si == nil) {
|
||||
// wwstage-only bail: the fill is
|
||||
// structinfo-keyed, so an anonymous-
|
||||
// struct field type has no registry
|
||||
// entry (cstage fills from Type
|
||||
// directly). Loud, rule 7.
|
||||
let man: str = "assign-resolver: structlit field layout unresolved (rule-7)\n";
|
||||
os.write(2, man.ptr, man.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
let scr: i32 = localalloc(c, "@placescr", fsz, nil);
|
||||
cgstructlitfillbp(c, si, n.rhs, scr);
|
||||
placed = cgplaceaddr(c, lhs, "BX");
|
||||
if (placed) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitoff(scr: i64);
|
||||
emitline("(BP), SI\n");
|
||||
};
|
||||
} else {
|
||||
// Addressable source — ident / global /
|
||||
// N_DOT chain / deref — via the closed
|
||||
// #265/#268 dispatch. Its N_INDEX arm
|
||||
// clobbers BX, so the dest spills around
|
||||
// it (the #270-1b order). Literal
|
||||
// arrays/tuples have no storage address
|
||||
// and stay loud.
|
||||
placed = cgplaceaddr(c, lhs, "BX");
|
||||
if (placed) {
|
||||
emitline("\tPUSHQ\tBX\n");
|
||||
if (!aggargsrcaddr(c, n.rhs, "SI")) {
|
||||
let mar: str = "assign-resolver: aggregate rhs shape unwired (rule-7)\n";
|
||||
os.write(2, mar.ptr, mar.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
emitline("\tPOPQ\tBX\n");
|
||||
};
|
||||
};
|
||||
if (!placed) {
|
||||
let mau: str = "unsupported assign target shape\n";
|
||||
os.write(2, mau.ptr, mau.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
let kc: i32 = 0;
|
||||
for (kc + 8 <= fsz) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(kc: i64);
|
||||
emitline("(SI), AX\n");
|
||||
emitline("\tMOVQ\tAX, ");
|
||||
emitoff(kc: i64);
|
||||
emitline("(BX)\n");
|
||||
kc += 8;
|
||||
};
|
||||
if (kc + 4 <= fsz) {
|
||||
emitline("\tMOVL\t");
|
||||
emitoff(kc: i64);
|
||||
emitline("(SI), AX\n");
|
||||
emitline("\tMOVL\tAX, ");
|
||||
emitoff(kc: i64);
|
||||
emitline("(BX)\n");
|
||||
kc += 4;
|
||||
};
|
||||
if (kc + 2 <= fsz) {
|
||||
emitline("\tMOVW\t");
|
||||
emitoff(kc: i64);
|
||||
emitline("(SI), AX\n");
|
||||
emitline("\tMOVW\tAX, ");
|
||||
emitoff(kc: i64);
|
||||
emitline("(BX)\n");
|
||||
kc += 2;
|
||||
};
|
||||
if (kc + 1 <= fsz) {
|
||||
emitline("\tMOVB\t");
|
||||
emitoff(kc: i64);
|
||||
emitline("(SI), AX\n");
|
||||
emitline("\tMOVB\tAX, ");
|
||||
emitoff(kc: i64);
|
||||
emitline("(BX)\n");
|
||||
kc += 1;
|
||||
};
|
||||
return;
|
||||
};
|
||||
};
|
||||
let fstrsl: bool = false;
|
||||
|
||||
@@ -9006,12 +9006,152 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
os.write(2, mt.ptr, mt.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
// C1.25 (#23): aggregate field STORE through the
|
||||
// resolver — run_thread's 40B capture store
|
||||
// `(*ts)[i].root_capture = capture{...}`. Dest
|
||||
// address from cgplaceaddr (BX), source address
|
||||
// in SI per rhs shape, then the #270-1b
|
||||
// word-copy tail (SI)→(BX). Pre-C1 a SILENT
|
||||
// no-op; C1 made it loud; this wires it
|
||||
// (loud-first, wire-next). Compound on an
|
||||
// aggregate is meaningless and stays loud.
|
||||
// Mirror of the cstage cgen.c C1.25 arm.
|
||||
if (fu.kind == tykind.TY_STRUCT
|
||||
|| fu.kind == tykind.TY_ARRAY
|
||||
|| fu.kind == tykind.TY_TUPLE) {
|
||||
let ma: str = "assign-resolver: aggregate field not wired (rule-7)\n";
|
||||
os.write(2, ma.ptr, ma.len: u64);
|
||||
os.exit(1);
|
||||
if (n.op != tkind.TK_ASSIGN) {
|
||||
let mac: str = "assign-resolver: compound on aggregate field not wired (rule-7)\n";
|
||||
os.write(2, mac.ptr, mac.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
if (n.rhs != nil) {
|
||||
if (n.rhs.kind == nkind.N_CALL) {
|
||||
// sret-class needs a runtime-RDI dest
|
||||
// (the #234-tail deferral); the ≤24B
|
||||
// reg-return receive is task #24. The
|
||||
// callee return type equals the field
|
||||
// type (checker-guaranteed), so
|
||||
// callsretsize gives cstage's
|
||||
// cg_sret_retsize(ft) verdict.
|
||||
if (callsretsize(c, n.rhs) > 0) {
|
||||
let mas: str = "assign-resolver: sret call into aggregate field unwired (#234-tail/rule-7)\n";
|
||||
os.write(2, mas.ptr, mas.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
let ma24: str = "assign-resolver: call result into aggregate field unwired (task #24/rule-7)\n";
|
||||
os.write(2, ma24.ptr, ma24.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
};
|
||||
let placed: bool = false;
|
||||
let isslit: bool = false;
|
||||
if (n.rhs != nil) {
|
||||
if (n.rhs.kind == nkind.N_STRUCTLIT
|
||||
&& fu.kind == tykind.TY_STRUCT) {
|
||||
isslit = true;
|
||||
};
|
||||
};
|
||||
if (isslit) {
|
||||
// @placescr — FRESH slot PER USE (the
|
||||
// @slicescr discipline via localalloc,
|
||||
// NOT the cached @tagscr table: a
|
||||
// cached slot is the #31 multi-live
|
||||
// corruption trap; rob ruling). Funnel
|
||||
// contract, #44 discipline: this arm is
|
||||
// the ONLY @placescr alloc site. Fill
|
||||
// handles nested literals (#18), tagged
|
||||
// fields, TK_ELLIPSIS autofill; the
|
||||
// value sits in memory, so the resolver
|
||||
// below may clobber AX/CX freely.
|
||||
let sname: str;
|
||||
sname.ptr = nil; sname.len = 0;
|
||||
if (ft.kind == tykind.TY_NAMED) {
|
||||
sname = ft.name;
|
||||
};
|
||||
let si: *structinfo = nil;
|
||||
if (sname.len > 0) {
|
||||
si = structlookup(c, sname);
|
||||
};
|
||||
if (si == nil) {
|
||||
// wwstage-only bail: the fill is
|
||||
// structinfo-keyed, so an anonymous-
|
||||
// struct field type has no registry
|
||||
// entry (cstage fills from Type
|
||||
// directly). Loud, rule 7.
|
||||
let man: str = "assign-resolver: structlit field layout unresolved (rule-7)\n";
|
||||
os.write(2, man.ptr, man.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
let scr: i32 = localalloc(c, "@placescr", fsz, nil);
|
||||
cgstructlitfillbp(c, si, n.rhs, scr);
|
||||
placed = cgplaceaddr(c, lhs, "BX");
|
||||
if (placed) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitoff(scr: i64);
|
||||
emitline("(BP), SI\n");
|
||||
};
|
||||
} else {
|
||||
// Addressable source — ident / global /
|
||||
// N_DOT chain / deref — via the closed
|
||||
// #265/#268 dispatch. Its N_INDEX arm
|
||||
// clobbers BX, so the dest spills around
|
||||
// it (the #270-1b order). Literal
|
||||
// arrays/tuples have no storage address
|
||||
// and stay loud.
|
||||
placed = cgplaceaddr(c, lhs, "BX");
|
||||
if (placed) {
|
||||
emitline("\tPUSHQ\tBX\n");
|
||||
if (!aggargsrcaddr(c, n.rhs, "SI")) {
|
||||
let mar: str = "assign-resolver: aggregate rhs shape unwired (rule-7)\n";
|
||||
os.write(2, mar.ptr, mar.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
emitline("\tPOPQ\tBX\n");
|
||||
};
|
||||
};
|
||||
if (!placed) {
|
||||
let mau: str = "unsupported assign target shape\n";
|
||||
os.write(2, mau.ptr, mau.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
let kc: i32 = 0;
|
||||
for (kc + 8 <= fsz) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(kc: i64);
|
||||
emitline("(SI), AX\n");
|
||||
emitline("\tMOVQ\tAX, ");
|
||||
emitoff(kc: i64);
|
||||
emitline("(BX)\n");
|
||||
kc += 8;
|
||||
};
|
||||
if (kc + 4 <= fsz) {
|
||||
emitline("\tMOVL\t");
|
||||
emitoff(kc: i64);
|
||||
emitline("(SI), AX\n");
|
||||
emitline("\tMOVL\tAX, ");
|
||||
emitoff(kc: i64);
|
||||
emitline("(BX)\n");
|
||||
kc += 4;
|
||||
};
|
||||
if (kc + 2 <= fsz) {
|
||||
emitline("\tMOVW\t");
|
||||
emitoff(kc: i64);
|
||||
emitline("(SI), AX\n");
|
||||
emitline("\tMOVW\tAX, ");
|
||||
emitoff(kc: i64);
|
||||
emitline("(BX)\n");
|
||||
kc += 2;
|
||||
};
|
||||
if (kc + 1 <= fsz) {
|
||||
emitline("\tMOVB\t");
|
||||
emitoff(kc: i64);
|
||||
emitline("(SI), AX\n");
|
||||
emitline("\tMOVB\tAX, ");
|
||||
emitoff(kc: i64);
|
||||
emitline("(BX)\n");
|
||||
kc += 1;
|
||||
};
|
||||
return;
|
||||
};
|
||||
};
|
||||
let fstrsl: bool = false;
|
||||
|
||||
@@ -4283,7 +4283,8 @@ fn cgstructlitfill(c: *cgen, si: *structinfo, lit: *node,
|
||||
};
|
||||
|
||||
// Thin wrapper preserving the BP-rel call shape used by cglet,
|
||||
// cgreturn, and cgassign N_IDENT-lhs N_STRUCTLIT.
|
||||
// cgreturn, cgassign N_IDENT-lhs N_STRUCTLIT, and the C1.25
|
||||
// @placescr materialise (cg_structlit_fill_bp's named twin).
|
||||
fn cgstructlitfillbp(c: *cgen, si: *structinfo, lit: *node, bpoff: i32) void = {
|
||||
if (si == nil) { return; };
|
||||
cgstructlitfill(c, si, lit, 0, 0, "", bpoff);
|
||||
|
||||
@@ -20015,7 +20015,8 @@ fn cgstructlitfill(c: *cgen, si: *structinfo, lit: *node,
|
||||
};
|
||||
|
||||
// Thin wrapper preserving the BP-rel call shape used by cglet,
|
||||
// cgreturn, and cgassign N_IDENT-lhs N_STRUCTLIT.
|
||||
// cgreturn, cgassign N_IDENT-lhs N_STRUCTLIT, and the C1.25
|
||||
// @placescr materialise (cg_structlit_fill_bp's named twin).
|
||||
fn cgstructlitfillbp(c: *cgen, si: *structinfo, lit: *node, bpoff: i32) void = {
|
||||
if (si == nil) { return; };
|
||||
cgstructlitfill(c, si, lit, 0, 0, "", bpoff);
|
||||
@@ -29029,12 +29030,152 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
os.write(2, mt.ptr, mt.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
// C1.25 (#23): aggregate field STORE through the
|
||||
// resolver — run_thread's 40B capture store
|
||||
// `(*ts)[i].root_capture = capture{...}`. Dest
|
||||
// address from cgplaceaddr (BX), source address
|
||||
// in SI per rhs shape, then the #270-1b
|
||||
// word-copy tail (SI)→(BX). Pre-C1 a SILENT
|
||||
// no-op; C1 made it loud; this wires it
|
||||
// (loud-first, wire-next). Compound on an
|
||||
// aggregate is meaningless and stays loud.
|
||||
// Mirror of the cstage cgen.c C1.25 arm.
|
||||
if (fu.kind == tykind.TY_STRUCT
|
||||
|| fu.kind == tykind.TY_ARRAY
|
||||
|| fu.kind == tykind.TY_TUPLE) {
|
||||
let ma: str = "assign-resolver: aggregate field not wired (rule-7)\n";
|
||||
os.write(2, ma.ptr, ma.len: u64);
|
||||
os.exit(1);
|
||||
if (n.op != tkind.TK_ASSIGN) {
|
||||
let mac: str = "assign-resolver: compound on aggregate field not wired (rule-7)\n";
|
||||
os.write(2, mac.ptr, mac.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
if (n.rhs != nil) {
|
||||
if (n.rhs.kind == nkind.N_CALL) {
|
||||
// sret-class needs a runtime-RDI dest
|
||||
// (the #234-tail deferral); the ≤24B
|
||||
// reg-return receive is task #24. The
|
||||
// callee return type equals the field
|
||||
// type (checker-guaranteed), so
|
||||
// callsretsize gives cstage's
|
||||
// cg_sret_retsize(ft) verdict.
|
||||
if (callsretsize(c, n.rhs) > 0) {
|
||||
let mas: str = "assign-resolver: sret call into aggregate field unwired (#234-tail/rule-7)\n";
|
||||
os.write(2, mas.ptr, mas.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
let ma24: str = "assign-resolver: call result into aggregate field unwired (task #24/rule-7)\n";
|
||||
os.write(2, ma24.ptr, ma24.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
};
|
||||
let placed: bool = false;
|
||||
let isslit: bool = false;
|
||||
if (n.rhs != nil) {
|
||||
if (n.rhs.kind == nkind.N_STRUCTLIT
|
||||
&& fu.kind == tykind.TY_STRUCT) {
|
||||
isslit = true;
|
||||
};
|
||||
};
|
||||
if (isslit) {
|
||||
// @placescr — FRESH slot PER USE (the
|
||||
// @slicescr discipline via localalloc,
|
||||
// NOT the cached @tagscr table: a
|
||||
// cached slot is the #31 multi-live
|
||||
// corruption trap; rob ruling). Funnel
|
||||
// contract, #44 discipline: this arm is
|
||||
// the ONLY @placescr alloc site. Fill
|
||||
// handles nested literals (#18), tagged
|
||||
// fields, TK_ELLIPSIS autofill; the
|
||||
// value sits in memory, so the resolver
|
||||
// below may clobber AX/CX freely.
|
||||
let sname: str;
|
||||
sname.ptr = nil; sname.len = 0;
|
||||
if (ft.kind == tykind.TY_NAMED) {
|
||||
sname = ft.name;
|
||||
};
|
||||
let si: *structinfo = nil;
|
||||
if (sname.len > 0) {
|
||||
si = structlookup(c, sname);
|
||||
};
|
||||
if (si == nil) {
|
||||
// wwstage-only bail: the fill is
|
||||
// structinfo-keyed, so an anonymous-
|
||||
// struct field type has no registry
|
||||
// entry (cstage fills from Type
|
||||
// directly). Loud, rule 7.
|
||||
let man: str = "assign-resolver: structlit field layout unresolved (rule-7)\n";
|
||||
os.write(2, man.ptr, man.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
let scr: i32 = localalloc(c, "@placescr", fsz, nil);
|
||||
cgstructlitfillbp(c, si, n.rhs, scr);
|
||||
placed = cgplaceaddr(c, lhs, "BX");
|
||||
if (placed) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitoff(scr: i64);
|
||||
emitline("(BP), SI\n");
|
||||
};
|
||||
} else {
|
||||
// Addressable source — ident / global /
|
||||
// N_DOT chain / deref — via the closed
|
||||
// #265/#268 dispatch. Its N_INDEX arm
|
||||
// clobbers BX, so the dest spills around
|
||||
// it (the #270-1b order). Literal
|
||||
// arrays/tuples have no storage address
|
||||
// and stay loud.
|
||||
placed = cgplaceaddr(c, lhs, "BX");
|
||||
if (placed) {
|
||||
emitline("\tPUSHQ\tBX\n");
|
||||
if (!aggargsrcaddr(c, n.rhs, "SI")) {
|
||||
let mar: str = "assign-resolver: aggregate rhs shape unwired (rule-7)\n";
|
||||
os.write(2, mar.ptr, mar.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
emitline("\tPOPQ\tBX\n");
|
||||
};
|
||||
};
|
||||
if (!placed) {
|
||||
let mau: str = "unsupported assign target shape\n";
|
||||
os.write(2, mau.ptr, mau.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
let kc: i32 = 0;
|
||||
for (kc + 8 <= fsz) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(kc: i64);
|
||||
emitline("(SI), AX\n");
|
||||
emitline("\tMOVQ\tAX, ");
|
||||
emitoff(kc: i64);
|
||||
emitline("(BX)\n");
|
||||
kc += 8;
|
||||
};
|
||||
if (kc + 4 <= fsz) {
|
||||
emitline("\tMOVL\t");
|
||||
emitoff(kc: i64);
|
||||
emitline("(SI), AX\n");
|
||||
emitline("\tMOVL\tAX, ");
|
||||
emitoff(kc: i64);
|
||||
emitline("(BX)\n");
|
||||
kc += 4;
|
||||
};
|
||||
if (kc + 2 <= fsz) {
|
||||
emitline("\tMOVW\t");
|
||||
emitoff(kc: i64);
|
||||
emitline("(SI), AX\n");
|
||||
emitline("\tMOVW\tAX, ");
|
||||
emitoff(kc: i64);
|
||||
emitline("(BX)\n");
|
||||
kc += 2;
|
||||
};
|
||||
if (kc + 1 <= fsz) {
|
||||
emitline("\tMOVB\t");
|
||||
emitoff(kc: i64);
|
||||
emitline("(SI), AX\n");
|
||||
emitline("\tMOVB\tAX, ");
|
||||
emitoff(kc: i64);
|
||||
emitline("(BX)\n");
|
||||
kc += 1;
|
||||
};
|
||||
return;
|
||||
};
|
||||
};
|
||||
let fstrsl: bool = false;
|
||||
|
||||
@@ -14,10 +14,15 @@
|
||||
* selfhost/cmd/wcc/cgenexpr.ww); each call-site keeps its own
|
||||
* load/store emission, and every N_DOT lvalue the resolver can't
|
||||
* address now dies LOUD ("unsupported assign target shape") instead of
|
||||
* silently dropping (rule 7). Field kinds the resolver arm does not
|
||||
* wire yet (float / tagged / aggregate / str-slice compound) hard-stop
|
||||
* with their own diagnostics — the reject rows pin the exact text on
|
||||
* BOTH stages. Non-DOT lvalue tail residue is task #22.
|
||||
* silently dropping (rule 7). C1.25 (#23) wires the aggregate field
|
||||
* STORE on top of the resolver: literal rhs materialises into a FRESH
|
||||
* per-use @placescr slot then word-copies to the resolved address;
|
||||
* addressable rhs (ident/global/dot/deref) takes its source address
|
||||
* straight from the #265/#268 dispatch. Field kinds the resolver arm
|
||||
* does not wire yet (float / tagged / aggregate-compound / str-slice
|
||||
* compound / call-rhs into aggregate) hard-stop with their own
|
||||
* diagnostics — the reject rows pin the exact text on BOTH stages.
|
||||
* Non-DOT lvalue tail residue is task #22.
|
||||
*
|
||||
* row | shape | want
|
||||
* --------------------+----------------------------------------+------
|
||||
@@ -36,7 +41,17 @@
|
||||
* neutral_ident_bases | x.f / a[i].f / p.f = and += (untouched | 51
|
||||
* | enumerated arms — runtime-pins the |
|
||||
* | resolver's asm-neutrality claim) |
|
||||
* reject_aggregate | struct-typed field store | BUILD_FAIL
|
||||
* agg_structlit_40b | C1.25: 40B capture literal store via | 52
|
||||
* | fresh @placescr + word-copy, incl ... |
|
||||
* agg_from_ident_deref| C1.25: aggregate from ident + *p rhs | 53
|
||||
* agg_nested_lit | C1.25: nested struct literal (#18) | 54
|
||||
* agg_array_field_odd | C1.25: [3]u8 field, MOVW/MOVB tails | 55
|
||||
* agg_fresh_two_stores| C1.25: two same-size structlit stores | 56
|
||||
* | in ONE fn — distinct @placescr slots |
|
||||
* agg_array_field_movl| C1.25: [3]u32 field, MOVQ+MOVL tail | 57
|
||||
* reject_agg_compound | compound on aggregate field | BUILD_FAIL
|
||||
* reject_agg_call_sret| >24B call rhs (#234-tail) | BUILD_FAIL
|
||||
* reject_agg_call_reg | ≤24B call rhs (task #24) | BUILD_FAIL
|
||||
* reject_float | f64 field store | BUILD_FAIL
|
||||
* reject_tagged | tagged-union field store | BUILD_FAIL
|
||||
* reject_str_compound | (*ts)[i].name += — str/slice compound | BUILD_FAIL
|
||||
@@ -363,19 +378,245 @@ static const struct row rows[] = {
|
||||
/* The fold-2b 40B capture store (p7b/p7_composed) — wired in a
|
||||
* follow-up resolver commit; until then it must die LOUD, never
|
||||
* the pre-C1 silent drop. */
|
||||
{ "reject_aggregate",
|
||||
/* C1.25 (#23): the run_thread 40B capture store, graduated from
|
||||
* BUILD_FAIL (C1's loud boundary) to wired. Literal rhs goes
|
||||
* through a FRESH per-use @placescr materialise + word-copy; the
|
||||
* `...` setter pins the autofill zero loop; neighbour element +
|
||||
* sibling field readbacks pin the stride and copy length. */
|
||||
/* Readback is RAW bytes over ts.ptr (the 804 tagged_56b
|
||||
* precedent): a depth-2 read behind an index (ts[1].cap.start)
|
||||
* is the F4 walker gap (task #6) and link-fails today on the
|
||||
* cgen.c:9038 global-leaf fallback — typed readbacks graduate
|
||||
* with the C2 read-walker. Layout: t={pc@0,cap@8}, size 48;
|
||||
* capture={content(str ptr@0,len@8,cap@16),start@24,end@32}.
|
||||
* Elem1 base 48 → content.len byte 64, start 80, end 88;
|
||||
* elem0 → 16/32/40. Stored values fit one byte. */
|
||||
{ "agg_structlit_40b",
|
||||
"package main;\n"
|
||||
"type capture = struct { content: str, start: size, end: size };\n"
|
||||
"type t = struct { pc: size, cap: capture };\n"
|
||||
"fn setcap(ts: *[]t, i: size) void = {\n"
|
||||
"\t(*ts)[i].cap = capture { content = \"x\", start = 1, end = 2 };\n"
|
||||
"\t(*ts)[i].cap = capture { content = \"hit\", start = 2, end = 4 };\n"
|
||||
"};\n"
|
||||
"fn clearcap(ts: *[]t, i: size) void = {\n"
|
||||
"\t(*ts)[i].cap = capture { content = \"z\", ... };\n"
|
||||
"};\n"
|
||||
"export fn main() i32 = {\n"
|
||||
"\tlet z: capture = capture { content = \"\", start = 0, end = 0 };\n"
|
||||
"\tlet ts: []t = [];\n"
|
||||
"\tappend(ts, t { pc = 7, cap = z });\n"
|
||||
"\tappend(ts, t { pc = 8, cap = z });\n"
|
||||
"\tsetcap(&ts, 1);\n"
|
||||
"\tlet bp: *u8 = ts.ptr: *u8;\n"
|
||||
"\tif (bp[64] != 3u8) { return 1; };\n"
|
||||
"\tif (bp[80] != 2u8) { return 2; };\n"
|
||||
"\tif (bp[88] != 4u8) { return 3; };\n"
|
||||
"\tif (ts[1].pc != 8) { return 4; };\n"
|
||||
"\tif (bp[16] != 0u8) { return 5; };\n"
|
||||
"\tif (ts[0].pc != 7) { return 6; };\n"
|
||||
"\tclearcap(&ts, 1);\n"
|
||||
"\tif (bp[64] != 1u8) { return 7; };\n"
|
||||
"\tif (bp[80] != 0u8) { return 8; };\n"
|
||||
"\tif (bp[88] != 0u8) { return 9; };\n"
|
||||
"\treturn 52;\n"
|
||||
"};\n",
|
||||
52, NULL },
|
||||
|
||||
/* Addressable aggregate sources via the #265/#268 dispatch:
|
||||
* local ident (LEAQ slot) and deref (*pc). Raw-byte readback per
|
||||
* the agg_structlit_40b layout note (F4 blocks typed depth-2). */
|
||||
{ "agg_from_ident_deref",
|
||||
"package main;\n"
|
||||
"type capture = struct { content: str, start: size, end: size };\n"
|
||||
"type t = struct { pc: size, cap: capture };\n"
|
||||
"fn copycap(ts: *[]t, i: size, src: capture) void = {\n"
|
||||
"\t(*ts)[i].cap = src;\n"
|
||||
"};\n"
|
||||
"fn derefcap(ts: *[]t, i: size, pc: *capture) void = {\n"
|
||||
"\t(*ts)[i].cap = *pc;\n"
|
||||
"};\n"
|
||||
"export fn main() i32 = {\n"
|
||||
"\tlet z: capture = capture { content = \"\", start = 0, end = 0 };\n"
|
||||
"\tlet ts: []t = [];\n"
|
||||
"\tappend(ts, t { pc = 7, cap = z });\n"
|
||||
"\tappend(ts, t { pc = 8, cap = z });\n"
|
||||
"\tlet a: capture = capture { content = \"ab\", start = 1, end = 3 };\n"
|
||||
"\tcopycap(&ts, 1, a);\n"
|
||||
"\tlet bp: *u8 = ts.ptr: *u8;\n"
|
||||
"\tif (bp[64] != 2u8) { return 1; };\n"
|
||||
"\tif (bp[80] != 1u8) { return 2; };\n"
|
||||
"\tif (bp[88] != 3u8) { return 3; };\n"
|
||||
"\tlet b: capture = capture { content = \"wxyz\", start = 5, end = 9 };\n"
|
||||
"\tderefcap(&ts, 0, &b);\n"
|
||||
"\tif (bp[16] != 4u8) { return 4; };\n"
|
||||
"\tif (bp[32] != 5u8) { return 5; };\n"
|
||||
"\tif (bp[40] != 9u8) { return 6; };\n"
|
||||
"\tif (bp[80] != 1u8) { return 7; };\n"
|
||||
"\treturn 53;\n"
|
||||
"};\n",
|
||||
53, NULL },
|
||||
|
||||
/* Nested struct-typed literal field inside the stored literal —
|
||||
* the #18 recursion through cg_structlit_fill must land the inner
|
||||
* bytes in the @placescr image before the copy. */
|
||||
{ "agg_nested_lit",
|
||||
"package main;\n"
|
||||
"type inner = struct { x: i64, y: i64 };\n"
|
||||
"type big = struct { a: i64, ib: inner };\n"
|
||||
"type t = struct { pc: size, bg: big };\n"
|
||||
"fn setbg(ts: *[]t, i: size) void = {\n"
|
||||
"\t(*ts)[i].bg = big { a = 1, ib = inner { x = 2, y = 3 } };\n"
|
||||
"};\n"
|
||||
"export fn main() i32 = {\n"
|
||||
"\tlet z: big = big { a = 0, ib = inner { x = 0, y = 0 } };\n"
|
||||
"\tlet ts: []t = [];\n"
|
||||
"\tappend(ts, t { pc = 7, bg = z });\n"
|
||||
"\tsetbg(&ts, 0);\n"
|
||||
"\tlet bp: *u8 = ts.ptr: *u8;\n"
|
||||
"\tif (bp[8] != 1u8) { return 1; };\n"
|
||||
"\tif (bp[16] != 2u8) { return 2; };\n"
|
||||
"\tif (bp[24] != 3u8) { return 3; };\n"
|
||||
"\tif (ts[0].pc != 7) { return 4; };\n"
|
||||
"\treturn 54;\n"
|
||||
"};\n",
|
||||
54, NULL },
|
||||
|
||||
/* [3]u8 array field from an ident source — TY_ARRAY aggregate arm
|
||||
* + the MOVW/MOVB copy tails (fsz=3). */
|
||||
{ "agg_array_field_odd",
|
||||
"package main;\n"
|
||||
"type t = struct { pc: size, arr: [3]u8 };\n"
|
||||
"fn setarr(ts: *[]t, i: size, src: [3]u8) void = {\n"
|
||||
"\t(*ts)[i].arr = src;\n"
|
||||
"};\n"
|
||||
"export fn main() i32 = {\n"
|
||||
"\tlet a3: [3]u8 = [9u8, 8u8, 7u8];\n"
|
||||
"\tlet z3: [3]u8 = [0u8, 0u8, 0u8];\n"
|
||||
"\tlet ts: []t = [];\n"
|
||||
"\tappend(ts, t { pc = 5, arr = z3 });\n"
|
||||
"\tsetarr(&ts, 0, a3);\n"
|
||||
"\tif (ts[0].arr[0] != 9u8) { return 1; };\n"
|
||||
"\tif (ts[0].arr[1] != 8u8) { return 2; };\n"
|
||||
"\tif (ts[0].arr[2] != 7u8) { return 3; };\n"
|
||||
"\tif (ts[0].pc != 5) { return 4; };\n"
|
||||
"\treturn 55;\n"
|
||||
"};\n",
|
||||
55, NULL },
|
||||
|
||||
/* Two same-size structlit stores in ONE fn — each must get its
|
||||
* own FRESH @placescr slot and both must land (the #31 multi-
|
||||
* live discipline pin). The stronger shape — a structlit whose
|
||||
* FIELD expr recurses into a same-size aggregate assign, the
|
||||
* fresh-per-use rationale proper — is not constructible today:
|
||||
* match-expr (the only stmt-carrying expr) is a parse reject in
|
||||
* field position; fresh-per-use stays defensive (rob ruling). */
|
||||
{ "agg_fresh_two_stores",
|
||||
"package main;\n"
|
||||
"type capture = struct { content: str, start: size, end: size };\n"
|
||||
"type t = struct { pc: size, cap: capture };\n"
|
||||
"fn settwo(ts: *[]t) void = {\n"
|
||||
"\t(*ts)[0].cap = capture { content = \"aa\", start = 1, end = 2 };\n"
|
||||
"\t(*ts)[1].cap = capture { content = \"bbb\", start = 3, end = 4 };\n"
|
||||
"};\n"
|
||||
"export fn main() i32 = {\n"
|
||||
"\tlet z: capture = capture { content = \"\", start = 0, end = 0 };\n"
|
||||
"\tlet ts: []t = [];\n"
|
||||
"\tappend(ts, t { pc = 7, cap = z });\n"
|
||||
"\tappend(ts, t { pc = 8, cap = z });\n"
|
||||
"\tsettwo(&ts);\n"
|
||||
"\tlet bp: *u8 = ts.ptr: *u8;\n"
|
||||
"\tif (bp[16] != 2u8) { return 1; };\n"
|
||||
"\tif (bp[32] != 1u8) { return 2; };\n"
|
||||
"\tif (bp[40] != 2u8) { return 3; };\n"
|
||||
"\tif (bp[64] != 3u8) { return 4; };\n"
|
||||
"\tif (bp[80] != 3u8) { return 5; };\n"
|
||||
"\tif (bp[88] != 4u8) { return 6; };\n"
|
||||
"\treturn 56;\n"
|
||||
"};\n",
|
||||
56, NULL },
|
||||
|
||||
/* [3]u32 field (fsz=12) — the MOVL copy tail, untouched by the
|
||||
* 40B (all-MOVQ) and [3]u8 (MOVW+MOVB) rows.
|
||||
*
|
||||
* Matrix honesty, TY_TUPLE: the arm wires tuple fields and a
|
||||
* local-ident tuple source stores correctly (cstage-verified),
|
||||
* but a dual-stage row is blocked by three PRE-EXISTING tuple
|
||||
* gaps outside this arm: by-value tuple param drops word 2 at
|
||||
* runtime (both stages, master too), wwstage tuple-let init
|
||||
* `let a: (i64,i64) = (3,4)` drops the word-2 store (cs≠ww),
|
||||
* and `a.0 =` element assign is unwired (loud). Tuple-field row
|
||||
* graduates with that family (filed). */
|
||||
{ "agg_array_field_movl",
|
||||
"package main;\n"
|
||||
"type t = struct { pc: size, arr: [3]u32 };\n"
|
||||
"fn setarr(ts: *[]t, i: size, src: [3]u32) void = {\n"
|
||||
"\t(*ts)[i].arr = src;\n"
|
||||
"};\n"
|
||||
"export fn main() i32 = {\n"
|
||||
"\tlet a3: [3]u32 = [9u32, 8u32, 7u32];\n"
|
||||
"\tlet z3: [3]u32 = [0u32, 0u32, 0u32];\n"
|
||||
"\tlet ts: []t = [];\n"
|
||||
"\tappend(ts, t { pc = 5, arr = z3 });\n"
|
||||
"\tsetarr(&ts, 0, a3);\n"
|
||||
"\tif (ts[0].arr[0] != 9u32) { return 1; };\n"
|
||||
"\tif (ts[0].arr[1] != 8u32) { return 2; };\n"
|
||||
"\tif (ts[0].arr[2] != 7u32) { return 3; };\n"
|
||||
"\tif (ts[0].pc != 5) { return 4; };\n"
|
||||
"\treturn 57;\n"
|
||||
"};\n",
|
||||
57, NULL },
|
||||
|
||||
/* Compound on an aggregate field is meaningless — stays loud. */
|
||||
{ "reject_agg_compound",
|
||||
"package main;\n"
|
||||
"type capture = struct { content: str, start: size, end: size };\n"
|
||||
"type t = struct { pc: size, cap: capture };\n"
|
||||
"fn addcap(ts: *[]t, i: size, src: capture) void = {\n"
|
||||
"\t(*ts)[i].cap += src;\n"
|
||||
"};\n"
|
||||
"export fn main() i32 = {\n"
|
||||
"\tlet ts: []t = [];\n"
|
||||
"\tlet a: capture = capture { content = \"\", start = 0, end = 0 };\n"
|
||||
"\taddcap(&ts, 0, a);\n"
|
||||
"\treturn 0;\n"
|
||||
"};\n",
|
||||
BUILD_FAIL,
|
||||
"assign-resolver: compound on aggregate field not wired (rule-7)" },
|
||||
|
||||
/* sret-class call rhs (>24B return) needs a runtime-RDI dest —
|
||||
* the #234-tail deferral. */
|
||||
{ "reject_agg_call_sret",
|
||||
"package main;\n"
|
||||
"type capture = struct { content: str, start: size, end: size };\n"
|
||||
"type t = struct { pc: size, cap: capture };\n"
|
||||
"fn mk() capture = {\n"
|
||||
"\treturn capture { content = \"x\", start = 1, end = 2 };\n"
|
||||
"};\n"
|
||||
"fn setcap(ts: *[]t, i: size) void = { (*ts)[i].cap = mk(); };\n"
|
||||
"export fn main() i32 = {\n"
|
||||
"\tlet ts: []t = [];\n"
|
||||
"\tsetcap(&ts, 0);\n"
|
||||
"\treturn 0;\n"
|
||||
"};\n",
|
||||
BUILD_FAIL, "assign-resolver: aggregate field not wired (rule-7)" },
|
||||
BUILD_FAIL,
|
||||
"assign-resolver: sret call into aggregate field unwired "
|
||||
"(#234-tail/rule-7)" },
|
||||
|
||||
/* ≤24B reg-return call rhs — deferred, task #24. */
|
||||
{ "reject_agg_call_reg",
|
||||
"package main;\n"
|
||||
"type pair = struct { a: i64, b: i64 };\n"
|
||||
"type t = struct { pc: size, pr: pair };\n"
|
||||
"fn mk() pair = { return pair { a = 1, b = 2 }; };\n"
|
||||
"fn setpr(ts: *[]t, i: size) void = { (*ts)[i].pr = mk(); };\n"
|
||||
"export fn main() i32 = {\n"
|
||||
"\tlet ts: []t = [];\n"
|
||||
"\tsetpr(&ts, 0);\n"
|
||||
"\treturn 0;\n"
|
||||
"};\n",
|
||||
BUILD_FAIL,
|
||||
"assign-resolver: call result into aggregate field unwired "
|
||||
"(task #24/rule-7)" },
|
||||
|
||||
{ "reject_float",
|
||||
"package main;\n"
|
||||
|
||||
Reference in New Issue
Block a user