Repository: swc-project/swc (rust)

Issue:
Variable named as `NaN` cannot be resolved
### Describe the bug

Variable `NaN` is incorrectly renamed.

### Input code

```typescript
{
    let NaN = 1;
    console.log(NaN);
}
```


### Config

```json
{
  "jsc": {
    "minify": {
      "compress": false
    },
    "parser": {
      "syntax": "ecmascript"
    },
    "target": "es2022"
  }
}
```


### Playground link

[playground](https://play.swc.rs/?version=1.3.70&code=H4sIAAAAAAAAA6vmUgCCnNQSBb9EPwVbBUNrsEByfl5xfk6qXk5%2BugZQQtOaqxYAp6nlwyoAAAA%3D&config=H4sIAAAAAAAAA1WLwQqAIBBE736FeO4QHvubRdYw0mTXQyL%2Be5tB1G3mzZumtDYbO7PoJlFKDCn4%2BnYh7oiZkFmYh51x8D49egZipK%2FONRU4hRh0EdhRyMX8PgVoxTIMtrO199pVvwAnblc2jAAAAA%3D%3D)

### Expected behavior

The output should be exactly the same as the input.

### Actual behavior

```JavaScript
{
    let NaN1 = 1;
    console.log(NaN);
}
```

### Version

1.3.70

### Additional context

- #4596
- #7684 

_No response_

Pull request description:
fix(es/resolver): Correctly resolve global value
<!-- 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):**
Closes #7685 

Patch:
diff --git a/crates/swc_ecma_transforms_base/src/resolver/mod.rs b/crates/swc_ecma_transforms_base/src/resolver/mod.rs
index c947a89cc5..d20afdff4e 100644
--- a/crates/swc_ecma_transforms_base/src/resolver/mod.rs
+++ b/crates/swc_ecma_transforms_base/src/resolver/mod.rs
@@ -1,5 +1,5 @@
 use rustc_hash::FxHashSet;
