Repository: swc-project/swc (rust)

Issue:
minify with mangle create incorrect code
### Describe the bug

it generates a code `(r?r=>r(e(r))` which should be `state=>selectorTransformer(selector(state))` (in unmangled mode).

the `r` is conflicting here, where the `r` in `r(e(r))` is referring to both `r` in the arrow function scope, (`state`) and `r` in the outer scope, `selectTransformer`.

the mangled code should keep track of the variable names in the scope

### Input code

```typescript
function memoizeWithArgs(
  fnWithArgs,
  options
) {
  const fn = proxyMemoize((args) => fnWithArgs(...args), options);
  return (...args) => fn(args);
}


function makeSelector(
  selector,
  selectorTransformer
) {
  return (state) => selectorTransformer(selector(state));
}

export function createSelectorHook(
  selector
) {
  const useSelectorHook = (
    selectorTransformer,
    deps
  ) => {
    const memoSelector = useMemo(
      () =>
        selectorTransformer && deps
          ? makeSelector(selector, memoizeWithArgs(selectorTransformer))
          : undefined,
      deps
    );
    const finalSelector = memoSelector
      ? memoSelector
      : selectorTransformer
      ? makeSelector(selector, selectorTransformer)
      : selector;
    return useSelector(finalSelector);
  };
  return useSelectorHook
}
```


