Repository: mishoo/UglifyJS (JavaScript)

Issue:
ufuzz failure
```js
// original code
// (beautified)
var _calls_ = 10, a = 100, b = 10, c = 0;

{
    var brake2 = 5;
    while (await (1 === 1 ? a : b) && --brake2 > 0) {
        {
            var a_1 = function f0(NaN, await_2) {
                function f1(bar, b_1) {}
                var bar_1 = f1(await_2 && typeof await_2.set == "function" && --_calls_ >= 0 && await_2.set(0));
                function f2(bar_1_2) {
                    function f3(a_1) {
                        c = 1 + c, (Object.isExtensible(a_1) && (a_1[!function() {
                        }()] += ("a" != "number") << "b" + /[a2][^e]+$/)) == (-2 && "c") <= 38..toString() >> Infinity;
                    }
                    var b = f3((c = 1 + c, (5 / NaN !== 24..toString() * "object") << (("function" === 5) > 3 + 3)), (c = 1 + c, 
                    (c = c + 1, "number" + null) || (c = c + 1, 0) << (c = c + 1, 
                    NaN)));
                }
                var b_2 = f2(~b);
            }(...[]);
        }
        try {
            var bar_1 = a++ + (typeof b != "crap" || a || 3).toString(), NaN = void ((-4 % null >>> (3 >= -1)) % ((c = c + 1, 
            23..toString()) >= (false <= "object")));
        } finally {}
    }
}

var b_1 = b_1 && b_1.c;

console.log(null, a, b, c, Infinity, NaN, undefined);
```
```js
// uglified code
// (beautified)
for (var t = 10, o = 100, i = 0, n = 5; await o && 0 < --n; ) {
    var e = v = void 0, r = void 0, g = (r && "function" == typeof r.set && 0 <= --t && r.set(0), 
    i = 1 + i, r = (5 / e != "object" * 24..toString()) << !1, i = 1 + i, i = 1 + (i += 1), 
    Object.isExtensible(r) && (r[!0] += 1), 38..toString(), o++, (!0).toString(), 
    void (i += 1, 23..toString()));
}

console.log(null, o, 10, i, 1 / 0, g, void 0);
```
```
original result:
null 104 10 20 Infinity undefined undefined

uglified result:
ReferenceError: v is not defined
    at [stdin]:190:51
    at <anonymous>
    at process._tickCallback (internal/process/next_tick.js:189:7)
    at evalScript (bootstrap_node.js:482:13)
    at Socket.<anonymous> (bootstrap_node.js:250:15)
    at emitNone (events.js:111:20)
    at Socket.emit (events.js:208:7)
    at endReadableNT (_stream_readable.js:1064:12)
    at _combinedTickCallback (internal/process/next_tick.js:139:11)
    at process._tickCallback (internal/process/next_tick.js:181:9)
```
```js
// reduced test case (output will differ)

// (beautified)
var brake2;

while (1) {
    var a_1 = function f0(await_2) {
        await_2();
        function f3(a_1) {
            a_1[0];
        }
        var b = f3(0, 0());
    }();
    var NaN = 0;
}

0(NaN);
// output: TypeError: await_2 is not a function
// minify: ReferenceError: h is not defined
// options: {
//   "mangle": {
//     "v8": true
//   },
//   "output": {
//     "v8": true
//   },
//   "module": true,
//   "validate": true
// }
```
```
minify(options):
{
  "mangle": {
    "v8": true
  },
  "output": {
    "v8": true
  },
  "module": true
}

Suspicious compress options:
  dead_code
  inline
  join_vars
  loops
  merge_vars
  reduce_vars
  unused

Suspicious options:
  module
  rename
  toplevel
```


Discussion:

Patch:
diff --git a/lib/compress.js b/lib/compress.js
index cb3cd3653b8..2dd3e9bf683 100644
--- a/lib/compress.js
+++ b/lib/compress.js
@@ -6662,15 +6662,15 @@ Compressor.prototype.compress = function(node) {
             do {
                 var head = first.shift();
                 if (tail.index > head.index) continue;
-                var id = head.definition.id;
-                if (!(id in prev)) continue;
-                var head_refs = references[id];
+                var prev_def = head.definition;
+                if (!(prev_def.id in prev)) continue;
+                var head_refs = references[prev_def.id];
                 if (!head_refs) continue;
                 if (head_refs.start.block !== tail_refs.start.block
                     || !mergeable(head_refs, tail_refs)
                     || (head_refs.start.loop || !same_scope(def)) && !mergeable(tail_refs, head_refs)
-                    || compressor.option("webkit") && is_funarg(def) !== is_funarg(head.definition)
-                    || head.definition.const_redefs
+                    || compressor.option("webkit") && is_funarg(def) !== is_funarg(prev_def)
+                    || prev_def.const_redefs
                     || !all(head_refs.scopes, function(scope) {
                         return scope.find_variable(def.name) === def;
                     })) {
@@ -6682,12 +6682,14 @@ Compressor.prototype.compress = function(node) {
                     sym.name = def.name;
                     if (sym instanceof AST_SymbolRef) {
                         def.references.push(sym);
+                        prev_def.replaced++;
                     } else {
                         def.orig.push(sym);
+                        prev_def.eliminated++;
                     }
                 });
-                if (!head.definition.fixed) def.fixed = false;
-                merged[id] = def;
+                if (!prev_def.fixed) def.fixed = false;
+                merged[prev_def.id] = def;
                 changed = true;
                 break;
             } while (first.length);


Test patch:
diff --git a/test/compress/merge_vars.js b/test/compress/merge_vars.js
index 7082491ef67..e7b1be3a836 100644
--- a/test/compress/merge_vars.js
+++ b/test/compress/merge_vars.js
@@ -3845,3 +3845,47 @@ issue_5471_2: {
     }
     expect_stdout: "PASS"
 }
+
+issue_5714: {
+    options = {
+        inline: true,
+        join_vars: true,
+        loops: true,
+        merge_vars: true,
+        unused: true,
+    }
+    input: {
+        "use strict";
+        console.log(function() {
+            var i = 1;
+            while (i--) {
+                var a = function f(b) {
+                    console.log(b);
+                    var c = function(d) {
+                        console.log(typeof d);
+                    }(console);
+                }();
+                var e = 42;
+            }
+            return e;
+        }());
+    }
+    expect: {
+        "use strict";
+        console.log(function() {
+            for (var i = 1; i--;) {
+                var b = void 0;
+                console.log(b);
+                b = console,
+                console.log(typeof b);
+                var e = 42;
+            }
+            return e;
+        }());
+    }
+    expect_stdout: [
+        "undefined",
+        "object",
+        "42",
+    ]
+}