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.
This commit is contained in:
2026-08-09 00:32:41 +09:00
parent f0029227b5
commit f191e6e0e2
42 changed files with 206 additions and 93 deletions

View File

@@ -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

View File

@@ -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 —

View File

@@ -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

View File

@@ -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;
};

View File

@@ -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;
};

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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 };

View File

@@ -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"; };

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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; };

View File

@@ -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; };

View File

@@ -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; };

View File

@@ -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; };

View File

@@ -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; };

View File

@@ -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; };

View File

@@ -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; };

View File

@@ -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; };

View File

@@ -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; };

View File

@@ -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; };

View File

@@ -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; };

View File

@@ -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];

View File

@@ -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];

View File

@@ -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];

View File

@@ -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];

View File

@@ -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;
};