diff --git a/crates/jett_comptime/src/interpreter.rs b/crates/jett_comptime/src/interpreter.rs index 33ca4ac..88b01a9 100644 --- a/crates/jett_comptime/src/interpreter.rs +++ b/crates/jett_comptime/src/interpreter.rs @@ -8786,7 +8786,12 @@ impl Interpreter { } else { let mut result: i64 = 1; for i in 2..=*n { - result = result.saturating_mul(i); + let Some(next_result) = result.checked_mul(i) else { + return Some(Err(format!( + "math.factorial: integer overflow: {result} * {i}" + ))); + }; + result = next_result; } Some(Ok(Value::Int64(result))) } diff --git a/crates/jett_driver/tests/fixture_suite.rs b/crates/jett_driver/tests/fixture_suite.rs index 354e5e4..7e5bf99 100644 --- a/crates/jett_driver/tests/fixture_suite.rs +++ b/crates/jett_driver/tests/fixture_suite.rs @@ -426,6 +426,14 @@ fn math_sum_reports_overflow() { ); } +#[test] +fn math_factorial_reports_overflow() { + assert_runtime_fail( + "math_factorial_overflow.jett", + "runtime error: math.factorial: integer overflow: 2432902008176640000 * 21", + ); +} + #[test] fn math_clamp_rejects_invalid_bounds() { let cases = [ diff --git a/tests/runtime_fail/math_factorial_overflow.jett b/tests/runtime_fail/math_factorial_overflow.jett new file mode 100644 index 0000000..ccfecfa --- /dev/null +++ b/tests/runtime_fail/math_factorial_overflow.jett @@ -0,0 +1,3 @@ +function main() returns nothing: + int64 result = math.factorial(21) + return nothing