also looking at this
fix(interpreter): report overflow when dividing the minimum integer by -1
#931
2 files
+36
-4
| @@ -11615,8 +11615,8 @@ pub const Interpreter = struct { | ||
| 11615 | 11615 | const result: i64 = switch (op) { |
| 11616 | 11616 | .Sub => std.math.sub(i64, l, r) catch return error.RuntimeError, |
| 11617 | 11617 | .Mul => std.math.mul(i64, l, r) catch return error.RuntimeError, |
| 11618 | .Div => @divTrunc(l, r), | |
| 11619 | .IntDiv => @divTrunc(l, r), | |
| 11618 | .Div => std.math.divTrunc(i64, l, r) catch return error.RuntimeError, | |
| 11619 | .IntDiv => std.math.divTrunc(i64, l, r) catch return error.RuntimeError, | |
| 11620 | 11620 | // Use truncated remainder (@rem) for consistency with TypeScript/C/Java |
| 11621 | 11621 | // semantics where the sign of the result matches the dividend: |
| 11622 | 11622 | // -7 % 3 == -1 (not 2 as with floored @mod) |
| @@ -11766,7 +11766,7 @@ pub const Interpreter = struct { | ||
| 11766 | 11766 | .SaturatingAdd => std.math.add(i64, l, r) catch null, |
| 11767 | 11767 | .SaturatingSub => std.math.sub(i64, l, r) catch null, |
| 11768 | 11768 | .SaturatingMul => std.math.mul(i64, l, r) catch null, |
| 11769 | .SaturatingDiv => if (r == 0) null else @divTrunc(l, r), | |
| 11769 | .SaturatingDiv => if (r == 0) null else std.math.divTrunc(i64, l, r) catch null, | |
| 11770 | 11770 | else => null, |
| 11771 | 11771 | }; |
| 11772 | 11772 | |
| @@ -11836,7 +11836,10 @@ pub const Interpreter = struct { | ||
| 11836 | 11836 | .CheckedDiv => if (r == 0) { |
| 11837 | 11837 | std.debug.print("Division by zero in checked division\n", .{}); |
| 11838 | 11838 | return error.RuntimeError; |
| 11839 | } else @divTrunc(l, r), | |
| 11839 | } else std.math.divTrunc(i64, l, r) catch { | |
| 11840 | std.debug.print("Integer overflow in checked division\n", .{}); | |
| 11841 | return error.RuntimeError; | |
| 11842 | }, | |
| 11840 | 11843 | else => l, |
| 11841 | 11844 | }; |
| 11842 | 11845 | |
| @@ -59,6 +59,35 @@ test "eval: nested arithmetic expression" { | ||
| 59 | 59 | try runProgram("fn main() { print((1 + 2) * 3 - 4) }"); |
| 60 | 60 | } |
| 61 | 61 | |
| 62 | test "eval: dividing the minimum integer by -1 reports the overflow" { | |
| 63 | try testing.expectError(error.RuntimeError, runProgram( | |
| 64 | \\fn main() { | |
| 65 | \\ let x = -9223372036854775807 - 1 | |
| 66 | \\ print(x / -1) | |
| 67 | \\} | |
| 68 | )); | |
| 69 | try testing.expectError(error.RuntimeError, runProgram( | |
| 70 | \\fn main() { | |
| 71 | \\ let x = -9223372036854775807 - 1 | |
| 72 | \\ print(x ~/ -1) | |
| 73 | \\} | |
| 74 | )); | |
| 75 | try testing.expectError(error.RuntimeError, runProgram( | |
| 76 | \\fn main() { | |
| 77 | \\ let x = -9223372036854775807 - 1 | |
| 78 | \\ print(x /! -1) | |
| 79 | \\} | |
| 80 | )); | |
| 81 | try runProgram( | |
| 82 | \\fn main() { | |
| 83 | \\ let x = -9223372036854775807 - 1 | |
| 84 | \\ assert(is_none(x /? -1)) | |
| 85 | \\ assert(x / 1 == x) | |
| 86 | \\ assert(x ~/ 2 == -4611686018427387904) | |
| 87 | \\} | |
| 88 | ); | |
| 89 | } | |
| 90 | ||
| 62 | 91 | test "eval: multiple statements and a returning function" { |
| 63 | 92 | // Exercises several evaluateExpression entries across statements and a |
| 64 | 93 | // user-function call — all of which were unreachable while expression depth |