Repository: swc-project/swc (rust)

Issue:
Minifier evaluates `slice` call of array wrong
### Describe the bug

`Array.prototype.call` with negative number as a first argument, minifier evaluates it wrong.

### Input code

```typescript
console.log([1,2,3].slice(-1))
```


### Config

```json
{
  "jsc": {
    "parser": {
      "syntax": "ecmascript",
      "jsx": false
    },
    "target": "es2022",
    "loose": false,
    "minify": {
      "compress": {
        "arguments": false,
        "arrows": true,
        "booleans": true,
        "booleans_as_integers": false,
        "collapse_vars": true,
        "comparisons": true,
        "computed_props": true,
        "conditionals": true,
        "dead_code": true,
        "directives": true,
        "drop_console": false,
        "drop_debugger": true,
        "evaluate": true,
        "expression": false,
        "hoist_funs": false,
        "hoist_props": true,
        "hoist_vars": false,
        "if_return": true,
        "join_vars": true,
        "keep_classnames": false,
        "keep_fargs": true,
        "keep_fnames": false,
        "keep_infinity": false,
        "loops": true,
        "negate_iife": true,
        "properties": true,
        "reduce_funcs": false,
        "reduce_vars": false,
        "side_effects": true,
        "switches": true,
        "typeofs": true,
        "unsafe": false,
        "unsafe_arrows": false,
        "unsafe_comps": false,
        "unsafe_Function": false,
        "unsafe_math": false,
        "unsafe_symbols": false,
        "unsafe_methods": false,
        "unsafe_proto": false,
        "unsafe_regexp": false,
        "unsafe_undefined": false,
        "unused": true,
        "const_to_let": true,
        "pristine_globals": true
      },
      "mangle": false
    }
  },
  "module": {
    "type": "es6"
  },
  "minify": false,
  "isModule": true
}
```


### Playground link (or link to the minimal reproduction)

https://play.swc.rs/?version=1.4.6&code=H4sIAAAAAAAAA0vOzyvOz0nVy8lP14g21DHSMY7VK87JTE7V0DXU1AQALid4bx4AAAA%3D&config=H4sIAAAAAAAAA32UO3LjMAyG%2B5zCozrFjostcoDtcgYOTYIyvXxoCNCxJuO7L0TJj40hdRI%2B%2FAAJgPh%2B2%2B26E5ruY%2FfNn%2Fwz6IJQ7v9swTGRvrClAxM1muIH6t5v9IQTcjogNNN1Jh3p0gM1Fe5%2F7feLogs5I9wUiy365N34nNPkOBRAfLKxlUPWCInwf%2F3CSv6aAJX6bD%2FkHECnDaI0Kp8IeihSYJND0AOCOusiRJlOqovHLKWYYCWwaih5EHmynnxOnPOVWtBWmWxBQL6AIX8GSca5WJaQryfcp2ELh9r3rc8%2F1HDWoWoScsKltYRPK0Q9Zo%2BkXE1SCWe4UoMZLsX9qfROFaBa0qvulH1a6clfAK5A0IhJR5DiNg%2FH87SmdptKnxyPLI0C5%2FmWbpmg56Iq751Q2akyUMhL3Sxgq4GpskY6zoJXyofeggLneFaE0PjlyRylpDQOkJ0AuL%2FaSVM1A3V%2FhSt8ehAb%2BA%2FfkuQBWzyipuM6xTEecthIEIGO2W44cCsor%2BPCW%2BIyrPOaLPBogBVdKjbwugT4AVBWoe3Ll9ng58ERVR%2Fy4bEmFofrfQ9HnfrHe59X8dvi0MVsa4PLkp%2F6O6%2Fm393D6baF7wfvPH7elC3p9R%2BoYzQdMAYAAA%3D%3D

### SWC Info output

_No response_

### Expected behavior

```javascript
console.log([3])
```
or don't minify it

### Actual behavior

```javascript
console.log([1,2,3])
```

### Version

1.4.6

### Additional context

_No response_

Pull request description:
fix(es/minifier): Do not evaluate `slice` calls with negative index
**Description:**


**Related issue:**

 - Closes #8715.

