diff --git a/core/engine/src/value/operations.rs b/core/engine/src/value/operations.rs index 7300684bc4c..4e232677dd1 100644 --- a/core/engine/src/value/operations.rs +++ b/core/engine/src/value/operations.rs @@ -154,9 +154,10 @@ impl JsValue { if y == 0 { Self::nan() } else { - match x % y { - rem if rem == 0 && x < 0 => Self::new(-0.0), - rem => Self::new(rem), + match x.checked_rem(y) { + Some(rem) if rem == 0 && x < 0 => Self::new(-0.0), + Some(rem) => Self::new(rem), + None => Self::new((f64::from(x) % f64::from(y)).copysign(f64::from(x))), } } } @@ -754,9 +755,10 @@ impl JsValue { if y == 0 { return Some(Self::nan()); } - return Some(match x % y { - rem if rem == 0 && x < 0 => Self::new(-0.0), - rem => Self::new(rem), + return Some(match x.checked_rem(y) { + Some(rem) if rem == 0 && x < 0 => Self::new(-0.0), + Some(rem) => Self::new(rem), + None => Self::new((f64::from(x) % f64::from(y)).copysign(f64::from(x))), }); } let x = self.as_number_cheap()?; diff --git a/core/engine/src/value/tests.rs b/core/engine/src/value/tests.rs index ee21a6e967d..653656237b8 100644 --- a/core/engine/src/value/tests.rs +++ b/core/engine/src/value/tests.rs @@ -297,6 +297,29 @@ fn rem_by_zero() { run_test_actions([TestAction::assert_eq("1 % 0", f64::NAN)]); } +#[test] +fn rem_i32_min_by_neg_one() { + run_test_actions([TestAction::assert_with_op( + "(-2147483648 | 0) % (-1 | 0)", + |val, _| { + val.as_number() + .is_some_and(|n| n == 0.0 && n.is_sign_negative()) + }, + )]); +} + +#[test] +fn rem_fast_i32_min_by_neg_one() { + let x = JsValue::from(i32::MIN); + let y = JsValue::from(-1_i32); + let result = x.rem_fast(&y).unwrap(); + assert!( + result + .as_number() + .is_some_and(|n| n == 0.0 && n.is_sign_negative()) + ); +} + #[test] fn bitand_integer_and_integer() { run_test_actions([TestAction::assert_eq("0xFFFF & 0xFF", 255)]);