diff --git a/lib/compress.js b/lib/compress.js index d05f3572..49f2cd39 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -2477,24 +2477,24 @@ Compressor.prototype.compress = function(node) { can_replace = false; var after = stop_after; var if_hit = stop_if_hit; - if (!all(fn.argnames, function(argname) { - if (argname instanceof AST_DefaultValue) { - argname.value.transform(scanner); - if (abort) return false; - argname = argname.name; + for (var i = 0; !abort && i < fn.argnames.length; i++) { + if (may_throw_arg(reject, fn.argnames[i], node.args[i])) abort = true; + } + if (!abort) { + if (fn.rest && may_throw_arg(reject, fn.rest, make_node(AST_Array, node, { + elements: node.args.slice(i), + }))) { + abort = true; + } else if (is_arrow(fn) && fn.value) { + fn.value.transform(scanner); + } else for (var i = 0; !abort && i < fn.body.length; i++) { + var stat = fn.body[i]; + if (stat instanceof AST_Return) { + if (stat.value) stat.value.transform(scanner); + break; + } + stat.transform(scanner); } - return !(argname instanceof AST_Destructured); - })) { - abort = true; - } else if (is_arrow(fn) && fn.value) { - fn.value.transform(scanner); - } else for (var i = 0; !abort && i < fn.body.length; i++) { - var stat = fn.body[i]; - if (stat instanceof AST_Return) { - if (stat.value) stat.value.transform(scanner); - break; - } - stat.transform(scanner); } stop_if_hit = if_hit; stop_after = after; @@ -2560,28 +2560,35 @@ Compressor.prototype.compress = function(node) { return node instanceof AST_SymbolRef && (lvalues.has(node.name) || read_toplevel && compressor.exposed(node.definition())); }, true); + + function reject(node) { + node.transform(scanner); + return abort; + } } - function may_throw_destructured(node, value) { - if (!value) return !(node instanceof AST_Symbol); + function may_throw_arg(reject, node, value) { if (node instanceof AST_DefaultValue) { - return value.has_side_effects(compressor) - || node.value.has_side_effects(compressor) - || may_throw_destructured(node.name, is_undefined(value) && node.value); + return reject(node.value) + || may_throw_arg(reject, node.name, node.value) + || !is_undefined(value) && may_throw_arg(reject, node.name, value); } + if (!value) return !(node instanceof AST_Symbol); if (node instanceof AST_Destructured) { - if (node.rest && may_throw_destructured(node.rest)) return true; + if (node.rest && may_throw_arg(reject, node.rest)) return true; if (node instanceof AST_DestructuredArray) { - if (!(value instanceof AST_Array || value.is_string(compressor))) return true; - return !all(node.elements, function(element) { - return !may_throw_destructured(element); + if (value instanceof AST_Array) return !all(node.elements, function(element, index) { + return !may_throw_arg(reject, element, value[index]); + }); + return value.is_string(compressor) && !all(node.elements, function(element) { + return !may_throw_arg(reject, element); }); } if (node instanceof AST_DestructuredObject) { if (!value.is_defined(compressor)) return true; return !all(node.properties, function(prop) { - if (prop instanceof AST_Node && prop.has_side_effects(compressor)) return false; - return !may_throw_destructured(prop.value); + if (prop.key instanceof AST_Node && reject(prop.key)) return false; + return !may_throw_arg(reject, prop.value); }); } } @@ -2645,7 +2652,9 @@ Compressor.prototype.compress = function(node) { args[len + i] = value; } if (sym instanceof AST_Destructured) { - if (!may_throw_destructured(sym, arg)) continue; + if (!may_throw_arg(function(node) { + return node.has_side_effects(compressor); + }, sym, arg)) continue; candidates.length = 0; break; } @@ -2668,6 +2677,7 @@ Compressor.prototype.compress = function(node) { candidate.arg_index = value ? len + i : i; candidates.unshift([ candidate ]); } + if (fn.rest) args.push(fn.rest); } } diff --git a/test/compress/rests.js b/test/compress/rests.js index b736a055..b18ab0b4 100644 --- a/test/compress/rests.js +++ b/test/compress/rests.js @@ -1531,3 +1531,96 @@ issue_5533_2_drop_fargs: { expect_stdout: "PASS" node_version: ">=6" } + +issue_5552_1: { + options = { + collapse_vars: true, + reduce_vars: true, + toplevel: true, + } + input: { + var log = console.log; + var a = f, b = log(); + function f(...[ c = a = "PASS" ]) {} + f((a = "FAIL", b)); + log(a); + } + expect: { + var log = console.log; + var a = f, b = log(); + function f(...[ c = a = "PASS" ]) {} + f((a = "FAIL", b)); + log(a); + } + expect_stdout: [ + "", + "PASS", + ] + node_version: ">=6" +} + +issue_5552_2: { + options = { + collapse_vars: true, + reduce_vars: true, + toplevel: true, + } + input: { + var log = console.log; + var a = f; + function f(...{ [a = "PASS"]: b }) {} + f((a = "FAIL", 42)); + log(a); + } + expect: { + var log = console.log; + var a = f; + function f(...{ [a = "PASS"]: b }) {} + f((a = "FAIL", 42)); + log(a); + } + expect_stdout: "PASS" + node_version: ">=6" +} + +issue_5552_3: { + options = { + collapse_vars: true, + unused: true, + } + input: { + var a = [ "FAIL", "PASS" ]; + console.log(function(b, ...[ c = a.pop() ]) { + return b; + }(a.pop())); + } + expect: { + var a = [ "FAIL", "PASS" ]; + console.log(function(b, ...[ c = a.pop() ]) { + return b; + }(a.pop())); + } + expect_stdout: "PASS" + node_version: ">=6" +} + +issue_5552_4: { + options = { + collapse_vars: true, + unused: true, + } + input: { + var a = [ "FAIL", "PASS" ]; + console.log(function(b, ...{ [a.pop()]: c }) { + return b; + }(a.pop())); + } + expect: { + var a = [ "FAIL", "PASS" ]; + console.log(function(b, ...{ [a.pop()]: c }) { + return b; + }(a.pop())); + } + expect_stdout: "PASS" + node_version: ">=6" +}