Patch:
diff --git a/crates/swc_ecma_minifier/src/compress/pure/evaluate.rs b/crates/swc_ecma_minifier/src/compress/pure/evaluate.rs
index cd2ac1aea2..1c29a585a2 100644
--- a/crates/swc_ecma_minifier/src/compress/pure/evaluate.rs
+++ b/crates/swc_ecma_minifier/src/compress/pure/evaluate.rs
@@ -76,6 +76,10 @@ impl Pure<'_> {
                         if let Value::Known(start) =
                             call.args[0].expr.as_pure_number(&self.expr_ctx)
                         {
+                            if start.is_sign_negative() {
+                                return;
+                            }
+
                             let start = start.floor() as usize;
 
                             self.changed = true;
@@ -98,9 +102,17 @@ impl Pure<'_> {
                         let start = call.args[0].expr.as_pure_number(&self.expr_ctx);
                         let end = call.args[1].expr.as_pure_number(&self.expr_ctx);
                         if let Value::Known(start) = start {
+                            if start.is_sign_negative() {
+                                return;
+                            }
+
                             let start = start.floor() as usize;
 
                             if let Value::Known(end) = end {
+                                if end.is_sign_negative() {
+                                    return;
+                                }
+
                                 let end = end.floor() as usize;
                                 let end = end.min(arr.elems.len());
 


Test patch:
diff --git a/crates/swc_ecma_minifier/tests/fixture/issues/8715/config.json b/crates/swc_ecma_minifier/tests/fixture/issues/8715/config.json
new file mode 100644
index 0000000000..7e144b291f
--- /dev/null
+++ b/crates/swc_ecma_minifier/tests/fixture/issues/8715/config.json
@@ -0,0 +1,47 @@
+{
+    "defaults": true,
+    "arguments": false,
+    "arrows": true,
+    "booleans": true,
+    "booleans_as_integers": false,
+    "collapse_vars": true,
+    "comparisons": true,
+    "computed_props": true,
+    "conditionals": true,
+    "dead_code": true,
+    "directives": true,
+    "drop_console": false,
+    "drop_debugger": true,
+    "evaluate": true,
+    "expression": false,
+    "hoist_funs": false,
+    "hoist_props": true,
+    "hoist_vars": false,
+    "if_return": true,
+    "join_vars": true,
+    "keep_classnames": false,
+    "keep_fargs": true,
+    "keep_fnames": false,
+    "keep_infinity": false,
+    "loops": true,
+    "negate_iife": true,
+    "properties": true,
+    "reduce_funcs": false,
+    "reduce_vars": false,
+    "side_effects": true,
+    "switches": true,
+    "typeofs": true,
+    "unsafe": false,
+    "unsafe_arrows": false,
+    "unsafe_comps": false,
+    "unsafe_Function": false,
+    "unsafe_math": false,
+    "unsafe_symbols": false,
+    "unsafe_methods": false,
+    "unsafe_proto": false,
+    "unsafe_regexp": false,
+    "unsafe_undefined": false,
+    "unused": true,
+    "const_to_let": true,
+    "pristine_globals": true
+}
diff --git a/crates/swc_ecma_minifier/tests/fixture/issues/8715/input.js b/crates/swc_ecma_minifier/tests/fixture/issues/8715/input.js
new file mode 100644
index 0000000000..60fd274a25
--- /dev/null
+++ b/crates/swc_ecma_minifier/tests/fixture/issues/8715/input.js
@@ -0,0 +1,2 @@
+console.log([1, 2, 3].slice(-1))
+console.log([1, 2, 3].slice(-1, 0))
diff --git a/crates/swc_ecma_minifier/tests/fixture/issues/8715/output.js b/crates/swc_ecma_minifier/tests/fixture/issues/8715/output.js
new file mode 100644
index 0000000000..823840bb3e
--- /dev/null
+++ b/crates/swc_ecma_minifier/tests/fixture/issues/8715/output.js
@@ -0,0 +1,9 @@
+console.log([
+    1,
+    2,
+    3
+].slice(-1)), console.log([
+    1,
+    2,
+    3
+].slice(-1, 0));