Unifying the two engines exposed what the split had been hiding: every rule
that lived only in the M6 body was silently dropped for units the M7 half
claimed, and since M1-M6 sources never reached that half, nothing failed until
they all did. Eleven cases across m3, m5 and m6 caught it.
Checker, all from the M6 statement and lvalue cases:
- writing a struct field needs a writable place, so `p.x = 3` on a `let` is an
error again (m3-badfield)
- `let` cannot bind a mutable slice, a var with no initializer needs a type,
and a void expression cannot initialize (m3-bad-mlet)
- a returned reference must derive from a parameter or a static, and a void
expression cannot be returned from a value function (m6-badarg, badret,
badself, badtwo, badlocsl)
- rebinding a reference must not outlive its source scope, and must release the
previous borrow (m6-badscop)
- the loop case delegates to the core, which carries the flow capture and merge
that detects a value moved on every iteration; the M7 version had none of it
(m5-bad-loop)
Emitter:
- builtins other than the print family (@size_of, @align_of) and the str alias
methods are lowered by the core, which the M7 call path never reached, so
they were emitted verbatim into the C (m3-struct)
- the trim helper is emitted from the M7 type-helper pass as well, not only the
core one, or the call has no definition to link (m6-oktrim)
M1-M7 all green: 16, 19, 50, 20, 16, 57, 42.