### 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": {
        "toplevel": false,
        "keep_classnames": false,
        "keep_fnames": false,
        "keep_private_props": false,
        "ie8": false,
        "safari10": false
      }
    }
  },
  "module": {
    "type": "es6"
  },
  "minify": true,
  "isModule": true
}
```


### Playground link (or link to the minimal reproduction)

https://play.swc.rs/?version=1.3.94-nightly-20231016.1&code=H4sIAAAAAAAAA4WSz2rDMAzG734KnYoDIQ%2FQ0o3ddtmpg51DomyhjR1sB7qVvPvkvziLYT7J8uefP0keFtGZUQqYcJLjD36M5utFfWrOAAYRdzXt5Gx1mlXwoF1HoSEFnGFW8v795q9z3pK8gvNTdps3TePSdYRUJ0IoNIsSkE79JQ84sZUxNiRz7RUveMPOSGWd6RDXWfyuWqEHqSZUwWN8QJvWoMMXtDzmgsw%2FjfdZKqovGugU0mG08CrlNbex6cmiNzpqkJUWfdbuoMdZU%2BAMPlzGg%2BxEIokoxLVN9jAAbvUhLsLhcIjouJ63jUxd3A2%2FgKuqDHSERfQ4jAL7OqTTU2626YOMor1lReQ1sWRqnzwWx%2FpPFSXXO553F75GNiu%2BseqKWLNf%2BmeqbP0FxQEFEzkDAAA%3D&config=H4sIAAAAAAAAA41VQY7bMAy87ysCn3vY5lAUfUBvfYOgWJSjVBYNkfImWOTvpRU7m93QRi9BzNGQIjmk3l92u%2BZEbfNr9y5%2F5WOwmSDfv8VCl8T2LJYG2t5Sm8PAzbcFPdEEeRsJqul6Qxq2uQOuLNq%2F7vczo4mIBAtjtvUhBX95jNliP2QgerCJVVyWHhLTZ%2F6MZXybAM7l0X5AjGDTBmIsmZAYOsia4xZjtAOBGW1WvEw3tTkQaiEmsDA4M2QcVDy5wAGTxHxGHVhnWnSgQCFDy2EEjSaxhJZI0lPyqbCDQ%2Bm62ucvbBhtLJaVmHCuLZHbKl6PGIiNL0kr4Q1cqcENnIv7lRm8ycAlp2feCUNa6clfAKlAtETJ9qD5rSe86GmN7TeZIXmRLF8UXPStZZmgk6KaELxS2akykDlo3czgSgtTZVvtOjO8Uj4KDgx4L1pRXNNb4PaoBeXLAOgVQPprvaaqG2DuU7iCTwOxAf%2BWLFkX2Hyit3xcR%2BnSHzBuBOiBj%2Bg2DkgrGNfhLFviPKzjJTkQaYBTjxSqwPMSkAFgNLHuyydtyHiIR9NFPHysifnA9b6He5u6Ou8P%2B5JxiDBCXJPxf4zIJip3GydVL5P9NL3wUxOllcEL318%2FPRuSysvyW5NqenTlIaGqydtz8qP5OLS8HEvVmkB%2FFmKt0%2FUfj5GfKOMGAAA%3D

### SWC Info output

_No response_

### Expected behavior

should minify into correct code

### Actual behavior

_No response_

### Version

1.3.94-nightly-20231016.1

### Additional context

_No response_

Pull request description:
fix(es/minifier): Apply new `SyntaxContext` to inlined `Arrow`
**Related issue:**

 - Closes #8288

Patch:
diff --git a/crates/swc_ecma_minifier/src/compress/optimize/iife.rs b/crates/swc_ecma_minifier/src/compress/optimize/iife.rs
index 841545f5e5..df8738e1f3 100644
--- a/crates/swc_ecma_minifier/src/compress/optimize/iife.rs
+++ b/crates/swc_ecma_minifier/src/compress/optimize/iife.rs
@@ -509,12 +509,11 @@ impl Optimizer<'_> {
                         //
                         // For arrow expressions this is required because we copy simple arrow
                         // expressions.
-                        let mut remap = HashMap::default();
-                        let new_ctxt = SyntaxContext::empty().apply_mark(Mark::fresh(Mark::root()));
-
-                        for p in param_ids.iter() {
-                            remap.insert(p.to_id(), new_ctxt);
-                        }
+                        let new_ctxt = SyntaxContext::empty().apply_mark(Mark::new());
+                        let remap = param_ids
+                            .iter()
+                            .map(|p| (p.to_id(), new_ctxt))
+                            .collect::<FxHashMap<_, _>>();
 
                         {
                             let vars = param_ids
@@ -843,7 +842,7 @@ impl Optimizer<'_> {
 
         // We remap variables.
         let mut remap = HashMap::default();
-        let new_ctxt = SyntaxContext::empty().apply_mark(Mark::fresh(Mark::root()));
+        let new_ctxt = SyntaxContext::empty().apply_mark(Mark::new());
 
         let params = orig_params
             .iter()
@@ -857,27 +856,25 @@ impl Optimizer<'_> {
             })
             .collect::<Vec<_>>();
 
-        {
-            for stmt in &body.stmts {
-                if let Stmt::Decl(Decl::Var(var)) = stmt {
-                    for decl in &var.decls {
-                        let ids: Vec<Id> = find_pat_ids(&decl.name);
-
-                        for id in ids {
-                            let ctx = remap
-                                .entry(id.clone())
-                                .or_insert_with(|| SyntaxContext::empty().apply_mark(Mark::new()));
-
-                            // [is_skippable_for_seq] would check fn scope
-                            if let Some(usage) = self.data.vars.get(&id) {
-                                let mut usage = usage.clone();
-                                // as we turn var declaration into assignment
-                                // we need to maintain correct var usage
-                                if decl.init.is_some() {
-                                    usage.ref_count += 1;
-                                }
-                                self.data.vars.insert((id.0, *ctx), usage);
+        for stmt in &body.stmts {
+            if let Stmt::Decl(Decl::Var(var)) = stmt {
+                for decl in &var.decls {
+                    let ids: Vec<Id> = find_pat_ids(&decl.name);
+
+                    for id in ids {
+                        let ctx = remap
+                            .entry(id.clone())
+                            .or_insert_with(|| SyntaxContext::empty().apply_mark(Mark::new()));
+
+                        // [is_skippable_for_seq] would check fn scope
+                        if let Some(usage) = self.data.vars.get(&id) {
+                            let mut usage = usage.clone();
+                            // as we turn var declaration into assignment
+                            // we need to maintain correct var usage
+                            if decl.init.is_some() {
+                                usage.ref_count += 1;
                             }
+                            self.data.vars.insert((id.0, *ctx), usage);
                         }
                     }
                 }
diff --git a/crates/swc_ecma_minifier/src/compress/optimize/inline.rs b/crates/swc_ecma_minifier/src/compress/optimize/inline.rs
index 0a4d10058a..b118d43e1a 100644
--- a/crates/swc_ecma_minifier/src/compress/optimize/inline.rs
+++ b/crates/swc_ecma_minifier/src/compress/optimize/inline.rs
@@ -1,8 +1,9 @@
-use swc_common::{util::take::Take, EqIgnoreSpan, Spanned};
+use rustc_hash::FxHashMap;
+use swc_common::{collections::AHashSet, util::take::Take, EqIgnoreSpan, Mark, Spanned};
 use swc_ecma_ast::*;
 use swc_ecma_transforms_optimization::simplify::expr_simplifier;
 use swc_ecma_usage_analyzer::alias::{collect_infects_from, AliasConfig};
-use swc_ecma_utils::{class_has_side_effect, find_pat_ids, ExprExt};
+use swc_ecma_utils::{class_has_side_effect, collect_decls, find_pat_ids, ExprExt, Remapper};
 use swc_ecma_visit::VisitMutWith;
 
 use super::Optimizer;
@@ -808,7 +809,7 @@ impl Optimizer<'_> {
             }
             Expr::Ident(i) => {
                 let id = i.to_id();
-                if let Some(value) = self
+                if let Some(mut value) = self
                     .vars
                     .lits
                     .get(&id)
@@ -827,6 +828,25 @@ impl Optimizer<'_> {
                         return;
                     }
 
+                    // currently renamer relies on the fact no distinct var has same ctxt, we need
+                    // to remap all new bindings.
+                    let bindings: AHashSet<Id> = collect_decls(&*value);
+                    let new_mark = Mark::new();
+                    let mut cache = FxHashMap::default();
+                    let remap: FxHashMap<_, _> = bindings
+                        .into_iter()
+                        .map(|id| {
+                            let value = cache
+                                .entry(id.1)
+                                .or_insert_with(|| id.1.apply_mark(new_mark));
+
+                            (id, *value)
+                        })
+                        .collect();
+
+                    let mut remapper = Remapper::new(&remap);
+                    value.visit_mut_with(&mut remapper);
+
                     self.changed = true;
                     report_change!("inline: Replacing a variable `{}` with cheap expression", i);
 


Test patch:
diff --git a/crates/swc_ecma_minifier/tests/full/issues/8288/input.js b/crates/swc_ecma_minifier/tests/full/issues/8288/input.js
new file mode 100644
index 0000000000..4f5dfa28d1
--- /dev/null
+++ b/crates/swc_ecma_minifier/tests/full/issues/8288/input.js
@@ -0,0 +1,30 @@
+function memoizeWithArgs(fnWithArgs, options) {
+    const fn = proxyMemoize((args) => fnWithArgs(...args), options);
+    return (...args) => fn(args);
+}
+
+function makeSelector(selector, selectorTransformer) {
+    return (state) => selectorTransformer(selector(state));
+}
+
+export function createSelectorHook(selector) {
+    const useSelectorHook = (selectorTransformer, deps) => {
+        const memoSelector = useMemo(
+            () =>
+                selectorTransformer && deps
+                    ? makeSelector(
+                          selector,
+                          memoizeWithArgs(selectorTransformer)
+                      )
+                    : undefined,
+            deps
+        );
+        const finalSelector = memoSelector
+            ? memoSelector
+            : selectorTransformer
+            ? makeSelector(selector, selectorTransformer)
+            : selector;
+        return useSelector(finalSelector);
+    };
+    return useSelectorHook;
+}
diff --git a/crates/swc_ecma_minifier/tests/full/issues/8288/output.js b/crates/swc_ecma_minifier/tests/full/issues/8288/output.js
new file mode 100644
index 0000000000..b23b1c067b
--- /dev/null
+++ b/crates/swc_ecma_minifier/tests/full/issues/8288/output.js
@@ -0,0 +1,1 @@
+export function createSelectorHook(e){return(o,r)=>{const t=useMemo(()=>{var t;return o&&r?(t=function(e,o){const r=proxyMemoize(o=>e(...o),void 0);return(...e)=>r(e)}(o),o=>t(e(o))):void 0},r)||(o?r=>o(e(r)):e);return useSelector(t)}}