Repository: swc-project/swc (rust)

Issue:
Wrong dead code elimination with variable named `Infinity`
### Describe the bug

The identifier `Infinity` might refer to a local variable whose value is not ∞, but SWC assumes that it's always ∞.

### Input code

```typescript
{
  let Infinity = 3;
  if (Infinity > 4) console.log(3)
}
```


### Config

```json
{
  "minify": true,
  "jsc": {
    "minify": {
      "compress": {
        "dead_code": true
      }
    },
    "parser": {
      "syntax": "typescript"
    },
    "target": "es2022"
  }
}
```


### Playground link

https://play.swc.rs/?version=1.3.70&code=H4sIAAAAAAAAA6vmUlDISS1R8MxLy8zLLKlUsFUwtgaKZaYpaMDF7BRMNBWS8%2FOK83NS9XLy0zWMNblqAbTYNkc6AAAA&config=H4sIAAAAAAAAA1WMMQ6AIAxFd09BmB0Mo5cxBKrBRCVtTSSGu1vEAaf2v9%2B%2Bu1NKb2EPc9KjYjyhL2QlJ%2FGWta1rFuKOLSIQNUyoB%2Bsnd3j4TF%2BT35n7KosWCbCVUdrZXkI0pwjkMETWvx%2B2uACXCyAzGFPa3OUHviUI6bwAAAA%3D

### Expected behavior

The generated code should either be empty, or still have the `if` check before `console.log`. The `console.log` statement should not be executed.

### Actual behavior

The generated code is
```js
console.log(3);
```

### Version

1.3.70

### Additional context

_No response_

Pull request:
fix(es/minifier): Only cast global `Infinity`/`undefined`/`NaN`
<!-- Note: CI script will automatically rebase your PR so please do not rebase unless required -->

<!-- Thanks for submitting a pull request! Please provide enough information so that others can review your pull request. -->

**Description:**

<!-- Explain the **motivation** for making this change. What existing problem does the pull request solve? -->

**BREAKING CHANGE:**

<!--
If this PR introduces a breaking change, it must contain a notice for it to be included in the CHANGELOG. Add description or remove entirely if not breaking.

You may need to update `MIGRATION.md` for the breaking changes.
-->

**Related issue (if exists):**
- fix #7683 

Patch:
diff --git a/crates/swc_ecma_utils/src/lib.rs b/crates/swc_ecma_utils/src/lib.rs
index d95042959b..d6a8ca25ca 100644
--- a/crates/swc_ecma_utils/src/lib.rs
+++ b/crates/swc_ecma_utils/src/lib.rs
@@ -902,9 +902,9 @@ pub trait ExprExt {
                 Lit::Str(Str { value, .. }) => return (Pure, num_from_str(value)),
                 _ => return (Pure, Unknown),
             },
-            Expr::Ident(Ident { sym, .. }) => match *sym {
-                js_word!("undefined") | js_word!("NaN") => NAN,
-                js_word!("Infinity") => INFINITY,
+            Expr::Ident(Ident { sym, span, .. }) => match *sym {
+                js_word!("undefined") | js_word!("NaN") if span.ctxt == ctx.unresolved_ctxt => NAN,
+                js_word!("Infinity") if span.ctxt == ctx.unresolved_ctxt => INFINITY,
                 _ => return (Pure, Unknown),
             },
             Expr::Unary(UnaryExpr {
@@ -915,8 +915,9 @@ pub trait ExprExt {
                 &**arg,
                 Expr::Ident(Ident {
                     sym: js_word!("Infinity"),
+                    span,
                     ..
-                })
+                }) if span.ctxt == ctx.unresolved_ctxt
             ) =>
             {
                 -INFINITY
@@ -1005,8 +1006,10 @@ pub trait ExprExt {
                 // converted. unimplemented!("TplLit.
                 // as_string()")
             }
-            Expr::Ident(Ident { ref sym, .. }) => match *sym {
-                js_word!("undefined") | js_word!("Infinity") | js_word!("NaN") => {
+            Expr::Ident(Ident { ref sym, span, .. }) => match *sym {
+                js_word!("undefined") | js_word!("Infinity") | js_word!("NaN")
+                    if span.ctxt == ctx.unresolved_ctxt =>
+                {
                     Known(Cow::Borrowed(&**sym))
                 }
                 _ => Unknown,


Test patch:
diff --git a/crates/swc_ecma_minifier/tests/fixture/issues/7683/1/input.js b/crates/swc_ecma_minifier/tests/fixture/issues/7683/1/input.js
new file mode 100644
index 0000000000..d4f14d93fc
--- /dev/null
+++ b/crates/swc_ecma_minifier/tests/fixture/issues/7683/1/input.js
@@ -0,0 +1,23 @@
+{
+    let Infinity = 3;
+    console.log(Infinity);
+    if (Infinity > 4) console.log("Infinity");
+}
+
+{
+    let NaN = 3;
+    console.log(NaN);
+    if (NaN < 4) console.log("NaN");
+}
+
+{
+    let undefined = 3;
+    console.log(undefined);
+    if (undefined < 4) console.log("undefined");
+}
+
+{
+    let x = 3;
+    console.log(x);
+    if (x < 4) console.log("undefined");
+}
diff --git a/crates/swc_ecma_minifier/tests/fixture/issues/7683/1/output.js b/crates/swc_ecma_minifier/tests/fixture/issues/7683/1/output.js
new file mode 100644
index 0000000000..882bd109d7
--- /dev/null
+++ b/crates/swc_ecma_minifier/tests/fixture/issues/7683/1/output.js
@@ -0,0 +1,16 @@
+{
+    let Infinity = 3;
+    console.log(Infinity);
+    if (Infinity > 4) console.log("Infinity");
+}{
+    let NaN1 = 3;
+    console.log(NaN);
+}{
+    let undefined = 3;
+    console.log(undefined);
+    if (undefined < 4) console.log("undefined");
+}{
+    let x = 3;
+    console.log(x);
+    if (x < 4) console.log("undefined");
+}
diff --git a/crates/swc_ecma_minifier/tests/fixture/issues/7683/config.json b/crates/swc_ecma_minifier/tests/fixture/issues/7683/config.json
new file mode 100644
index 0000000000..db9bf721a8
--- /dev/null
+++ b/crates/swc_ecma_minifier/tests/fixture/issues/7683/config.json
@@ -0,0 +1,3 @@
+{
+    "dead_code": true
+}
\ No newline at end of file