Repository: mishoo/UglifyJS (JavaScript)

Issue:
bug in `sequences`
```js
// original code
// (beautified)
a = "PASS";

console.log(a);

for (const a in 42) {}
```
```js
// uglified code
// (beautified)
for (const a in a = "PASS", console.log(a), 42) {}
```
```
original result:
PASS

uglified result:
evalmachine.<anonymous>:1
for(const a in a="PASS",console.log(a),42);
                ^

ReferenceError: Cannot access 'a' before initialization
    at evalmachine.<anonymous>:1:17
    at Script.runInContext (node:vm:141:12)
    at Object.runInContext (node:vm:292:6)
    at run_code_vm (UglifyJS\test\sandbox.js:227:12)
    at Object.exports.run_code (UglifyJS\test\sandbox.js:37:16)
    at UglifyJS\test\ufuzz\index.js:2320:37
    at Array.forEach (<anonymous>)
    at Object.<anonymous> (UglifyJS\test\ufuzz\index.js:2311:20)
    at Module._compile (node:internal/modules/cjs/loader:1108:14)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1137:10)
```
```js
// reduced test case (output will differ)

// (beautified)
a = 0;

for (const a in 0) {}
// output:
// minify: ReferenceError: Cannot access 'a' before initialization
// options: {
//   "mangle": false,
//   "output": {
//     "v8": true
//   },
//   "validate": true
// }
```
```
minify(options):
{
  "mangle": false,
  "output": {
    "v8": true
  }
}

Suspicious compress options:
  sequences
```


Discussion:

Patch:
diff --git a/lib/compress.js b/lib/compress.js
index 2b28c754a8c..08b0987ac5d 100644
--- a/lib/compress.js
+++ b/lib/compress.js
@@ -3118,7 +3118,7 @@ merge(Compressor.prototype, {
                             }
                         }
                     } else if (stat instanceof AST_ForIn) {
-                        stat.object = cons_seq(stat.object);
+                        if (!is_lexical_definition(stat.init)) stat.object = cons_seq(stat.object);
                     } else if (stat instanceof AST_If) {
                         stat.condition = cons_seq(stat.condition);
                     } else if (stat instanceof AST_Switch) {


Test patch:
diff --git a/test/compress/const.js b/test/compress/const.js
index 38cd8fbd1d7..be49e845e73 100644
--- a/test/compress/const.js
+++ b/test/compress/const.js
@@ -1434,3 +1434,23 @@ issue_4527: {
     }
     expect_stdout: "aaaa"
 }
+
+issue_4689: {
+    options = {
+        sequences: true,
+    }
+    input: {
+        "use strict";
+        var a = "PASS";
+        console.log(a);
+        for (const a in 42);
+    }
+    expect: {
+        "use strict";
+        var a = "PASS";
+        console.log(a);
+        for (const a in 42);
+    }
+    expect_stdout: "PASS"
+    node_version: ">=4"
+}
diff --git a/test/compress/let.js b/test/compress/let.js
index 7a9db16928a..b5005ebf687 100644
--- a/test/compress/let.js
+++ b/test/compress/let.js
@@ -1319,7 +1319,6 @@ issue_4531_2: {
         toplevel: true,
     }
     input: {
-        "use strict";
         var a = console;
         console.log(typeof a, function a() {
             let { [console]: a } = 0 && a;
@@ -1328,7 +1327,6 @@ issue_4531_2: {
         }());
     }
     expect: {
-        "use strict";
         var o = console;
         console.log(typeof o, function o() {
             let { [console]: o } = 0;
@@ -1339,3 +1337,23 @@ issue_4531_2: {
     expect_stdout: "object undefined"
     node_version: ">=6"
 }
+
+issue_4689: {
+    options = {
+        sequences: true,
+    }
+    input: {
+        "use strict";
+        var a = "PASS";
+        console.log(a);
+        for (let a in 42);
+    }
+    expect: {
+        "use strict";
+        var a = "PASS";
+        console.log(a);
+        for (let a in 42);
+    }
+    expect_stdout: "PASS"
+    node_version: ">=4"
+}