diff --git a/lib/compress.js b/lib/compress.js index 453b6ed6..3745b764 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -6033,7 +6033,7 @@ Compressor.prototype.compress = function(node) { var NO_MERGE = makePredicate("arguments await yield"); AST_Scope.DEFMETHOD("merge_variables", function(compressor) { if (!compressor.option("merge_vars")) return; - var in_try, root, segment = {}, self = this; + var in_arg = [], in_try, root, segment = {}, self = this; var first = [], last = [], index = 0; var declarations = new Dictionary(); var references = Object.create(null); @@ -6183,45 +6183,29 @@ Compressor.prototype.compress = function(node) { return true; } if (node instanceof AST_Scope) { - push(); - segment.block = node; + var parent = tw.parent(); + var in_iife = parent && parent.TYPE == "Call" && parent.expression === node; + if (!in_iife) { + push(); + segment.block = node; + } if (node === self) root = segment; if (node instanceof AST_Lambda) { if (node.name) references[node.name.definition().id] = false; - var parent = tw.parent(); - var in_iife = parent && parent.TYPE == "Call" && parent.expression === node; var marker = node.uses_arguments && !tw.has_directive("use strict") ? function(node) { if (node instanceof AST_SymbolFunarg) references[node.definition().id] = false; } : function(node) { if (node instanceof AST_SymbolFunarg) mark(node); }; - var scanner = new TreeWalker(function(ref) { - if (ref instanceof AST_SymbolDeclaration) references[ref.definition().id] = false; - if (!(ref instanceof AST_SymbolRef)) return; - var def = ref.definition(); - var ldef = node.variables.get(ref.name); - if (ldef && (ldef === def - || def.undeclared - || node.parent_scope.find_variable(ref.name) === def)) { - references[def.id] = false; - references[ldef.id] = false; - } else if (in_iife) { - var save = segment; - pop(); - mark(ref, true); - segment = save; - } else { - mark(ref, true); - } - return true; - }); + in_arg.push(node); node.argnames.forEach(function(argname) { - argname.mark_symbol(marker, scanner); + argname.mark_symbol(marker, tw); }); - if (node.rest) node.rest.mark_symbol(marker, scanner); + if (node.rest) node.rest.mark_symbol(marker, tw); + in_arg.pop(); } walk_lambda(node, tw); - pop(); + if (!in_iife) pop(); return true; } if (node instanceof AST_Sub) { @@ -6433,7 +6417,16 @@ Compressor.prototype.compress = function(node) { } function mark(sym, read) { - var def = sym.definition(), ldef, seg = segment; + var def = sym.definition(), ldef; + if (read && !all(in_arg, function(fn) { + ldef = fn.variables.get(sym.name); + if (!ldef) return true; + if (!is_funarg(ldef)) return true; + return ldef !== def + && !def.undeclared + && fn.parent_scope.find_variable(sym.name) !== def; + })) return references[def.id] = references[ldef.id] = false; + var seg = segment; if (in_try) { push(); seg = segment; diff --git a/test/compress.js b/test/compress.js index 2b7259f7..f4469df6 100644 --- a/test/compress.js +++ b/test/compress.js @@ -69,9 +69,7 @@ function make_code(ast, options) { function parse_test(file) { var script = fs.readFileSync(file, "utf8"); try { - var ast = U.parse(script, { - filename: file - }); + var ast = U.parse(script, { filename: file }); } catch (e) { console.error("Caught error while parsing tests in " + file); console.error(e); @@ -98,14 +96,14 @@ function parse_test(file) { file: file, line: node.start.line, col: node.start.col, - code: make_code(node, { beautify: false }) + code: make_code(node, { beautify: false }), })); } function read_string(stat) { if (stat.TYPE == "SimpleStatement") { var body = stat.body; - switch(body.TYPE) { + switch (body.TYPE) { case "String": return body.value; case "Array": @@ -142,7 +140,7 @@ function parse_test(file) { ].indexOf(label.name) >= 0, tmpl("Unsupported label {name} [{line},{col}]", { name: label.name, line: label.start.line, - col: label.start.col + col: label.start.col, })); var stat = node.body; if (label.name == "expect_exact" || label.name == "node_version") { @@ -155,12 +153,12 @@ function parse_test(file) { var ctor = global[body.expression.name]; assert.ok(ctor === Error || ctor.prototype instanceof Error, tmpl("Unsupported expect_stdout format [{line},{col}]", { line: label.start.line, - col: label.start.col + col: label.start.col, })); test[label.name] = ctor.apply(null, body.args.map(function(node) { assert.ok(node instanceof U.AST_Constant, tmpl("Unsupported expect_stdout format [{line},{col}]", { line: label.start.line, - col: label.start.col + col: label.start.col, })); return node.value; })); diff --git a/test/compress/arrows.js b/test/compress/arrows.js index 9691648e..1d43df14 100644 --- a/test/compress/arrows.js +++ b/test/compress/arrows.js @@ -726,8 +726,8 @@ issue_4401: { expect: { (function() { var a = (b => b(a))(console.log || a); - var c = console.log; - c && c(typeof b); + var a = console.log; + a && a(typeof b); })(); } expect_stdout: [ diff --git a/test/compress/const.js b/test/compress/const.js index 8178747d..9601c588 100644 --- a/test/compress/const.js +++ b/test/compress/const.js @@ -184,12 +184,12 @@ merge_vars_2: { expect: { var a = 0; 1 && --a, - b = function f() { + a = function f() { const c = a && f; c.var += 0; }(), - void console.log(b); - var b; + void console.log(a); + var a; } expect_stdout: "undefined" } diff --git a/test/compress/default-values.js b/test/compress/default-values.js index 0dcbd862..9878820c 100644 --- a/test/compress/default-values.js +++ b/test/compress/default-values.js @@ -2239,3 +2239,77 @@ issue_5407: { ] node_version: ">=6" } + +issue_5444_1: { + options = { + merge_vars: true, + toplevel: true, + } + input: { + var a = 42; + var b = function({} = setImmediate(function() { + console.log(a++); + })) { + return this; + }(); + console.log(typeof b); + } + expect: { + var a = 42; + var b = function({} = setImmediate(function() { + console.log(a++); + })) { + return this; + }(); + console.log(typeof b); + } + expect_stdout: [ + "object", + "42", + ] + node_version: ">=6" +} + +issue_5444_2: { + options = { + merge_vars: true, + } + input: { + function f(a, b = a++) { + return b; + } + console.log(f("FAIL") || "PASS"); + } + expect: { + function f(a, b = a++) { + return b; + } + console.log(f("FAIL") || "PASS"); + } + expect_stdout: "PASS" + node_version: ">=6" +} + +issue_5444_3: { + options = { + merge_vars: true, + } + input: { + function f(a, b = function(c = a *= this) { + return c; + }()) { + return b; + } + console.log(f("FAIL") || "PASS"); + } + expect: { + function f(a, b = function(c = a *= this) { + return c; + }()) { + return b; + } + console.log(f("FAIL") || "PASS"); + } + expect_stdout: "PASS" + node_version: ">=6" +} diff --git a/test/compress/destructured.js b/test/compress/destructured.js index 165f5ad4..847ab87c 100644 --- a/test/compress/destructured.js +++ b/test/compress/destructured.js @@ -1815,8 +1815,8 @@ issue_4288: { console.log(typeof b); }()]: a, }) { - var b = a; - b++; + var a = a; + a++; } f(0); } diff --git a/test/compress/let.js b/test/compress/let.js index d0261fc4..34308ab8 100644 --- a/test/compress/let.js +++ b/test/compress/let.js @@ -237,12 +237,12 @@ merge_vars_2: { "use strict"; var a = 0; 1 && --a, - b = function f() { + a = function f() { let c = a && f; c.var += 0; }(), - void console.log(b); - var b; + void console.log(a); + var a; } expect_stdout: "undefined" node_version: ">=4"