Skip to content

Commit

Permalink
feat(es/utils): Support for arrays using cast_to_number (#9212)
Browse files Browse the repository at this point in the history
**Description:**

This PR allows `ArrayLit`s to be converted to numbers in the
`cast_to_number` function. This allows expressions using arrays to be
converted to numbers. See some example expressions below that were
previously not able to be computed, but are now able to due to this
change.

```js
+[] // 0
+[[]] // 0
+[1] // 1
+[undefined] // 0
+[null] // 0
+[[1]] // 1
+[,] // 0
+[,,] // NaN
```

Regarding the implementation, arrays are converted to strings, and the
string is then parsed as a number. So arrays like `[]` and `[undefined]`
return `""` which then return `0` when parsed as a string. This is also
why arrays with more than one element can't be parsed because e.g. `[1,
2]` returns `"1,2"`. This procedure follows the ECMAScript
specification.
https://262.ecma-international.org/6.0/#sec-tonumber
https://262.ecma-international.org/6.0/#sec-toprimitive
  • Loading branch information
levi-nz committed Jul 12, 2024
1 parent b4dbe0b commit 2aef14d
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 1 deletion.
21 changes: 21 additions & 0 deletions crates/swc_ecma_transforms_optimization/src/simplify/expr/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
8 changes: 7 additions & 1 deletion crates/swc_ecma_utils/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -890,6 +890,13 @@ pub trait ExprExt {
Lit::Str(Str { value, .. }) => return (Pure, num_from_str(value)),
_ => return (Pure, Unknown),
},
Expr::Array(..) => {
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,
Expand Down Expand Up @@ -1572,7 +1579,6 @@ pub fn num_from_str(s: &str) -> Value<f64> {
return Unknown;
}

// TODO: Check if this is correct
let s = s.trim();

if s.is_empty() {
Expand Down

0 comments on commit 2aef14d

Please sign in to comment.