diff --git a/lib/ast.js b/lib/ast.js index c4866f85..344d2eed 100644 --- a/lib/ast.js +++ b/lib/ast.js @@ -1999,7 +1999,7 @@ TreeWalker.prototype = { }, find_parent: function(type) { var stack = this.stack; - for (var i = stack.length; --i >= 0;) { + for (var i = stack.length - 1; --i >= 0;) { var x = stack[i]; if (x instanceof type) return x; } diff --git a/lib/compress.js b/lib/compress.js index 3df34c42..115408d0 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -2906,8 +2906,9 @@ merge(Compressor.prototype, { if (!value) { value = node; var def = node.definition(); + var escaped = node.fixed && node.fixed.escaped || def.escaped; if (!def.undeclared - && (def.assignments || !def.escaped || def.escaped.cross_scope) + && (def.assignments || !escaped || escaped.cross_scope) && (has_escaped(def, node.scope, node, tw.parent()) || !same_scope(def))) { well_defined = false; } @@ -2915,8 +2916,11 @@ merge(Compressor.prototype, { } else if (node instanceof AST_ObjectIdentity) { value = node; } - if (value) lvalues.add(node.name, is_modified(compressor, tw, node, value, 0)); - if (find_arguments && node instanceof AST_Sub) { + if (value) { + lvalues.add(node.name, is_modified(compressor, tw, node, value, 0)); + } else if (node instanceof AST_Lambda) { + if (!(tw.find_parent(AST_Call) || tw.find_parent(AST_Scope))) return true; + } else if (find_arguments && node instanceof AST_Sub) { scope.each_argname(function(argname) { if (!compressor.option("reduce_vars") || argname.definition().assignments) { if (!argname.definition().fixed) well_defined = false; @@ -3023,7 +3027,10 @@ merge(Compressor.prototype, { return false; } var def = lhs.definition(); - return def.references.length - def.replaced == referenced; + if (def.references.length - def.replaced == referenced) return true; + return def.fixed && lhs.fixed && def.references.filter(function(ref) { + return ref.fixed === lhs.fixed; + }).length == referenced; } function symbol_in_lvalues(sym, parent) { diff --git a/test/compress/collapse_vars.js b/test/compress/collapse_vars.js index 0df9d72f..16d8dc3d 100644 --- a/test/compress/collapse_vars.js +++ b/test/compress/collapse_vars.js @@ -9253,13 +9253,13 @@ issue_4920_2: { console.log(b); } expect: { - var o = { + var o; + var a = "PASS", b; + ({ get PASS() { a = "FAIL"; }, - }; - var a = "PASS", b; - o[b = a]; + })[b = a]; console.log(b); } expect_stdout: "PASS" @@ -9283,16 +9283,47 @@ issue_4920_3: { } expect: { var log = console.log; - var o = { + var o; + var a = "PASS", b; + ({ get PASS() { a = "FAIL"; }, + })[b = a]; + log(b); + } + expect_stdout: "PASS" +} + +issue_4920_4: { + options = { + collapse_vars: true, + toplevel: true, + } + input: { + var log = console.log; + var o = { + get [(a = "FAIL 1", "PASS")]() { + a = "FAIL 2"; + }, + }; + var a = "PASS", b; + o[b = a]; + log(b); + } + expect: { + var log = console.log; + var o = { + get [(a = "FAIL 1", "PASS")]() { + a = "FAIL 2"; + }, }; var a = "PASS", b; o[b = a]; log(b); } expect_stdout: "PASS" + node_version: ">=4" } issue_4935: { @@ -9482,3 +9513,56 @@ issue_5112_2: { } expect_stdout: "PASS" } + +issue_5182: { + options = { + arrows: true, + collapse_vars: true, + evaluate: true, + hoist_props: true, + inline: true, + merge_vars: true, + passes: 3, + reduce_vars: true, + sequences: true, + side_effects: true, + toplevel: true, + unused: true, + } + input: { + var con = console; + global.log = con.log; + var jump = function(x) { + console.log("JUMP:", x * 10); + return x + x; + }; + var jump2 = jump; + var run = function(x) { + console.log("RUN:", x * -10); + return x * x; + }; + var run2 = run; + var bar = (x, y) => { + console.log("BAR:", x + y); + return x - y; + }; + var bar2 = bar; + var obj = { + foo: bar2, + go: run2, + not_used: jump2, + }; + console.log(obj.foo(1, 2), global.log("PASS")); + } + expect: { + var obj = console; + global.log = obj.log, + console.log((console.log("BAR:", 3), -1), global.log("PASS")); + } + expect_stdout: [ + "BAR: 3", + "PASS", + "-1 undefined", + ] + node_version: ">=4" +}