diff --git a/lib/compress.js b/lib/compress.js index 6286741f34..24446b251d 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -2391,21 +2391,36 @@ merge(Compressor.prototype, { return null; } + function find_stop_logical(parent, op, level) { + var node; + do { + node = parent; + parent = scanner.parent(++level); + } while (parent instanceof AST_Assign && parent.operator.slice(0, -1) == op + || parent instanceof AST_Binary && parent.operator == op); + return node; + } + function find_stop_value(node, level) { var parent = scanner.parent(level); if (parent instanceof AST_Array) return find_stop_value(parent, level + 1); - if (parent instanceof AST_Assign) return may_throw(parent) || parent.left.match_symbol(function(ref) { - return ref instanceof AST_SymbolRef && (lhs.name == ref.name || value_def.name == ref.name); - }) ? node : find_stop_value(parent, level + 1); + if (parent instanceof AST_Assign) { + if (may_throw(parent)) return node; + if (parent.left.match_symbol(function(ref) { + return ref instanceof AST_SymbolRef && (lhs.name == ref.name || value_def.name == ref.name); + })) return node; + var op; + if (parent.left === node || !lazy_op[op = parent.operator.slice(0, -1)]) { + return find_stop_value(parent, level + 1); + } + return find_stop_logical(parent, op, level); + } if (parent instanceof AST_Binary) { - if (lazy_op[parent.operator] && parent.left !== node) { - do { - node = parent; - parent = scanner.parent(++level); - } while (parent instanceof AST_Binary && parent.operator == node.operator); - return node; + var op; + if (parent.left === node || !lazy_op[op = parent.operator]) { + return find_stop_value(parent, level + 1); } - return find_stop_value(parent, level + 1); + return find_stop_logical(parent, op, level); } if (parent instanceof AST_Call) return parent; if (parent instanceof AST_Case) { @@ -5325,8 +5340,9 @@ merge(Compressor.prototype, { var tw = new TreeWalker(function(node, descend) { if (node instanceof AST_Assign) { var lhs = node.left; + var rhs = node.right; if (lhs instanceof AST_Destructured) { - node.right.walk(tw); + rhs.walk(tw); var marker = new TreeWalker(function(node) { if (node instanceof AST_Destructured) return; if (node instanceof AST_DefaultValue) { @@ -5354,9 +5370,17 @@ merge(Compressor.prototype, { lhs.walk(marker); return true; } + if (lazy_op[node.operator.slice(0, -1)]) { + lhs.walk(tw); + push(); + rhs.walk(tw); + if (lhs instanceof AST_SymbolRef) mark(lhs); + pop(); + return true; + } if (lhs instanceof AST_SymbolRef) { if (node.operator != "=") mark(lhs, true); - node.right.walk(tw); + rhs.walk(tw); mark(lhs); return true; } diff --git a/test/compress/assignments.js b/test/compress/assignments.js index 80538bd8df..3973e2f57a 100644 --- a/test/compress/assignments.js +++ b/test/compress/assignments.js @@ -603,3 +603,72 @@ issue_4819: { expect_stdout: "true" node_version: ">=15" } + +issue_4827_1: { + options = { + collapse_vars: true, + toplevel: true, + } + input: { + A = "FAIL"; + var a = A, b = "PASS", c; + c &&= b = a, console.log(b); + } + expect: { + A = "FAIL"; + var a = A, b = "PASS", c; + c &&= b = a, console.log(b); + } + expect_stdout: "PASS" + node_version: ">=15" +} + +issue_4827_2: { + options = { + collapse_vars: true, + inline: true, + reduce_vars: true, + side_effects: true, + toplevel: true, + unused: true, + } + input: { + var a = 0, b = "PASS"; + function f(c) { + a++, + c &&= b = a; + } + f(); + console.log(b); + } + expect: { + var a = 0, b = "PASS"; + a++, + c &&= b = a; + var c; + console.log(b); + } + expect_stdout: "PASS" + node_version: ">=15" +} + +issue_4827_3: { + options = { + merge_vars: true, + toplevel: true, + } + input: { + var a = 0, b, c; + a++; + c &&= b = a; + console.log(b); + } + expect: { + var a = 0, b, c; + a++; + c &&= b = a; + console.log(b); + } + expect_stdout: "undefined" + node_version: ">=15" +}