checker: detect empty ranges with comptime constant bounds - #27890
checker: detect empty ranges with comptime constant bounds#27890rilaaax wants to merge 6 commits into
Conversation
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8b7b1f37ad
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
Please remember to add a regression test whenever you submit a valid codex review fix. Thanks! |
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5368b548f0
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e9b3b79363
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| left_f := left.f64() | ||
| right_f := right.f64() |
There was a problem hiding this comment.
Round operands before folding f32 arithmetic
When an integer operand is not exactly representable as f32, these lines preserve it as an exact f64 and only round the final result, whereas generated code converts each operand to the promoted f32 type first. For example, for i in int(i32(16777217) - f32(16777215.0)) .. 2 {} executes once at runtime because the left operand rounds to 16777216, but the evaluator computes 2 and rejects the range as empty. The new final-result rounding therefore does not cover operand conversion; convert both operands to f32 before performing an f32 operation.
Useful? React with 👍 / 👎.
|
|
||
| // Check for empty range with comptime constant integer bounds | ||
| fn (mut c Checker) check_for_empty_range(low ast.Expr, high ast.Expr) { | ||
| if low_val := c.eval_comptime_const_expr(low, 0) { |
There was a problem hiding this comment.
Apply the promoted type when folding power bounds
The fresh remaining narrow-integer case is **: evaluating a range bound now reaches comptime_power_value, which returns before the generic promoted-type wrapping path. Thus for i in u8(16) ** u8(2) .. 1 {} is rejected using a folded low bound of 256, although codegen casts the power result to u8, producing 0, so the loop executes once. Power folding needs to honor expr.promoted_type just like the other arithmetic operators.
Useful? React with 👍 / 👎.
| range_error := c.errors.map(it.pos.line_nr).any(it == node.pos.line_nr) | ||
| if !range_error { | ||
| c.check_for_empty_range(node.cond, node.high) |
There was a problem hiding this comment.
Track range errors independently of source lines
The new guard only finds errors whose position is on the for statement's starting line, so an invalid bound placed on a later line still gets evaluated. For example, a multiline for i in 4.0 .. 2 reports its range-type error at the bound and then adds an incorrect empty-range diagnostic, while a multiline invalid shift also reaches the evaluator. Record the error count before checking the two bounds and skip this check if that count increases instead of correlating errors by line.
AGENTS.md reference: AGENTS.md:L713-L713
Useful? React with 👍 / 👎.
Fixes #27889
Problem
The compile-time check that detects empty numeric ranges (e.g.
for i in 4 .. 2) only worked when both bounds were raw integer literals. Ranges whose bounds were comptime constant cast expressions (int(2),u8(2),u16(4)) or operation results (4 - 2,int(4) - int(2)) silently compiled even when the range could never execute.Cause
checker/for.vmatched the bounds againstast.IntegerLiteralonly, so any other AST node type (ast.CastExpr, etc.) bypassed the emptiness check entirely, even though its value was fully known at compile time.Fix
Replaced the
ast.IntegerLiteralpattern match withc.eval_comptime_const_expr(), the same comptime evaluator already used elsewhere in the checker, to resolve both bounds to concrete values before comparing them. The check is restricted to cases where both bounds resolve to actual integer types, so it doesn't misfire alongside the existing "range types do not match" / "range type can only be an integer type" errors (e.g.10 .. 10.5,'a' .. 'b'). A fallback unsigned comparison handles literals that overflowi64.Known remaining limitations (left as TODOs, out of scope for this fix):
0 .. max_u8 + 1)4 .. int(2) + u8(1))Test
Coverage + regression tests added.