fix(ir): float / folds as FLOAT division under the unified narrowing rule — int folder refuses a float-operand / [F0.11]
The shared compile-time integer folder (`evalConstIntExpr`) accepts an integral float literal/const as an integer leaf (`[4.0]` → 4) and then applied INTEGER arithmetic to the whole expression — so `5.0 / 2.0` folded as `divTrunc(5,2)` = 2 instead of float division (`2.5`). The bug fired at all FIVE unified-rule sites (typed local, field default, param default, typed const, array dimension), because the typed sites evaluate through `evalConstFloatExpr` (which delegates the node to the int folder) and the count sites through `foldCountI64` (int folder first). Fix at the single root: `evalConstIntExpr`'s `.div` arm refuses to fold a division whose lhs/rhs is float-valued (`isFloatValuedExpr`), so the value surfaces through `evalConstFloatExpr` + the unified rule — an integral quotient (`6.0 / 2.0` → 3) folds, a non-integral one (`5.0 / 2.0` = 2.5, mixed `5 / 2.0`, float-const `F / G`) errors. Genuine integer `/` (`5 / 2` → 2) is unchanged; `*`/`+`/`-` need no guard (they agree between int and float for the integral operands the int folder ever sees). `isFloatValuedExpr` judges a const-leaf by VALUE (`moduleConstIsFloatTyped` recurses into the const's value with the existing cycle-guard frame), so an untyped float-EXPRESSION const (`ME :: 4.0 + 1.0`, placeholder type s64) is caught at both the count path and — via `foldComptimeFloatInit`'s guard — the typed-binding path. A backtick RAW receiver (`` `f64.epsilon ``) is a field read, not a float limit (is_raw check, issues 0092/0093). Regression: examples/1147 (negative — `5.0 / 2.0` errors at all five sites plus untyped float-EXPR const div); 0168 extended (positive — `6.0 / 2.0`, `12.0 / 4.0`, `[6.0/2.0]`, `xx (5.0/2.0)` → 2); unit tests "the int folder refuses a FLOAT division" and "moduleConstIsFloatTyped judges a const by VALUE". specs.md + readme.md state the float-`/` rule.
This commit is contained in:
@@ -141,6 +141,30 @@
|
||||
> f64.max` → 0, `6.0 % 4.0` → 2, integer-limit `s8.max`/`[u8.max]` unregressed,
|
||||
> `xx` escapes for both new forms) and 1146 (negative: `f64.true_min + 0.5` and
|
||||
> `5.5 % 2.0` error at a binding site).
|
||||
>
|
||||
> **Completion (F0.11 attempt 6)** — attempt 5 reached evaluator parity for
|
||||
> leaves/operators, but a structural hole remained in the SHARED integer folder:
|
||||
> `evalConstIntExpr` accepts an integral float literal/const as an integer leaf
|
||||
> (`[4.0]` → 4) and then applies INTEGER arithmetic to the whole expression — so a
|
||||
> float DIVISION with integral-looking operands (`5.0 / 2.0`) folded as integer
|
||||
> truncating division (`divTrunc(5,2)` = 2) instead of float division (`2.5`). The
|
||||
> bug fired at ALL FIVE sites (`5.0 / 2.0` printed `2` at a typed local, field
|
||||
> default, param default, typed const, and array dimension), because the typed
|
||||
> sites evaluate through `evalConstFloatExpr` (which delegates the whole node to
|
||||
> the int folder) and the count sites through `foldCountI64` (which tries the int
|
||||
> folder first). Closed at the single root: `evalConstIntExpr`'s `.div` arm now
|
||||
> REFUSES to fold a division whose lhs/rhs is float-valued (a new
|
||||
> `isFloatValuedExpr` predicate, resolving a float-typed const leaf through each
|
||||
> ctx's `nameIsFloatTyped`) — so the division surfaces through `evalConstFloatExpr`
|
||||
> (float `/`) + the unified rule: an integral quotient (`6.0 / 2.0` → 3) folds, a
|
||||
> non-integral one (`5.0 / 2.0` = 2.5, mixed `5 / 2.0`, float-const `F / G`)
|
||||
> errors. Genuine integer `/` (`5 / 2` → 2) is unchanged; `*`/`+`/`-` need no guard
|
||||
> (they agree between int and float for the integral operands the int folder ever
|
||||
> sees). Regression: `examples/1147-diagnostics-float-division-narrowing.sx`
|
||||
> (negative — `5.0 / 2.0` errors at all five sites), the integral-`/` positives
|
||||
> added to `examples/0168` (`6.0 / 2.0` local/field, `12.0 / 4.0` const, `[6.0 /
|
||||
> 2.0]` dim, `xx (5.0 / 2.0)` → 2), and unit
|
||||
> `program_index.test.zig` "the int folder refuses a FLOAT division".
|
||||
|
||||
## Symptom
|
||||
A typed LOCAL (and likely typed param/field) silently truncates a floating-point
|
||||
|
||||
Reference in New Issue
Block a user