From 0cf78bbc05fde9f9da16361345b3ae8048961645 Mon Sep 17 00:00:00 2001 From: Haled Odat Date: Thu, 16 Mar 2023 16:59:58 +0100 Subject: [PATCH] Fix exponent operator When abs(base) == 1 and y == +/- Infinity result should be NaN --- boa_engine/src/value/operations.rs | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/boa_engine/src/value/operations.rs b/boa_engine/src/value/operations.rs index 597b36dc55c..ef7bcce44df 100644 --- a/boa_engine/src/value/operations.rs +++ b/boa_engine/src/value/operations.rs @@ -195,6 +195,8 @@ impl JsValue { } /// Perform the binary `**` operator on the value and return the result. + // NOTE: There are some cases in the spec where we have to compare floats + #[allow(clippy::float_cmp)] pub fn pow(&self, other: &Self, context: &mut Context<'_>) -> JsResult { Ok(match (self, other) { // Fast path: @@ -202,15 +204,32 @@ impl JsValue { .ok() .and_then(|y| x.checked_pow(y)) .map_or_else(|| Self::new(f64::from(*x).powi(*y)), Self::new), - (Self::Rational(x), Self::Rational(y)) => Self::new(x.powf(*y)), - (Self::Integer(x), Self::Rational(y)) => Self::new(f64::from(*x).powf(*y)), + (Self::Rational(x), Self::Rational(y)) => { + if x.abs() == 1.0 && y.is_infinite() { + Self::nan() + } else { + Self::new(x.powf(*y)) + } + } + (Self::Integer(x), Self::Rational(y)) => { + if x.abs() == 1 && y.is_infinite() { + Self::nan() + } else { + Self::new(f64::from(*x).powf(*y)) + } + } (Self::Rational(x), Self::Integer(y)) => Self::new(x.powi(*y)), - (Self::BigInt(ref a), Self::BigInt(ref b)) => Self::new(JsBigInt::pow(a, b)?), // Slow path: (_, _) => match (self.to_numeric(context)?, other.to_numeric(context)?) { - (Numeric::Number(a), Numeric::Number(b)) => Self::new(a.powf(b)), + (Numeric::Number(a), Numeric::Number(b)) => { + if a.abs() == 1.0 && b.is_infinite() { + Self::nan() + } else { + Self::new(a.powf(b)) + } + } (Numeric::BigInt(ref a), Numeric::BigInt(ref b)) => Self::new(JsBigInt::pow(a, b)?), (_, _) => { return Err(JsNativeError::typ()