From 381f09fca5756b9a05d6e29c02de1403b78087ed Mon Sep 17 00:00:00 2001 From: Levi Date: Fri, 12 Jul 2024 03:35:18 +1200 Subject: [PATCH 1/4] Remove TODO This is correct according to https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number#number_coercion --- crates/swc_ecma_utils/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/swc_ecma_utils/src/lib.rs b/crates/swc_ecma_utils/src/lib.rs index 074b38ac41d0..81c362346acd 100644 --- a/crates/swc_ecma_utils/src/lib.rs +++ b/crates/swc_ecma_utils/src/lib.rs @@ -1572,7 +1572,6 @@ pub fn num_from_str(s: &str) -> Value { return Unknown; } - // TODO: Check if this is correct let s = s.trim(); if s.is_empty() { From ff2749d5b693fc4e3beb691e3570fcc0b0233414 Mon Sep 17 00:00:00 2001 From: Levi Date: Fri, 12 Jul 2024 03:35:55 +1200 Subject: [PATCH 2/4] Support for converting `ArrayLit`s to numbers --- .../src/simplify/expr/tests.rs | 21 ++++++++++++ crates/swc_ecma_utils/src/lib.rs | 33 +++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/crates/swc_ecma_transforms_optimization/src/simplify/expr/tests.rs b/crates/swc_ecma_transforms_optimization/src/simplify/expr/tests.rs index b70c0743a1e9..6f6d7b4d89a2 100644 --- a/crates/swc_ecma_transforms_optimization/src/simplify/expr/tests.rs +++ b/crates/swc_ecma_transforms_optimization/src/simplify/expr/tests.rs @@ -488,6 +488,27 @@ fn test_unary_ops_4() { fold("a=~~0xffffffff", "a=-1"); } +#[test] +fn test_unary_ops_5() { + // Empty arrays + fold("+[]", "0"); + fold("+[[]]", "0"); + fold("+[[[]]]", "0"); + + // Arrays with one element + fold("+[1]", "1"); + fold("+[[1]]", "1"); + fold("+[undefined]", "0"); + fold("+[null]", "0"); + fold("+[,]", "0"); + + // Arrays with more than one element + fold("+[1, 2]", "NaN"); + fold("+[[1], 2]", "NaN"); + fold("+[,1]", "NaN"); + fold("+[,,]", "NaN"); +} + #[test] fn test_unary_ops_string_compare() { fold_same("a = -1"); diff --git a/crates/swc_ecma_utils/src/lib.rs b/crates/swc_ecma_utils/src/lib.rs index 81c362346acd..493bb4530c26 100644 --- a/crates/swc_ecma_utils/src/lib.rs +++ b/crates/swc_ecma_utils/src/lib.rs @@ -890,6 +890,39 @@ pub trait ExprExt { Lit::Str(Str { value, .. }) => return (Pure, num_from_str(value)), _ => return (Pure, Unknown), }, + Expr::Array(array) => { + if array.elems.len() != 1 { + // Can only be converted to a number if there's exactly one element. + return (Pure, Known(if array.elems.is_empty() { + // Empty array is treated as zero. + 0.0 + } else { + // More than one element is treated as NaN. + f64::NAN + })); + } + + let Some(elem) = array.elems.get(0) else { + return (Pure, Unknown); + }; + + // [,] is treated as zero. + let Some(e) = elem else { + return (Pure, Known(0.0)); + }; + + // Ignore spread if it exists. + if e.spread.is_some() { + return (Pure, Unknown); + } + + // Special case: undefined is treated as zero in arrays (e.g. +[undefined]) + if e.expr.is_undefined(ctx) { + return (Pure, Known(0.0)); + } + + return e.expr.cast_to_number(ctx); + }, Expr::Ident(Ident { sym, span, .. }) => match &**sym { "undefined" | "NaN" if span.ctxt == ctx.unresolved_ctxt => f64::NAN, "Infinity" if span.ctxt == ctx.unresolved_ctxt => f64::INFINITY, From af1906d5b1563a786bcf817ace0d4f9a0ebf3250 Mon Sep 17 00:00:00 2001 From: Levi Date: Fri, 12 Jul 2024 04:26:51 +1200 Subject: [PATCH 3/4] Use `as_pure_string` for conversion --- crates/swc_ecma_utils/src/lib.rs | 32 +++----------------------------- 1 file changed, 3 insertions(+), 29 deletions(-) diff --git a/crates/swc_ecma_utils/src/lib.rs b/crates/swc_ecma_utils/src/lib.rs index 493bb4530c26..7316fb3aab62 100644 --- a/crates/swc_ecma_utils/src/lib.rs +++ b/crates/swc_ecma_utils/src/lib.rs @@ -890,38 +890,12 @@ pub trait ExprExt { Lit::Str(Str { value, .. }) => return (Pure, num_from_str(value)), _ => return (Pure, Unknown), }, - Expr::Array(array) => { - if array.elems.len() != 1 { - // Can only be converted to a number if there's exactly one element. - return (Pure, Known(if array.elems.is_empty() { - // Empty array is treated as zero. - 0.0 - } else { - // More than one element is treated as NaN. - f64::NAN - })); - } - - let Some(elem) = array.elems.get(0) else { + Expr::Array(..) => { + let Known(s) = self.as_pure_string(ctx) else { return (Pure, Unknown); }; - - // [,] is treated as zero. - let Some(e) = elem else { - return (Pure, Known(0.0)); - }; - - // Ignore spread if it exists. - if e.spread.is_some() { - return (Pure, Unknown); - } - - // Special case: undefined is treated as zero in arrays (e.g. +[undefined]) - if e.expr.is_undefined(ctx) { - return (Pure, Known(0.0)); - } - return e.expr.cast_to_number(ctx); + return (Pure, num_from_str(&s)); }, Expr::Ident(Ident { sym, span, .. }) => match &**sym { "undefined" | "NaN" if span.ctxt == ctx.unresolved_ctxt => f64::NAN, From bb7ea9d7a4758eabc84494a73bee3e6289d5bc0e Mon Sep 17 00:00:00 2001 From: Levi Date: Fri, 12 Jul 2024 04:38:33 +1200 Subject: [PATCH 4/4] `cargo fmt` --- .../src/simplify/expr/tests.rs | 4 ++-- crates/swc_ecma_utils/src/lib.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/swc_ecma_transforms_optimization/src/simplify/expr/tests.rs b/crates/swc_ecma_transforms_optimization/src/simplify/expr/tests.rs index 6f6d7b4d89a2..ba3ad6f30150 100644 --- a/crates/swc_ecma_transforms_optimization/src/simplify/expr/tests.rs +++ b/crates/swc_ecma_transforms_optimization/src/simplify/expr/tests.rs @@ -494,14 +494,14 @@ fn test_unary_ops_5() { fold("+[]", "0"); fold("+[[]]", "0"); fold("+[[[]]]", "0"); - + // Arrays with one element fold("+[1]", "1"); fold("+[[1]]", "1"); fold("+[undefined]", "0"); fold("+[null]", "0"); fold("+[,]", "0"); - + // Arrays with more than one element fold("+[1, 2]", "NaN"); fold("+[[1], 2]", "NaN"); diff --git a/crates/swc_ecma_utils/src/lib.rs b/crates/swc_ecma_utils/src/lib.rs index 7316fb3aab62..c50cd8ee278b 100644 --- a/crates/swc_ecma_utils/src/lib.rs +++ b/crates/swc_ecma_utils/src/lib.rs @@ -894,9 +894,9 @@ pub trait ExprExt { let Known(s) = self.as_pure_string(ctx) else { return (Pure, Unknown); }; - + return (Pure, num_from_str(&s)); - }, + } Expr::Ident(Ident { sym, span, .. }) => match &**sym { "undefined" | "NaN" if span.ctxt == ctx.unresolved_ctxt => f64::NAN, "Infinity" if span.ctxt == ctx.unresolved_ctxt => f64::INFINITY,