From ff2749d5b693fc4e3beb691e3570fcc0b0233414 Mon Sep 17 00:00:00 2001 From: Levi Date: Fri, 12 Jul 2024 03:35:55 +1200 Subject: [PATCH] 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,