From f191e6e0e28981adf377261542c6883ff8202a30 Mon Sep 17 00:00:00 2001 From: Hojun-Cho Date: Sun, 9 Aug 2026 00:32:41 +0900 Subject: [PATCH] wcc: modulo is integer-only; compound ops carry their operand class Hare's rule (harec check.c binarithm): % and the bitwise/shift five are integer-only; + - * / need numeric operands. ww grouped % with the numeric ops, and compound assigns never op-checked at all, so `a % b` on floats compiled half-lowered (live cs!=ww divergence), `a %= 2.0` plain-stored the rhs (op silently dropped, both stages), and `s += "cd"` garbled str headers. Gate both at the checker, both stages; the cgen float-compound fallbacks and the three unknown- compound legacy defaults (deref/global/local) demote to rule-7 hard stops. 34 compound-on-tagged/str/slice fixtures re-pin from the old cgen "not wired" stops to the earlier checker diagnostics; 3 new reject fixtures pin the closed shapes. --- cmd/w6c/cgen.c | 53 ++++++-------- cmd/wcc/check.c | 31 ++++++++ internal/wwfixture/types.ww | 8 +-- selfhost/cmd/wcc/cgenexpr.ww | 70 ++++++++++++------- selfhost/cmd/wcc/check.ww | 37 ++++++++++ test/wcc/data/dotfield_compound_slice/case.ww | 2 +- test/wcc/data/dotfield_compound_str/case.ww | 2 +- .../wcc/data/dotfield_compound_tagged/case.ww | 2 +- test/wcc/data/float_mod_reject/case.ww | 11 +++ test/wcc/data/float_modeq_reject/case.ww | 12 ++++ .../wcc/data/idx_compound_str_indexed/case.ww | 2 +- test/wcc/data/idxfield_compound_slice/case.ww | 2 +- test/wcc/data/idxfield_compound_str/case.ww | 2 +- .../wcc/data/idxfield_compound_tagged/case.ww | 2 +- .../wcc/data/r805_reject_agg_compound/case.ww | 2 +- .../wcc/data/r805_reject_str_compound/case.ww | 2 +- .../r989_tagderef_ampeq_tagged_deref/case.ww | 2 +- .../case.ww | 2 +- .../case.ww | 2 +- .../case.ww | 2 +- .../case.ww | 2 +- .../r989_tagderef_pipeeq_tagged_deref/case.ww | 2 +- .../r989_tagderef_pluseq_tagged_deref/case.ww | 2 +- .../case.ww | 2 +- .../case.ww | 2 +- .../r989_tagderef_stareq_tagged_deref/case.ww | 2 +- .../data/r989_tagplace_gident_pluseq/case.ww | 2 +- .../data/r989_tagplace_gidx_careteq/case.ww | 2 +- .../data/r989_tagplace_gidx_pluseq/case.ww | 2 +- .../data/r989_tagplace_gidx_stareq/case.ww | 2 +- .../data/r989_tagplace_ident_careteq/case.ww | 2 +- .../data/r989_tagplace_ident_lshifteq/case.ww | 2 +- .../data/r989_tagplace_ident_minuseq/case.ww | 2 +- .../data/r989_tagplace_ident_pipeeq/case.ww | 2 +- .../data/r989_tagplace_ident_pluseq/case.ww | 2 +- .../data/r989_tagplace_ident_slasheq/case.ww | 2 +- .../data/r989_tagplace_ident_stareq/case.ww | 2 +- .../data/r989_tagplace_lidx_lshifteq/case.ww | 2 +- .../data/r989_tagplace_lidx_minuseq/case.ww | 2 +- .../data/r989_tagplace_lidx_pipeeq/case.ww | 2 +- .../data/r989_tagplace_lidx_pluseq/case.ww | 2 +- test/wcc/data/str_pluseq_reject/case.ww | 9 +++ 42 files changed, 206 insertions(+), 93 deletions(-) create mode 100644 test/wcc/data/float_mod_reject/case.ww create mode 100644 test/wcc/data/float_modeq_reject/case.ww create mode 100644 test/wcc/data/str_pluseq_reject/case.ww diff --git a/cmd/w6c/cgen.c b/cmd/w6c/cgen.c index b3485c99..dbbb22d6 100644 --- a/cmd/w6c/cgen.c +++ b/cmd/w6c/cgen.c @@ -7041,25 +7041,20 @@ cgexpr(Cg *c, Node *n, Local *locals) case TK_SLASHEQ: fop = divop; break; default: break; } + /* Non-SSE compound on a float lvalue is checker- + * rejected (modulo/bitwise integer-only); a survivor + * here means a checker gap — loud, never the old + * plain-store of rhs that dropped the op. */ + if (fop < 0) + fatal("float compound: op has no SSE " + "lowering (rule 7)"); if (off != 0) { - if (fop < 0) { - /* Unsupported compound (e.g., %= on float): - * fall back to plain store of rhs. */ - ins2(c, mvop, areg(D_X0), - amem(D_BP, off)); - break; - } ins2(c, mvop, amem(D_BP, off), areg(D_X1)); ins2(c, fop, areg(D_X0), areg(D_X1)); ins2(c, mvop, areg(D_X1), amem(D_BP, off)); } else { ins2(c, A_LEAQ, masym(c, n->lhs->str), areg(D_CX)); - if (fop < 0) { - ins2(c, mvop, areg(D_X0), - amem(D_CX, 0)); - break; - } ins2(c, mvop, amem(D_CX, 0), areg(D_X1)); ins2(c, fop, areg(D_X0), areg(D_X1)); ins2(c, mvop, areg(D_X1), amem(D_CX, 0)); @@ -7921,10 +7916,12 @@ cgexpr(Cg *c, Node *n, Local *locals) break; } default: - /* unknown compound: legacy fallback — - * store rhs only. */ - ins2(c, A_MOVQ, areg(D_CX), areg(D_AX)); - break; + /* all 10 compound tokens enumerated + * above — an 11th means a parser/ + * checker gap, never a plain store + * of rhs (rule 7). */ + fatal("deref compound: unknown " + "compound op (rule 7)"); } ins2(c, store_op, areg(D_AX), amem(D_BX, 0)); break; @@ -8364,7 +8361,6 @@ cgexpr(Cg *c, Node *n, Local *locals) ins2(c, glop, amem(D_CX, 0), areg(D_BX)); } - int did_compound = 1; switch (n->op) { case TK_PLUSEQ: ins2(c, A_ADDQ, areg(D_AX), areg(D_BX)); break; case TK_MINUSEQ: ins2(c, A_SUBQ, areg(D_AX), areg(D_BX)); break; @@ -8410,16 +8406,13 @@ cgexpr(Cg *c, Node *n, Local *locals) break; } default: - /* unknown compound: legacy fallback — - * store rhs only. */ - did_compound = 0; - ins2(c, A_MOVQ, areg(D_AX), - masym(c, n->lhs->str)); - break; + /* all 10 compound tokens enumerated + * above (rule 7). */ + fatal("global compound: unknown " + "compound op (rule 7)"); } - if (did_compound) - ins2(c, A_MOVQ, areg(D_BX), - masym(c, n->lhs->str)); + ins2(c, A_MOVQ, areg(D_BX), + masym(c, n->lhs->str)); break; } cgexpr(c, n->rhs, locals); @@ -8490,12 +8483,12 @@ cgexpr(Cg *c, Node *n, Local *locals) break; } default: - /* unknown: just store rhs (legacy fallback) */ - ins2(c, A_MOVQ, areg(D_AX), amem(D_BP, off)); - goto skip_assign_store; + /* all 10 compound tokens enumerated above + * (rule 7). */ + fatal("local compound: unknown compound op " + "(rule 7)"); } ins2(c, A_MOVQ, areg(D_BX), amem(D_BP, off)); - skip_assign_store: ; } /* C1 residual (task #22): a non-DOT lvalue no arm above * matched still falls out SILENT here — the known member is diff --git a/cmd/wcc/check.c b/cmd/wcc/check.c index 547a7c24..e28db632 100644 --- a/cmd/wcc/check.c +++ b/cmd/wcc/check.c @@ -1282,6 +1282,11 @@ cbinop(Checker *c, Node *n) return ty_i64; if (!type_isnum(l) || !type_isnum(r)) return err(c, n->pos, "arithmetic on non-numeric type"); + /* % is integer-only (harec check.c binarithm BIN_MODULO): + * floats have no SSE modulo lowering, so an admitted float % + * fell through cgen half-lowered (cs!=ww divergence). */ + if (n->op == TK_PERCENT && (!type_isint(l) || !type_isint(r))) + return err(c, n->pos, "modulo on non-integer type"); return unify_arith(c, n->pos, l, r); case TK_AMP: case TK_PIPE: case TK_CARET: case TK_LSHIFT: case TK_RSHIFT: @@ -2016,6 +2021,32 @@ cexpr(Checker *c, Node *n) !assignable_addrfn(c, l, n->rhs)) err(c, n->pos, "cannot assign %s to %s", type_name(c->a, r), type_name(c->a, l)); + /* Compound ops carry their binary op's operand class (harec + * check.c binarithm): += -= *= /= need numeric operands, + * %= modulo-integer, the bitwise/shift five integer. The + * assignability check above cannot see the op, so `f %= x` + * and `s += "x"` passed and cgen's fallback plain-stored the + * rhs, silently dropping the operation. */ + if (n->op != TK_ASSIGN && l != ty_err && r != ty_err) { + switch (n->op) { + case TK_PLUSEQ: case TK_MINUSEQ: case TK_STAREQ: + case TK_SLASHEQ: + if (!type_isnum(l) || !type_isnum(r)) + err(c, n->pos, "arithmetic on " + "non-numeric type"); + break; + case TK_PERCENTEQ: + if (!type_isint(l) || !type_isint(r)) + err(c, n->pos, "modulo on " + "non-integer type"); + break; + default: + if (!type_isint(l) || !type_isint(r)) + err(c, n->pos, "bitwise on " + "non-integer type"); + break; + } + } /* #120: `w = 1.0` narrows the rhs literal to the lvalue's f32. */ coerce_floatlit(n->rhs, l); /* #258: `s = arr` borrows the array as a full slice. diff --git a/internal/wwfixture/types.ww b/internal/wwfixture/types.ww index 1fd12037..eb713adb 100644 --- a/internal/wwfixture/types.ww +++ b/internal/wwfixture/types.ww @@ -1,13 +1,13 @@ package wwfixture; def protocolversion: i32 = 1; -def corpuscount: i32 = 1746; -def errorcount: i32 = 346; +def corpuscount: i32 = 1749; +def errorcount: i32 = 349; def compilecount: i32 = 21; def runcount: i32 = 209; def runexitcount: i32 = 1170; -def nativecount: i32 = 3492; -def corpushash: str = "6afbab274e0c6d1479a2f0cb6e575b14f5e4ffd25a9cb8a3701307db97d3c489"; +def nativecount: i32 = 3498; +def corpushash: str = "616b3e7f4fca31cb99409c58a29ac73623c997967ddd57651a1370c2c2e2be6a"; type directive = enum i32 { ERROR = 0, diff --git a/selfhost/cmd/wcc/cgenexpr.ww b/selfhost/cmd/wcc/cgenexpr.ww index 119b734f..38a041ad 100644 --- a/selfhost/cmd/wcc/cgenexpr.ww +++ b/selfhost/cmd/wcc/cgenexpr.ww @@ -9322,6 +9322,15 @@ fn cgassign(c: *cgen, n: *syntax.node) void = { else { combineop = "SARQ"; }; }; }; }; }; }; }; }; }; + // all 10 compound tokens enumerated above + // (/= %= returned earlier) — a MOVQ + // combineop is the old rhs-plain-store + // legacy fallback. Rule 7. + if (syntax.streq(combineop, "MOVQ")) { + let mdc: str = "deref compound: unknown compound op (rule 7)\n"; + os.write(2, mdc.ptr, mdc.len: u64); + os.exit(1); + }; emitline("\t"); emitline(combineop); emitline("\tCX, AX\n"); @@ -12555,12 +12564,14 @@ fn cgassign(c: *cgen, n: *syntax.node) void = { if (n.op == syntax.tkind.TK_STAREQ) { fop = mulf; }; if (n.op == syntax.tkind.TK_SLASHEQ) { fop = divf; }; if (fop.len == 0) { - // Unsupported (e.g., %= on float): - // fall back to plain store of rhs. - emitline("\t"); - emitline(mov); - emitline("\tX0, (CX)\n"); - return; + // Non-SSE compound on a float lvalue is + // checker-rejected (modulo/bitwise + // integer-only); a survivor here means a + // checker gap — loud, never the old + // plain-store of rhs that dropped the op. + let mfc: str = "float compound: op has no SSE lowering (rule 7)\n"; + os.write(2, mfc.ptr, mfc.len: u64); + os.exit(1); }; emitline("\t"); emitline(mov); @@ -12722,7 +12733,6 @@ fn cgassign(c: *cgen, n: *syntax.node) void = { emitline(glop); emitline("\t(CX), BX\n"); }; - let didcompound: bool = true; if (n.op == syntax.tkind.TK_PLUSEQ) { emitline("\tADDQ\tAX, BX\n"); } else { if (n.op == syntax.tkind.TK_MINUSEQ) { emitline("\tSUBQ\tAX, BX\n"); } else { if (n.op == syntax.tkind.TK_STAREQ) { emitline("\tIMULQ\tAX, BX\n"); } @@ -12778,19 +12788,15 @@ fn cgassign(c: *cgen, n: *syntax.node) void = { }; } else { - // Unsupported compound: store rhs - // directly. Mirrors the local path's - // legacy fallback for unknown ops. - didcompound = false; - emitline("\tMOVQ\tAX, "); - emitsymname(c, nm); - emitline("(SB)\n"); + // all 10 compound tokens enumerated + // above (rule 7). + let mgc: str = "global compound: unknown compound op (rule 7)\n"; + os.write(2, mgc.ptr, mgc.len: u64); + os.exit(1); };};};};};};};};}; - if (didcompound) { - emitline("\tMOVQ\tBX, "); - emitsymname(c, nm); - emitline("(SB)\n"); - }; + emitline("\tMOVQ\tBX, "); + emitsymname(c, nm); + emitline("(SB)\n"); return; }; // #10 Fold B: over-cap tuple reassign `t = f();`. t's @@ -12978,12 +12984,14 @@ fn cgassign(c: *cgen, n: *syntax.node) void = { if (n.op == syntax.tkind.TK_STAREQ) { fop = mulf; }; if (n.op == syntax.tkind.TK_SLASHEQ) { fop = divf; }; if (fop.len == 0) { - emitline("\t"); - emitline(mov); - emitline("\tX0, "); - emitoff(off: i64); - emitline("(BP)\n"); - return; + // Non-SSE compound on a float lvalue is + // checker-rejected (modulo/bitwise + // integer-only); a survivor here means a + // checker gap — loud, never the old + // plain-store of rhs that dropped the op. + let mfc: str = "float compound: op has no SSE lowering (rule 7)\n"; + os.write(2, mfc.ptr, mfc.len: u64); + os.exit(1); }; emitline("\t"); emitline(mov); @@ -13156,6 +13164,18 @@ fn cgassign(c: *cgen, n: *syntax.node) void = { emitline("\tMOVQ\tDX, BX\n"); }; }; + // all 10 compound tokens enumerated above — an 11th + // stored the untouched loaded value back (silent + // no-op). Rule 7. + if (n.op != syntax.tkind.TK_PLUSEQ && n.op != syntax.tkind.TK_MINUSEQ + && n.op != syntax.tkind.TK_STAREQ && n.op != syntax.tkind.TK_AMPEQ + && n.op != syntax.tkind.TK_PIPEEQ && n.op != syntax.tkind.TK_CARETEQ + && n.op != syntax.tkind.TK_LSHIFTEQ && n.op != syntax.tkind.TK_RSHIFTEQ + && n.op != syntax.tkind.TK_SLASHEQ && n.op != syntax.tkind.TK_PERCENTEQ) { + let mlc: str = "local compound: unknown compound op (rule 7)\n"; + os.write(2, mlc.ptr, mlc.len: u64); + os.exit(1); + }; emitline("\tMOVQ\tBX, "); emitoff(off: i64); emitline("(BP)\n"); diff --git a/selfhost/cmd/wcc/check.ww b/selfhost/cmd/wcc/check.ww index 0a4c746f..36924435 100644 --- a/selfhost/cmd/wcc/check.ww +++ b/selfhost/cmd/wcc/check.ww @@ -3069,6 +3069,15 @@ fn binoptype(c: *checker, e: *syntax.node) *syntax.node = { (rtn != nil && !numkindast(c, rtn))) { deffolderr(c, e, "arithmetic on non-numeric type"); }; + // % is integer-only (harec check.c binarithm BIN_MODULO): + // floats have no SSE modulo lowering, so an admitted float % + // fell through cgen half-lowered (cs!=ww divergence). + if (op == syntax.tkind.TK_PERCENT) { + if ((ltn != nil && !intkindast(c, ltn)) || + (rtn != nil && !intkindast(c, rtn))) { + deffolderr(c, e, "modulo on non-integer type"); + }; + }; return unifyarith(c, e, ltn, rtn); }; if (op == syntax.tkind.TK_AMP || op == syntax.tkind.TK_PIPE || @@ -6137,6 +6146,34 @@ fn checkassign(c: *checker, n: *syntax.node) void = { }; let ltn: *syntax.node = exprtype(c, n.lhs, nil); let rtn: *syntax.node = exprtype(c, n.rhs, nil); + // Compound ops carry their binary op's operand class (harec + // check.c binarithm): += -= *= /= need numeric operands, + // %= modulo-integer, the bitwise/shift five integer. Without + // this `f %= x` and `s += "x"` passed and cgen's fallback + // plain-stored the rhs, silently dropping the operation. + // Mirror cstage cmd/wcc/check.c N_ASSIGN compound gate. + if (n.op != syntax.tkind.TK_ASSIGN) { + if (n.op == syntax.tkind.TK_PLUSEQ || n.op == syntax.tkind.TK_MINUSEQ || + n.op == syntax.tkind.TK_STAREQ || n.op == syntax.tkind.TK_SLASHEQ) { + if ((ltn != nil && !numkindast(c, ltn)) || + (rtn != nil && !numkindast(c, rtn))) { + cerr("error: arithmetic on non-numeric type\n"); + c.errs += 1; + }; + } else { if (n.op == syntax.tkind.TK_PERCENTEQ) { + if ((ltn != nil && !intkindast(c, ltn)) || + (rtn != nil && !intkindast(c, rtn))) { + cerr("error: modulo on non-integer type\n"); + c.errs += 1; + }; + } else { + if ((ltn != nil && !intkindast(c, ltn)) || + (rtn != nil && !intkindast(c, rtn))) { + cerr("error: bitwise on non-integer type\n"); + c.errs += 1; + }; + }; }; + }; // #120: `w = 1.0` narrows the rhs literal to the lvalue's f32. Mirror // cstage cmd/wcc/check.c N_ASSIGN coerce_floatlit. coercefloatlit(c, n.rhs, ltn); diff --git a/test/wcc/data/dotfield_compound_slice/case.ww b/test/wcc/data/dotfield_compound_slice/case.ww index 83c20396..2b331fb6 100644 --- a/test/wcc/data/dotfield_compound_slice/case.ww +++ b/test/wcc/data/dotfield_compound_slice/case.ww @@ -1,4 +1,4 @@ -//ww:error "single-dot field compound on slice field" +//ww:error "arithmetic on non-numeric type" // Lifted from test/wcc/949_dotfield_compound_run.c reject row "dotfld_he_slice" // (#34/rule-7): a compound assign on a single-dot SLICE field is unwired in // both stages and MUST loud-fail. The substring is the shared diagnostic body diff --git a/test/wcc/data/dotfield_compound_str/case.ww b/test/wcc/data/dotfield_compound_str/case.ww index dd1e255e..f91dcef6 100644 --- a/test/wcc/data/dotfield_compound_str/case.ww +++ b/test/wcc/data/dotfield_compound_str/case.ww @@ -1,4 +1,4 @@ -//ww:error "single-dot field compound on str field" +//ww:error "arithmetic on non-numeric type" // Lifted from test/wcc/949_dotfield_compound_run.c reject row "dotfld_he_str" // (#34/rule-7): a compound assign on a single-dot STR field is unwired in both // stages and MUST loud-fail. The substring is the shared diagnostic body — diff --git a/test/wcc/data/dotfield_compound_tagged/case.ww b/test/wcc/data/dotfield_compound_tagged/case.ww index a9fcfc2a..07a00ae9 100644 --- a/test/wcc/data/dotfield_compound_tagged/case.ww +++ b/test/wcc/data/dotfield_compound_tagged/case.ww @@ -1,4 +1,4 @@ -//ww:error "single-dot field compound on tagged field" +//ww:error "arithmetic on non-numeric type" // Lifted from test/wcc/949_dotfield_compound_run.c reject row "dotfld_he_tagged" // (#34/rule-7): a compound assign on a single-dot TAGGED-union field is unwired // in both stages and MUST loud-fail. The substring is the shared diagnostic diff --git a/test/wcc/data/float_mod_reject/case.ww b/test/wcc/data/float_mod_reject/case.ww new file mode 100644 index 00000000..09e3951c --- /dev/null +++ b/test/wcc/data/float_mod_reject/case.ww @@ -0,0 +1,11 @@ +//ww:error "modulo on non-integer type" +// % is integer-only (harec check.c binarithm BIN_MODULO). Pre-gate a +// float % half-lowered through cgen as a live cs!=ww divergence. +package main; +export fn main() i32 = { + let a: f64 = 7.0; + let b: f64 = 2.0; + let m: f64 = a % b; + if (m == 1.0) { return 1; }; + return 0; +}; diff --git a/test/wcc/data/float_modeq_reject/case.ww b/test/wcc/data/float_modeq_reject/case.ww new file mode 100644 index 00000000..1e682610 --- /dev/null +++ b/test/wcc/data/float_modeq_reject/case.ww @@ -0,0 +1,12 @@ +//ww:error "modulo on non-integer type" +// Compound ops carry their binary op's operand class: %= on a float +// lvalue plain-stored the rhs pre-gate (`a %= 2.0` became `a = 2.0`, +// silently, both stages). +package main; +let g: f64 = 9.0; +export fn main() i32 = { + let a: f64 = 7.0; + a %= 2.0; + g %= 2.0; + return 0; +}; diff --git a/test/wcc/data/idx_compound_str_indexed/case.ww b/test/wcc/data/idx_compound_str_indexed/case.ww index f984210f..4f670952 100644 --- a/test/wcc/data/idx_compound_str_indexed/case.ww +++ b/test/wcc/data/idx_compound_str_indexed/case.ww @@ -1,4 +1,4 @@ -//ww:error "indexed-lvalue compound on str element not wired (#133/rule-7)" +//ww:error "arithmetic on non-numeric type" // Lifted from test/wcc/948_idx_compound_run.c reject row "he_str_indexed" // (#133-expanded rule-7): a compound assign on an indexed STR element is // unwired in both stages and MUST loud-fail. The substring is the FULL shared diff --git a/test/wcc/data/idxfield_compound_slice/case.ww b/test/wcc/data/idxfield_compound_slice/case.ww index 7654b61f..aa7940fe 100644 --- a/test/wcc/data/idxfield_compound_slice/case.ww +++ b/test/wcc/data/idxfield_compound_slice/case.ww @@ -1,4 +1,4 @@ -//ww:error "arr[i].field compound on slice field" +//ww:error "arithmetic on non-numeric type" // Lifted from test/wcc/949_idxfield_compound_run.c reject row "fld_he_slice" // (#33/rule-7): a compound assign on an indexed-element SLICE field is unwired // in both stages and MUST loud-fail. The substring is the shared diagnostic diff --git a/test/wcc/data/idxfield_compound_str/case.ww b/test/wcc/data/idxfield_compound_str/case.ww index edcfed34..5ae339ea 100644 --- a/test/wcc/data/idxfield_compound_str/case.ww +++ b/test/wcc/data/idxfield_compound_str/case.ww @@ -1,4 +1,4 @@ -//ww:error "arr[i].field compound on str field" +//ww:error "arithmetic on non-numeric type" // Lifted from test/wcc/949_idxfield_compound_run.c reject row "fld_he_str" // (#33/rule-7): a compound assign on an indexed-element STR field is unwired in // both stages and MUST loud-fail. The substring is the shared diagnostic body diff --git a/test/wcc/data/idxfield_compound_tagged/case.ww b/test/wcc/data/idxfield_compound_tagged/case.ww index deacb0b5..24e9ed26 100644 --- a/test/wcc/data/idxfield_compound_tagged/case.ww +++ b/test/wcc/data/idxfield_compound_tagged/case.ww @@ -1,4 +1,4 @@ -//ww:error "arr[i].field compound on tagged field" +//ww:error "arithmetic on non-numeric type" // Lifted from test/wcc/949_idxfield_compound_run.c reject row "fld_he_tagged" // (#33/rule-7): a compound assign on an indexed-element TAGGED-union field is // unwired in both stages and MUST loud-fail. The substring is the shared diff --git a/test/wcc/data/r805_reject_agg_compound/case.ww b/test/wcc/data/r805_reject_agg_compound/case.ww index 2e4c3630..58e30f29 100644 --- a/test/wcc/data/r805_reject_agg_compound/case.ww +++ b/test/wcc/data/r805_reject_agg_compound/case.ww @@ -1,4 +1,4 @@ -//ww:error "assign-resolver: compound on aggregate field not wired (rule-7)" +//ww:error "arithmetic on non-numeric type" package main; type capture = struct { content: str, start: size, end: size }; type t = struct { pc: size, cap: capture }; diff --git a/test/wcc/data/r805_reject_str_compound/case.ww b/test/wcc/data/r805_reject_str_compound/case.ww index 7d17daaa..a25d6868 100644 --- a/test/wcc/data/r805_reject_str_compound/case.ww +++ b/test/wcc/data/r805_reject_str_compound/case.ww @@ -1,4 +1,4 @@ -//ww:error "assign-resolver: compound on str/slice field not wired (rule-7)" +//ww:error "arithmetic on non-numeric type" package main; type t = struct { pc: size, name: str }; fn addname(ts: *[]t, i: size) void = { (*ts)[i].name += "x"; }; diff --git a/test/wcc/data/r989_tagderef_ampeq_tagged_deref/case.ww b/test/wcc/data/r989_tagderef_ampeq_tagged_deref/case.ww index b90baa0c..1309b601 100644 --- a/test/wcc/data/r989_tagderef_ampeq_tagged_deref/case.ww +++ b/test/wcc/data/r989_tagderef_ampeq_tagged_deref/case.ww @@ -1,4 +1,4 @@ -//ww:error "assign-resolver: tagged field not wired (rule-7)" +//ww:error "bitwise on non-integer type" package main; export fn main() int = { let v: (int | bool) = 7; diff --git a/test/wcc/data/r989_tagderef_careteq_tagged_deref/case.ww b/test/wcc/data/r989_tagderef_careteq_tagged_deref/case.ww index 70d5c69a..4aacfc48 100644 --- a/test/wcc/data/r989_tagderef_careteq_tagged_deref/case.ww +++ b/test/wcc/data/r989_tagderef_careteq_tagged_deref/case.ww @@ -1,4 +1,4 @@ -//ww:error "assign-resolver: tagged field not wired (rule-7)" +//ww:error "bitwise on non-integer type" package main; export fn main() int = { let v: (int | bool) = 7; diff --git a/test/wcc/data/r989_tagderef_lshifteq_tagged_deref/case.ww b/test/wcc/data/r989_tagderef_lshifteq_tagged_deref/case.ww index 0db39392..b757237a 100644 --- a/test/wcc/data/r989_tagderef_lshifteq_tagged_deref/case.ww +++ b/test/wcc/data/r989_tagderef_lshifteq_tagged_deref/case.ww @@ -1,4 +1,4 @@ -//ww:error "assign-resolver: tagged field not wired (rule-7)" +//ww:error "bitwise on non-integer type" package main; export fn main() int = { let v: (int | bool) = 7; diff --git a/test/wcc/data/r989_tagderef_minuseq_tagged_deref/case.ww b/test/wcc/data/r989_tagderef_minuseq_tagged_deref/case.ww index 46057ce4..1ab7bd0d 100644 --- a/test/wcc/data/r989_tagderef_minuseq_tagged_deref/case.ww +++ b/test/wcc/data/r989_tagderef_minuseq_tagged_deref/case.ww @@ -1,4 +1,4 @@ -//ww:error "assign-resolver: tagged field not wired (rule-7)" +//ww:error "arithmetic on non-numeric type" package main; export fn main() int = { let v: (int | bool) = 7; diff --git a/test/wcc/data/r989_tagderef_percenteq_tagged_deref/case.ww b/test/wcc/data/r989_tagderef_percenteq_tagged_deref/case.ww index e6df8d9c..b71e3a33 100644 --- a/test/wcc/data/r989_tagderef_percenteq_tagged_deref/case.ww +++ b/test/wcc/data/r989_tagderef_percenteq_tagged_deref/case.ww @@ -1,4 +1,4 @@ -//ww:error "assign-resolver: tagged field not wired (rule-7)" +//ww:error "modulo on non-integer type" package main; export fn main() int = { let v: (int | bool) = 7; diff --git a/test/wcc/data/r989_tagderef_pipeeq_tagged_deref/case.ww b/test/wcc/data/r989_tagderef_pipeeq_tagged_deref/case.ww index 26015cec..306d487f 100644 --- a/test/wcc/data/r989_tagderef_pipeeq_tagged_deref/case.ww +++ b/test/wcc/data/r989_tagderef_pipeeq_tagged_deref/case.ww @@ -1,4 +1,4 @@ -//ww:error "assign-resolver: tagged field not wired (rule-7)" +//ww:error "bitwise on non-integer type" package main; export fn main() int = { let v: (int | bool) = 7; diff --git a/test/wcc/data/r989_tagderef_pluseq_tagged_deref/case.ww b/test/wcc/data/r989_tagderef_pluseq_tagged_deref/case.ww index 1674bb75..b0f6c5c5 100644 --- a/test/wcc/data/r989_tagderef_pluseq_tagged_deref/case.ww +++ b/test/wcc/data/r989_tagderef_pluseq_tagged_deref/case.ww @@ -1,4 +1,4 @@ -//ww:error "assign-resolver: tagged field not wired (rule-7)" +//ww:error "arithmetic on non-numeric type" package main; export fn main() int = { let v: (int | bool) = 7; diff --git a/test/wcc/data/r989_tagderef_rshifteq_tagged_deref/case.ww b/test/wcc/data/r989_tagderef_rshifteq_tagged_deref/case.ww index 0063820b..7cd591a4 100644 --- a/test/wcc/data/r989_tagderef_rshifteq_tagged_deref/case.ww +++ b/test/wcc/data/r989_tagderef_rshifteq_tagged_deref/case.ww @@ -1,4 +1,4 @@ -//ww:error "assign-resolver: tagged field not wired (rule-7)" +//ww:error "bitwise on non-integer type" package main; export fn main() int = { let v: (int | bool) = 7; diff --git a/test/wcc/data/r989_tagderef_slasheq_tagged_deref/case.ww b/test/wcc/data/r989_tagderef_slasheq_tagged_deref/case.ww index 688c5517..18a25520 100644 --- a/test/wcc/data/r989_tagderef_slasheq_tagged_deref/case.ww +++ b/test/wcc/data/r989_tagderef_slasheq_tagged_deref/case.ww @@ -1,4 +1,4 @@ -//ww:error "assign-resolver: tagged field not wired (rule-7)" +//ww:error "arithmetic on non-numeric type" package main; export fn main() int = { let v: (int | bool) = 7; diff --git a/test/wcc/data/r989_tagderef_stareq_tagged_deref/case.ww b/test/wcc/data/r989_tagderef_stareq_tagged_deref/case.ww index 8ee05b00..d5a14bd9 100644 --- a/test/wcc/data/r989_tagderef_stareq_tagged_deref/case.ww +++ b/test/wcc/data/r989_tagderef_stareq_tagged_deref/case.ww @@ -1,4 +1,4 @@ -//ww:error "assign-resolver: tagged field not wired (rule-7)" +//ww:error "arithmetic on non-numeric type" package main; export fn main() int = { let v: (int | bool) = 7; diff --git a/test/wcc/data/r989_tagplace_gident_pluseq/case.ww b/test/wcc/data/r989_tagplace_gident_pluseq/case.ww index 1ca21ff6..ee91c79e 100644 --- a/test/wcc/data/r989_tagplace_gident_pluseq/case.ww +++ b/test/wcc/data/r989_tagplace_gident_pluseq/case.ww @@ -1,4 +1,4 @@ -//ww:error "ident compound on tagged not wired (#21/rule-7)" +//ww:error "arithmetic on non-numeric type" package main; let g: (int | bool) = 7; export fn main() int = { g += 1; return 0; }; diff --git a/test/wcc/data/r989_tagplace_gidx_careteq/case.ww b/test/wcc/data/r989_tagplace_gidx_careteq/case.ww index 89ad1514..86358835 100644 --- a/test/wcc/data/r989_tagplace_gidx_careteq/case.ww +++ b/test/wcc/data/r989_tagplace_gidx_careteq/case.ww @@ -1,4 +1,4 @@ -//ww:error "indexed-lvalue compound on tagged element not wired (#133/rule-7)" +//ww:error "bitwise on non-integer type" package main; let gs: [3](int | bool) = [1, 2, 3]; export fn main() int = { gs[0] ^= 1; return 0; }; diff --git a/test/wcc/data/r989_tagplace_gidx_pluseq/case.ww b/test/wcc/data/r989_tagplace_gidx_pluseq/case.ww index 5d6b34c3..cdfeba66 100644 --- a/test/wcc/data/r989_tagplace_gidx_pluseq/case.ww +++ b/test/wcc/data/r989_tagplace_gidx_pluseq/case.ww @@ -1,4 +1,4 @@ -//ww:error "indexed-lvalue compound on tagged element not wired (#133/rule-7)" +//ww:error "arithmetic on non-numeric type" package main; let gs: [3](int | bool) = [1, 2, 3]; export fn main() int = { gs[0] += 1; return 0; }; diff --git a/test/wcc/data/r989_tagplace_gidx_stareq/case.ww b/test/wcc/data/r989_tagplace_gidx_stareq/case.ww index ffaf9aaf..2a453277 100644 --- a/test/wcc/data/r989_tagplace_gidx_stareq/case.ww +++ b/test/wcc/data/r989_tagplace_gidx_stareq/case.ww @@ -1,4 +1,4 @@ -//ww:error "indexed-lvalue compound on tagged element not wired (#133/rule-7)" +//ww:error "arithmetic on non-numeric type" package main; let gs: [3](int | bool) = [1, 2, 3]; export fn main() int = { gs[0] *= 1; return 0; }; diff --git a/test/wcc/data/r989_tagplace_ident_careteq/case.ww b/test/wcc/data/r989_tagplace_ident_careteq/case.ww index 5a17e05e..8f5f185d 100644 --- a/test/wcc/data/r989_tagplace_ident_careteq/case.ww +++ b/test/wcc/data/r989_tagplace_ident_careteq/case.ww @@ -1,3 +1,3 @@ -//ww:error "ident compound on tagged not wired (#21/rule-7)" +//ww:error "bitwise on non-integer type" package main; export fn main() int = { let g: (int | bool) = 7; g ^= 1; return 0; }; diff --git a/test/wcc/data/r989_tagplace_ident_lshifteq/case.ww b/test/wcc/data/r989_tagplace_ident_lshifteq/case.ww index b61f0e11..805713f0 100644 --- a/test/wcc/data/r989_tagplace_ident_lshifteq/case.ww +++ b/test/wcc/data/r989_tagplace_ident_lshifteq/case.ww @@ -1,3 +1,3 @@ -//ww:error "ident compound on tagged not wired (#21/rule-7)" +//ww:error "bitwise on non-integer type" package main; export fn main() int = { let g: (int | bool) = 7; g <<= 1; return 0; }; diff --git a/test/wcc/data/r989_tagplace_ident_minuseq/case.ww b/test/wcc/data/r989_tagplace_ident_minuseq/case.ww index ff7a8128..17190365 100644 --- a/test/wcc/data/r989_tagplace_ident_minuseq/case.ww +++ b/test/wcc/data/r989_tagplace_ident_minuseq/case.ww @@ -1,3 +1,3 @@ -//ww:error "ident compound on tagged not wired (#21/rule-7)" +//ww:error "arithmetic on non-numeric type" package main; export fn main() int = { let g: (int | bool) = 7; g -= 1; return 0; }; diff --git a/test/wcc/data/r989_tagplace_ident_pipeeq/case.ww b/test/wcc/data/r989_tagplace_ident_pipeeq/case.ww index c6b166ec..49d04c86 100644 --- a/test/wcc/data/r989_tagplace_ident_pipeeq/case.ww +++ b/test/wcc/data/r989_tagplace_ident_pipeeq/case.ww @@ -1,3 +1,3 @@ -//ww:error "ident compound on tagged not wired (#21/rule-7)" +//ww:error "bitwise on non-integer type" package main; export fn main() int = { let g: (int | bool) = 7; g |= 1; return 0; }; diff --git a/test/wcc/data/r989_tagplace_ident_pluseq/case.ww b/test/wcc/data/r989_tagplace_ident_pluseq/case.ww index f808e290..a36ad338 100644 --- a/test/wcc/data/r989_tagplace_ident_pluseq/case.ww +++ b/test/wcc/data/r989_tagplace_ident_pluseq/case.ww @@ -1,3 +1,3 @@ -//ww:error "ident compound on tagged not wired (#21/rule-7)" +//ww:error "arithmetic on non-numeric type" package main; export fn main() int = { let g: (int | bool) = 7; g += 1; return 0; }; diff --git a/test/wcc/data/r989_tagplace_ident_slasheq/case.ww b/test/wcc/data/r989_tagplace_ident_slasheq/case.ww index 296776e5..6a34de19 100644 --- a/test/wcc/data/r989_tagplace_ident_slasheq/case.ww +++ b/test/wcc/data/r989_tagplace_ident_slasheq/case.ww @@ -1,3 +1,3 @@ -//ww:error "ident compound on tagged not wired (#21/rule-7)" +//ww:error "arithmetic on non-numeric type" package main; export fn main() int = { let g: (int | bool) = 7; g /= 1; return 0; }; diff --git a/test/wcc/data/r989_tagplace_ident_stareq/case.ww b/test/wcc/data/r989_tagplace_ident_stareq/case.ww index b24c55b8..57ccc7ae 100644 --- a/test/wcc/data/r989_tagplace_ident_stareq/case.ww +++ b/test/wcc/data/r989_tagplace_ident_stareq/case.ww @@ -1,3 +1,3 @@ -//ww:error "ident compound on tagged not wired (#21/rule-7)" +//ww:error "arithmetic on non-numeric type" package main; export fn main() int = { let g: (int | bool) = 7; g *= 1; return 0; }; diff --git a/test/wcc/data/r989_tagplace_lidx_lshifteq/case.ww b/test/wcc/data/r989_tagplace_lidx_lshifteq/case.ww index 8bd0502b..1f5be4f5 100644 --- a/test/wcc/data/r989_tagplace_lidx_lshifteq/case.ww +++ b/test/wcc/data/r989_tagplace_lidx_lshifteq/case.ww @@ -1,4 +1,4 @@ -//ww:error "indexed-lvalue compound on tagged element not wired (#133/rule-7)" +//ww:error "bitwise on non-integer type" package main; export fn main() int = { let a: [3](int | bool) = [1, 2, 3]; diff --git a/test/wcc/data/r989_tagplace_lidx_minuseq/case.ww b/test/wcc/data/r989_tagplace_lidx_minuseq/case.ww index fb1a37d6..e25aeb32 100644 --- a/test/wcc/data/r989_tagplace_lidx_minuseq/case.ww +++ b/test/wcc/data/r989_tagplace_lidx_minuseq/case.ww @@ -1,4 +1,4 @@ -//ww:error "indexed-lvalue compound on tagged element not wired (#133/rule-7)" +//ww:error "arithmetic on non-numeric type" package main; export fn main() int = { let a: [3](int | bool) = [1, 2, 3]; diff --git a/test/wcc/data/r989_tagplace_lidx_pipeeq/case.ww b/test/wcc/data/r989_tagplace_lidx_pipeeq/case.ww index bfe41f28..0c5cbc6e 100644 --- a/test/wcc/data/r989_tagplace_lidx_pipeeq/case.ww +++ b/test/wcc/data/r989_tagplace_lidx_pipeeq/case.ww @@ -1,4 +1,4 @@ -//ww:error "indexed-lvalue compound on tagged element not wired (#133/rule-7)" +//ww:error "bitwise on non-integer type" package main; export fn main() int = { let a: [3](int | bool) = [1, 2, 3]; diff --git a/test/wcc/data/r989_tagplace_lidx_pluseq/case.ww b/test/wcc/data/r989_tagplace_lidx_pluseq/case.ww index d8740503..d6ae0b02 100644 --- a/test/wcc/data/r989_tagplace_lidx_pluseq/case.ww +++ b/test/wcc/data/r989_tagplace_lidx_pluseq/case.ww @@ -1,4 +1,4 @@ -//ww:error "indexed-lvalue compound on tagged element not wired (#133/rule-7)" +//ww:error "arithmetic on non-numeric type" package main; export fn main() int = { let a: [3](int | bool) = [1, 2, 3]; diff --git a/test/wcc/data/str_pluseq_reject/case.ww b/test/wcc/data/str_pluseq_reject/case.ww new file mode 100644 index 00000000..0a172624 --- /dev/null +++ b/test/wcc/data/str_pluseq_reject/case.ww @@ -0,0 +1,9 @@ +//ww:error "arithmetic on non-numeric type" +// += needs numeric operands; `s += "cd"` passed the op-blind +// assignability check and cgen garbled the header words silently. +package main; +export fn main() i32 = { + let s: str = "ab"; + s += "cd"; + return 0; +};