fix(ir): infer mixed int+float arithmetic as the promoted float [F0.7]

`ExprTyper.inferType`'s binary-op arm inferred every non-comparison op
from the LHS alone, so `M + 0.5` (s64 + f64) statically typed as s64
while `0.5 + M` typed as f64 — operand-order-dependent. The value path
(`lowerBinaryOp`) already promoted int×float → float, so static
inference disagreed with the value: `M + 0.5` formatted as a truncated
int and a typed const `BAD : s64 : M + 0.5` was accepted+truncated
(issue 0088 mixed-numeric escape).

Extract the value path's inline promotion into a shared
`Lowering.arithResultType(lhs, rhs)` and reuse it at both sites, so
arithmetic / bitwise / shift inference reports exactly the type the
lowered value carries — int LHS × float RHS → the float, order-
independent. The value-path behavior is unchanged (the block is moved
verbatim into the helper), so no IR shifts; the suite stays green. The
typed-const validation reuses `inferExprType`, so this auto-closes the
escape with no change to the validation logic.

- examples/1143: BAD/BAD2 (`s64 : M + 0.5`, `s64 : 0.5 + M`) rejected
  in both operand orders.
- examples/0162: MF/MFR (`f64 : M + 0.5`, `f64 : 0.5 + M`) fold to 2.5.
- examples/0163 (new): pins the inference fix in a value context
  (`print("{}", n + 0.5)` formats the float, both orders, +-*/, f32).
- expr_typer.test.zig: arithResultType + mixed-arithmetic inference.
- specs.md / readme.md: document the numeric-promotion rule.
- issues/0088: RESOLVED banner notes the inferExprType root fix.
This commit is contained in:
agra
2026-06-05 08:23:59 +03:00
parent 454ea06bd4
commit b69ec43ba3
14 changed files with 218 additions and 52 deletions

View File

@@ -118,7 +118,10 @@ A typed constant's initializer must be compatible with its annotation — an
integer fits any integer or float, a float a float type, a string `string`,
`null` a pointer/optional. The check is type-based, so it covers a literal and a
constant expression alike: both `N : string : 4` and `N : string : M + 2` are a
compile-time `type mismatch` error, not a silently-accepted constant.
compile-time `type mismatch` error, not a silently-accepted constant. Mixed
int+float arithmetic promotes to the float in either operand order (`n + 0.5` and
`0.5 + n` are both `f64`), so `C : s64 : M + 0.5` is rejected regardless of order
while `F : f64 : M + 0.5` folds to `2.5`.
Builtin type names (`s2`, `u8`, `bool`, `string`, …) are reserved and a *bare*
spelling can't be used as an identifier at a **value-binding or declaration-name**