-use swc_atoms::{js_word, JsWord};
+use swc_atoms::JsWord;
 use swc_common::{
     collections::{AHashMap, AHashSet},
     Mark, Span, SyntaxContext,
@@ -269,11 +269,6 @@ impl<'a> Resolver<'a> {
     }
 
     fn mark_for_ref_inner(&self, sym: &JsWord, stop_an_fn_scope: bool) -> Option<Mark> {
-        // NaN always points the globals
-        if *sym == js_word!("NaN") {
-            return Some(self.config.unresolved_mark);
-        }
-
         if self.config.handle_types && self.in_type {
             let mut mark = self.current.mark;
             let mut scope = Some(&self.current);
@@ -307,7 +302,16 @@ impl<'a> Resolver<'a> {
                 if mark == Mark::root() {
                     return None;
                 }
-                return Some(mark);
+
+                return match &**sym {
+                    // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects#value_properties
+                    "undefined" | "NaN" | "Infinity" | "globalThis"
+                        if mark == self.config.top_level_mark =>
+                    {
+                        Some(self.config.unresolved_mark)
+                    }
+                    _ => Some(mark),
+                };
             }
 
             if cur.kind == ScopeKind::Fn && stop_an_fn_scope {


Test patch:
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
index 882bd109d7..2e2a7c08f3 100644
--- a/crates/swc_ecma_minifier/tests/fixture/issues/7683/1/output.js
+++ b/crates/swc_ecma_minifier/tests/fixture/issues/7683/1/output.js
@@ -3,8 +3,9 @@
     console.log(Infinity);
     if (Infinity > 4) console.log("Infinity");
 }{
-    let NaN1 = 3;
+    let NaN = 3;
     console.log(NaN);
+    if (NaN < 4) console.log("NaN");
 }{
     let undefined = 3;
     console.log(undefined);
diff --git a/crates/swc_ecma_minifier/tests/terser/compress/collapse_vars/issue_2506/output.mangleOnly.js b/crates/swc_ecma_minifier/tests/terser/compress/collapse_vars/issue_2506/output.mangleOnly.js
index bbeefcf686..0725ec6d3a 100644
--- a/crates/swc_ecma_minifier/tests/terser/compress/collapse_vars/issue_2506/output.mangleOnly.js
+++ b/crates/swc_ecma_minifier/tests/terser/compress/collapse_vars/issue_2506/output.mangleOnly.js
@@ -1,14 +1,14 @@
-var a = 0;
-function n(n) {
-    function f(n) {
-        function f(n) {
-            if ((false <= NaN) & (this >> 1 >= 0)) {
-                a++;
+var n = 0;
+function a(a) {
+    function f(a) {
+        function f(a) {
+            if ((false <= a) & (this >> 1 >= 0)) {
+                n++;
             }
         }
-        var o = f(NaN, a++);
+        var o = f(NaN, n++);
     }
-    var n = f(-3, -1);
+    var a = f(-3, -1);
 }
-n(false);
-console.log(a);
+a(false);
+console.log(n);
diff --git a/crates/swc_ecma_minifier/tests/terser/compress/functions/issue_2616/output.mangleOnly.js b/crates/swc_ecma_minifier/tests/terser/compress/functions/issue_2616/output.mangleOnly.js
index 3c479d009b..bc478f38d2 100644
--- a/crates/swc_ecma_minifier/tests/terser/compress/functions/issue_2616/output.mangleOnly.js
+++ b/crates/swc_ecma_minifier/tests/terser/compress/functions/issue_2616/output.mangleOnly.js
@@ -2,7 +2,7 @@ var n = "FAIL";
 (function() {
     function o() {
         function o(o) {
-            (true << NaN) - 0 / 0 || (n = "PASS");
+            (true << o) - 0 / 0 || (n = "PASS");
         }
         o([]);
     }
diff --git a/crates/swc_ecma_minifier/tests/terser/compress/functions/issue_2620_3/output.mangleOnly.js b/crates/swc_ecma_minifier/tests/terser/compress/functions/issue_2620_3/output.mangleOnly.js
index 458d9794f4..dd94cfe6dc 100644
--- a/crates/swc_ecma_minifier/tests/terser/compress/functions/issue_2620_3/output.mangleOnly.js
+++ b/crates/swc_ecma_minifier/tests/terser/compress/functions/issue_2620_3/output.mangleOnly.js
@@ -1,15 +1,15 @@
 var c = "FAIL";
 (function() {
-    function n(n, a) {
-        function o() {
+    function n(n, o) {
+        function a() {
             switch(n){
                 case n:
                     break;
-                case ((c = "PASS"), NaN):
+                case ((c = "PASS"), o):
                     break;
             }
         }
-        o();
+        a();
     }
     n(0 / 0);
 })();
diff --git a/crates/swc_ecma_minifier/tests/terser/compress/functions/issue_2620_4/output.mangleOnly.js b/crates/swc_ecma_minifier/tests/terser/compress/functions/issue_2620_4/output.mangleOnly.js
index 458d9794f4..dd94cfe6dc 100644
--- a/crates/swc_ecma_minifier/tests/terser/compress/functions/issue_2620_4/output.mangleOnly.js
+++ b/crates/swc_ecma_minifier/tests/terser/compress/functions/issue_2620_4/output.mangleOnly.js
@@ -1,15 +1,15 @@
 var c = "FAIL";
 (function() {
-    function n(n, a) {
-        function o() {
+    function n(n, o) {
+        function a() {
             switch(n){
                 case n:
                     break;
-                case ((c = "PASS"), NaN):
+                case ((c = "PASS"), o):
                     break;
             }
         }
-        o();
+        a();
     }
     n(0 / 0);
 })();
diff --git a/crates/swc_ecma_minifier/tests/terser/compress/issue_597/NaN_and_Infinity_should_not_be_replaced_when_they_are_redefined/output.js b/crates/swc_ecma_minifier/tests/terser/compress/issue_597/NaN_and_Infinity_should_not_be_replaced_when_they_are_redefined/output.js
index 8a005e8f6b..bf9891c575 100644
--- a/crates/swc_ecma_minifier/tests/terser/compress/issue_597/NaN_and_Infinity_should_not_be_replaced_when_they_are_redefined/output.js
+++ b/crates/swc_ecma_minifier/tests/terser/compress/issue_597/NaN_and_Infinity_should_not_be_replaced_when_they_are_redefined/output.js
@@ -1,3 +1,3 @@
 var Infinity, NaN1;
-Infinity.toString();
+(1 / 0).toString();
 NaN.toString();
diff --git a/crates/swc_ecma_minifier/tests/terser/compress/issue_597/NaN_and_Infinity_should_not_be_replaced_when_they_are_redefined/output.mangleOnly.js b/crates/swc_ecma_minifier/tests/terser/compress/issue_597/NaN_and_Infinity_should_not_be_replaced_when_they_are_redefined/output.mangleOnly.js
index a2a7cc5af6..9aec8187a7 100644
--- a/crates/swc_ecma_minifier/tests/terser/compress/issue_597/NaN_and_Infinity_should_not_be_replaced_when_they_are_redefined/output.mangleOnly.js
+++ b/crates/swc_ecma_minifier/tests/terser/compress/issue_597/NaN_and_Infinity_should_not_be_replaced_when_they_are_redefined/output.mangleOnly.js
@@ -1,3 +1,3 @@
-var t, r;
-t.toString();
+var t, i;
+Infinity.toString();
 NaN.toString();
diff --git a/crates/swc_ecma_transforms_base/tests/resolver/issues/7685/input.js b/crates/swc_ecma_transforms_base/tests/resolver/issues/7685/input.js
new file mode 100644
index 0000000000..9bf5178cb4
--- /dev/null
+++ b/crates/swc_ecma_transforms_base/tests/resolver/issues/7685/input.js
@@ -0,0 +1,6 @@
+var NaN = 1;
+{
+    let NaN = 1;
+    console.log(NaN);
+}
+console.log(NaN);
diff --git a/crates/swc_ecma_transforms_base/tests/resolver/issues/7685/output.js b/crates/swc_ecma_transforms_base/tests/resolver/issues/7685/output.js
new file mode 100644
index 0000000000..a31e62c38b
--- /dev/null
+++ b/crates/swc_ecma_transforms_base/tests/resolver/issues/7685/output.js
@@ -0,0 +1,5 @@
+var NaN__2 = 1;
+{
+    let NaN__3 = 1;
+    console.log(NaN__3);
+}console.log(NaN);
diff --git a/crates/swc_node_bundler/tests/pass/resolve-name-fix/output/entry.js b/crates/swc_node_bundler/tests/pass/resolve-name-fix/output/entry.js
index ae90cb84c0..7940dc3b7d 100644
--- a/crates/swc_node_bundler/tests/pass/resolve-name-fix/output/entry.js
+++ b/crates/swc_node_bundler/tests/pass/resolve-name-fix/output/entry.js
@@ -4569,8 +4569,7 @@ var load228 = __swcpack_require__.bind(void 0, function(module, exports) {
     var $DataView = global[DATA_VIEW];
     var Math1 = global.Math;
     var RangeError1 = global.RangeError;
-    // eslint-disable-next-line no-shadow-restricted-names
-    var Infinity1 = global.Infinity;
+    global.Infinity;
     var BaseBuffer = $ArrayBuffer;
     var abs = Math1.abs;
     var pow = Math1.pow;
@@ -4595,7 +4594,7 @@ var load228 = __swcpack_require__.bind(void 0, function(module, exports) {
         var e, m, c;
         value = abs(value);
         // eslint-disable-next-line no-self-compare
-        if (value != value || value === Infinity1) {
+        if (value != value || value === Infinity) {
             // eslint-disable-next-line no-self-compare
             m = value != value ? 1 : 0;
             e = eMax;
@@ -4645,7 +4644,7 @@ var load228 = __swcpack_require__.bind(void 0, function(module, exports) {
         nBits += mLen;
         for(; nBits > 0; m = m * 256 + buffer[i], i--, nBits -= 8);
         if (e === 0) e = 1 - eBias;
-        else if (e === eMax) return m ? NaN : s ? -Infinity1 : Infinity1;
+        else if (e === eMax) return m ? NaN : s ? -Infinity : Infinity;
         else {
             m = m + pow(2, mLen);
             e = e - eBias;