Repository: vercel/next.js
Pull request: Turbopack: fix scope hoisting variable renaming bug

- [x] Add test
- [x] Fix

Closes PACK-5064

I have found another scope hoisting variable renaming (i.e. hygiene) problem:
The module is first this (after $$$ is the syntax context):
```js
const bar$$$2 = (patch$$$3)=>patch$$$3 + 1;
const foo$$$2 = (patch$$$4)=>patch$$$4 !== patch$$$6;
```
after running `renamer`, it's this and that duplicate `patch1$$$0` seems to mess everything up after merging.
```js
const bar$$$2 = (patch1$$$0)=>patch1$$$0 + 1;
const foo$$$2 = (patch1$$$0)=>patch1$$$0 !== patch$$$6;
```
Generally, this looks fine still after merging and the syntax context translation (apart form the duplicate `patch1` parameter inherited from above)
```js
function patch$$$7() {
    return 2;
}
function patch$$$6() {
    return 1;
}
const bar$$$4 = (patch1$$$5)=>patch1$$$5 + 1;
const foo$$$4 = (patch1$$$5)=>patch1$$$5 !== patch$$$6;
```
but the output after the final hygiene call on the  AST is
```js
function patch() {
    return 2;
}
function patch1() {
    return 1;
}
const bar = (patch1)=>patch1 + 1;
const foo = (patch1)=>patch1 !== patch1; // the RHS should be different from the LHS
```

## The fix

`renamer_keep_contexts` together with `type Target = Id` is going to generate valid syntax contexts in the AST (i.e. no duplicate `patch1$$$0` as above. That fixes the bug

Changed files:
filename: turbopack/crates/turbopack-ecmascript/src/lib.rs
patch: @@ -2062,7 +2062,7 @@ fn hygiene_rename_only(
     }
     // Copied from `hygiene_with_config`'s HygieneRenamer, but added an `preserved_exports`
     impl swc_core::ecma::transforms::base::rename::Renamer for HygieneRenamer<'_> {
-        type Target = Atom;
+        type Target = Id;
 
         const MANGLE: bool = false;
         const RESET_N: bool = true;
@@ -2081,7 +2081,7 @@ fn hygiene_rename_only(
             self.preserved_exports.contains(orig) || orig.1.has_mark(self.is_import_mark)
         }
     }
-    swc_core::ecma::transforms::base::rename::renamer(
+    swc_core::ecma::transforms::base::rename::renamer_keep_contexts(
         swc_core::ecma::transforms::base::hygiene::Config {
             top_level_mark: top_level_mark.unwrap_or_default(),
             ..Default::default()

filename: turbopack/crates/turbopack-tests/tests/execution/turbopack/scope-hoisting/renaming-2/input/index.js
patch: @@ -0,0 +1,5 @@
+import { foo } from './internal/index.js'
+
+it('should correctly rename imports', () => {
+  expect(foo({})).toBe(true)
+})

filename: turbopack/crates/turbopack-tests/tests/execution/turbopack/scope-hoisting/renaming-2/input/internal/index.js
patch: @@ -0,0 +1,5 @@
+import './patch-other.js'
+import { patch as patch2 } from './patch.js'
+
+export const bar = (patch) => patch + 1
+export const foo = (patch) => patch !== patch2

filename: turbopack/crates/turbopack-tests/tests/execution/turbopack/scope-hoisting/renaming-2/input/internal/patch-other.js
patch: @@ -0,0 +1,3 @@
+export function patch() {
+  return 2
+}

filename: turbopack/crates/turbopack-tests/tests/execution/turbopack/scope-hoisting/renaming-2/input/internal/patch.js
patch: @@ -0,0 +1,3 @@
+export function patch() {
+  return 1
+}