You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
semantic: a numeric literal outside its own type's range is not checked before codegen — 1e400, 1e39f are SPY0599 behind Roslyn, 1e29m is a SPY0909 ICE #2340
Class tracker. Found by the P68 verify round (sibling-cell prober, C1 × literal magnitude), measured @ 0d58024 with sharpyc run.
Contract
A numeric literal whose value its own type cannot hold gets a typed refusal in semantic analysis, or an explicit spec rule (CPython gives inf for a float). It must never reach code generation. Integers already work this way: an unsuffixed literal past int64 is SPY0210 "too large for 'long'". The float32 narrowing twin does too: float_literals.md:82 says x: float32 = 1e40 is SPY0220. The literal forms below are not checked. They reach Roslyn (SPY0599) or crash the compiler (SPY0909).
SPY0909 internal compiler error (InvalidOperationException): "The decimal literal '1e29' … could not be parsed as a decimal. Semantic analysis admits a literal into a decimal slot only after checking its range…"
Open ruling: should a float64 literal past double.MaxValue be refused, or be inf as in CPython? The spec says nothing for float64. float_literals.md:82 refuses silent infinity for float32. Either way, SPY0599/SPY0909 is a bug.
Not in this class: int64/uint64 overflow is already SPY0210, which is by design.
Batching 2026-10-21 @ e7e0a0e — charter .claude/plans/remediation-round-2026-09-20-batching.md §3.0, chores band (order 0, one commit, no plan; Semantic expression typing only; seam-free with P21e, rides its gate). Ruling R-HU (owner, 2026-10-21): (a) REFUSE every numeric literal outside the range of its own resolved type at ONE semantic seam — the SPY0210 family.Ruling R-HV (owner, 2026-10-21): (a) a chore in the current band with a closed-axis theory.
Measured @ e7e0a0e (built CLI, lock-free):print(1e400) → SPY0599 "generated C# contains 1 syntax error(s): Floating-point constant is outside the range of type 'double'" (Roslyn CS0594 behind the net); print(1e29m) → SPY0909 internal compiler error InvalidOperationException whose own message (CodeGen/RoslynEmitter.Expressions.cs:796) says "Semantic analysis admits a literal into a decimal slot only after checking its range" — the emitter holds an invariant semantic does not keep; 1e39f → SPY0599 'float'. Controls: x: float32 = 1e40 → SPY0220 (float_literals.md:82, "not a silent infinity"); print(99999999999999999999) → SPY0210 "too large for any integer type". CPython 3.12.13: 1e400 → inf. Lane / reach: ice · program (rare shape). Class: the integer check and the float32 slot check exist; float64, f and m are unchecked — contract §1's position-missing-shared-check meta-class.
Mechanism (R-HU a): one range check keyed on the literal's RESOLVED type; the SPY0210 family gains "too large for 'double' / 'float' / 'decimal'"; float_literals.md gains the sentence beside line 82 and decimal likewise; DiagnosticExplanations for any new code. Guard (R-HV a): theory type {int32→int64 promotion, int64, uint32, uint64, float64, float32, decimal} × spelling {unsuffixed, suffixed, slot-narrowed} × magnitude {max, max + one ulp, far, negative}; mutation (drop the float64 arm → its rows red) in the commit body; direction record: NO program that ran changes (every cell is SPY0599/SPY0909 today) — recorded in the commit body, no fixture moves. Blast radius: Semantic → the whole gate. Class tracker: this issue.
Rejected — R-HU (b): float64 unsuffixed → inf (CPython's value, double.PositiveInfinity) with f/m refusing — two rules for one surface, and x: float = 1e400 then carries infinity into arithmetic silently; a runtime value is one-way, a refusal is relaxable to (b) later; Type Safety > Python syntax, and the spec already chose refusal for float32. R-HV (b): a P37 row — P37 is slot-DIRECTED operand totality (Some(v)/None() against a typed other operand); print(1e400) and 1e29m have no slot, so P37's generator would gain a foreign axis and an ICE would wait behind P70. Ordering two-way.
Landed (chores band 2026-10-22) on dev @ 4d22212, PR #2346 to mainline. Whole-solution gate 81669/0/7 @ 4d22212 (measured), against 81093/0/7 @ be4664e.
Commit 64ff07e (R-HU a, R-HV a).FloatLiteralClassifier.Fits(text, double|float|decimal) is the one range question. The literal-typing arm refuses a miss with SPY0210 ("too large for 'double'/'float'/'decimal'"), and the float32 and decimal narrowing predicates ask the same Fits. The SPY0210 constant is renamed NumericLiteralOutOfRange. float_literals.md gains "A Literal Must Fit Its Own Type".
Direction:
SPY0599 → SPY0210: 1e400, -1e400, 1e400d, 1e39f, the slot and pattern positions, and the parameter-default and const positions.
Sibling filed: #2344. A non-zero decimal literal below 1e-28 still gets two verdicts. 1e-30m is stored as zero, while d: decimal = 1e-30 is refused. The narrowing path keeps an underflow check the suffixed path never asks. That is a magnitude axis this issue's contract did not list, so it has its own tracker.
Activity
antonsynd commentedon Oct 22, 2026
Batching 2026-10-21 @ e7e0a0e — charter
.claude/plans/remediation-round-2026-09-20-batching.md§3.0, chores band (order 0, one commit, no plan; Semantic expression typing only; seam-free with P21e, rides its gate). Ruling R-HU (owner, 2026-10-21): (a) REFUSE every numeric literal outside the range of its own resolved type at ONE semantic seam — the SPY0210 family. Ruling R-HV (owner, 2026-10-21): (a) a chore in the current band with a closed-axis theory.Measured @ e7e0a0e (built CLI, lock-free):
print(1e400)→ SPY0599 "generated C# contains 1 syntax error(s): Floating-point constant is outside the range of type 'double'" (Roslyn CS0594 behind the net);print(1e29m)→ SPY0909 internal compiler errorInvalidOperationExceptionwhose own message (CodeGen/RoslynEmitter.Expressions.cs:796) says "Semantic analysis admits a literal into a decimal slot only after checking its range" — the emitter holds an invariant semantic does not keep;1e39f→ SPY0599 'float'. Controls:x: float32 = 1e40→ SPY0220 (float_literals.md:82, "not a silent infinity");print(99999999999999999999)→ SPY0210 "too large for any integer type". CPython 3.12.13:1e400→inf. Lane / reach: ice · program (rare shape). Class: the integer check and the float32 slot check exist; float64,fandmare unchecked — contract §1's position-missing-shared-check meta-class.Mechanism (R-HU a): one range check keyed on the literal's RESOLVED type; the SPY0210 family gains "too large for 'double' / 'float' / 'decimal'";
float_literals.mdgains the sentence beside line 82 anddecimallikewise;DiagnosticExplanationsfor any new code. Guard (R-HV a): theory type {int32→int64 promotion, int64, uint32, uint64, float64, float32, decimal} × spelling {unsuffixed, suffixed, slot-narrowed} × magnitude {max, max + one ulp, far, negative}; mutation (drop the float64 arm → its rows red) in the commit body; direction record: NO program that ran changes (every cell is SPY0599/SPY0909 today) — recorded in the commit body, no fixture moves. Blast radius: Semantic → the whole gate. Class tracker: this issue.Rejected — R-HU (b): float64 unsuffixed →
inf(CPython's value,double.PositiveInfinity) withf/mrefusing — two rules for one surface, andx: float = 1e400then carries infinity into arithmetic silently; a runtime value is one-way, a refusal is relaxable to (b) later; Type Safety > Python syntax, and the spec already chose refusal for float32. R-HV (b): a P37 row — P37 is slot-DIRECTED operand totality (Some(v)/None()against a typed other operand);print(1e400)and1e29mhave no slot, so P37's generator would gain a foreign axis and an ICE would wait behind P70. Ordering two-way.fix(semantic): a numeric literal outside its own type's range is SPY0…
antonsynd commentedon Oct 22, 2026
Landed (chores band 2026-10-22) on
dev@ 4d22212, PR #2346 to mainline. Whole-solution gate 81669/0/7 @ 4d22212 (measured), against 81093/0/7 @ be4664e.Commit 64ff07e (R-HU a, R-HV a).
FloatLiteralClassifier.Fits(text, double|float|decimal)is the one range question. The literal-typing arm refuses a miss with SPY0210 ("too large for 'double'/'float'/'decimal'"), and the float32 and decimal narrowing predicates ask the sameFits. The SPY0210 constant is renamedNumericLiteralOutOfRange.float_literals.mdgains "A Literal Must Fit Its Own Type".Direction:
1e400,-1e400,1e400d,1e39f, the slot and pattern positions, and the parameter-default and const positions.1e29m,79228162514264337593543950336m.-1UL→ SPY0223, andx: uint32 = -1U→ SPY0220.Matrix:
NumericLiteralRangeMatrixTests, 84 rows plus a 13-text Roslyn differential.Mutations:
trueturned 14 rows red.NegatesAsLiteralreturningtrueturned 3 rows red.Sibling filed: #2344. A non-zero decimal literal below 1e-28 still gets two verdicts.
1e-30mis stored as zero, whiled: decimal = 1e-30is refused. The narrowing path keeps an underflow check the suffixed path never asks. That is a magnitude axis this issue's contract did not list, so it has its own tracker.Every cell in this issue's table is met. Closing.
Merge pull request #2346 from antonsynd/dev