diff --git a/lib/compress.js b/lib/compress.js index 2dd3e9bf68..cde397cf2e 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -501,6 +501,23 @@ Compressor.prototype.compress = function(node) { if (parent instanceof AST_VarDef) return parent.value === node; } + function make_ref(ref, fixed) { + var node = make_node(AST_SymbolRef, ref); + node.fixed = fixed || make_node(AST_Undefined, ref); + return node; + } + + function replace_ref(resolve, fixed) { + return function(node) { + var ref = resolve(node); + var node = make_ref(ref, fixed); + var def = ref.definition(); + def.references.push(node); + def.replaced++; + return node; + }; + } + var RE_POSITIVE_INTEGER = /^(0|[1-9][0-9]*)$/; (function(def) { def(AST_Node, noop); @@ -705,22 +722,6 @@ Compressor.prototype.compress = function(node) { }); } - function make_ref(ref, fixed) { - var node = make_node(AST_SymbolRef, ref); - node.fixed = fixed || make_node(AST_Undefined, ref); - return node; - } - - function replace_ref(ref, fixed) { - return function() { - var node = make_ref(ref, fixed); - var def = ref.definition(); - def.references.push(node); - def.replaced++; - return node; - }; - } - function ref_once(compressor, def) { return compressor.option("unused") && !def.scope.pinned() @@ -1021,7 +1022,9 @@ Compressor.prototype.compress = function(node) { }; left.fixed.assigns = !fixed || !fixed.assigns ? [ ld.orig[0] ] : fixed.assigns.slice(); left.fixed.assigns.push(node); - left.fixed.to_binary = replace_ref(left, fixed); + left.fixed.to_binary = replace_ref(function(node) { + return node.left; + }, fixed); } else { left.walk(tw); ld.fixed = false; @@ -1529,7 +1532,9 @@ Compressor.prototype.compress = function(node) { }); }; exp.fixed.assigns = fixed && fixed.assigns; - exp.fixed.to_prefix = replace_ref(exp, d.fixed); + exp.fixed.to_prefix = replace_ref(function(node) { + return node.expression; + }, d.fixed); } } else { exp.walk(tw); @@ -2156,7 +2161,7 @@ Compressor.prototype.compress = function(node) { abort = true; folded = make_node(AST_Binary, candidate, { operator: compound, - left: lhs.fixed && lhs.definition().fixed ? lhs.fixed.to_binary() : lhs, + left: lhs.fixed && lhs.definition().fixed ? lhs.fixed.to_binary(candidate) : lhs, right: rvalue, }); } @@ -2220,7 +2225,7 @@ Compressor.prototype.compress = function(node) { } if (candidate instanceof AST_UnaryPostfix) return make_node(AST_UnaryPrefix, candidate, { operator: candidate.operator, - expression: lhs.fixed && lhs.definition().fixed ? lhs.fixed.to_prefix() : lhs, + expression: lhs.fixed && lhs.definition().fixed ? lhs.fixed.to_prefix(candidate) : lhs, }); if (candidate instanceof AST_UnaryPrefix) { clear_write_only(candidate); @@ -12780,34 +12785,19 @@ Compressor.prototype.compress = function(node) { } if (compressor.option("assignments")) { if (self.operator == "=" && self.left instanceof AST_SymbolRef && self.right instanceof AST_Binary) { - var ref; // x = expr1 OP expr2 - if ((ref = self.right.left) instanceof AST_SymbolRef - && ref.name == self.left.name + if (self.right.left instanceof AST_SymbolRef + && self.right.left.name == self.left.name && ASSIGN_OPS[self.right.operator]) { // x = x - 2 ---> x -= 2 - if (self.left.fixed) self.left.fixed.to_binary = function() { - return ref; - }; - return make_node(AST_Assign, self, { - operator: self.right.operator + "=", - left: self.left, - right: self.right.right, - }); + return make_compound(self.right.right); } - if ((ref = self.right.right) instanceof AST_SymbolRef - && ref.name == self.left.name + if (self.right.right instanceof AST_SymbolRef + && self.right.right.name == self.left.name && ASSIGN_OPS_COMMUTATIVE[self.right.operator] && !self.right.left.has_side_effects(compressor)) { // x = 2 & x ---> x &= 2 - if (self.left.fixed) self.left.fixed.to_binary = function() { - return ref; - }; - return make_node(AST_Assign, self, { - operator: self.right.operator + "=", - left: self.left, - right: self.right.left, - }); + return make_compound(self.right.left); } } if ((self.operator == "-=" || self.operator == "+=" @@ -12870,6 +12860,18 @@ Compressor.prototype.compress = function(node) { return find_try(compressor, level, node, scope, may_throw, sync); } + function make_compound(rhs) { + var fixed = self.left.fixed; + if (fixed) fixed.to_binary = replace_ref(function(node) { + return node.left; + }, fixed); + return make_node(AST_Assign, self, { + operator: self.right.operator + "=", + left: self.left, + right: rhs, + }); + } + function strip_assignment(def) { if (def) def.fixed = false; return (self.operator != "=" ? make_node(AST_Binary, self, { diff --git a/test/compress/reduce_vars.js b/test/compress/reduce_vars.js index 885887ede3..93eccafe98 100644 --- a/test/compress/reduce_vars.js +++ b/test/compress/reduce_vars.js @@ -7927,3 +7927,138 @@ issue_5623: { } expect_stdout: "1" } + +issue_5716_1: { + options = { + collapse_vars: true, + inline: true, + merge_vars: true, + reduce_vars: true, + toplevel: true, + unused: true, + } + input: { + var a; + function f() { + var b = [ c, c ], c = function() { + return b++ + (a = b); + }(); + } + f(); + console.log(a); + } + expect: { + c = [ c, c ], + void (c = ++c); + var c; + console.log(c); + } + expect_stdout: "NaN" +} + +issue_5716_2: { + options = { + collapse_vars: true, + inline: true, + merge_vars: true, + reduce_vars: true, + toplevel: true, + unused: true, + } + input: { + var a; + function f() { + var b = [ c, c ], c = function() { + return (b += 4) + (a = b += 2); + }(); + } + f(); + console.log(a); + } + expect: { + void (c = c = (c = [ c, c ]) + 4 + 2); + var c; + console.log(c); + } + expect_stdout: ",42" +} + +issue_5716_3: { + options = { + assignments: true, + collapse_vars: true, + inline: true, + merge_vars: true, + reduce_vars: true, + toplevel: true, + unused: true, + } + input: { + var a; + function f() { + var b = [ c, c ], c = function() { + return (b = b + 4) + (a = b += 2); + }(); + } + f(); + console.log(a); + } + expect: { + void (c = c = (c = [ c, c ]) + 4 + 2); + var c; + console.log(c); + } + expect_stdout: ",42" +} + +issue_5716_4: { + options = { + assignments: true, + collapse_vars: true, + inline: true, + merge_vars: true, + reduce_vars: true, + toplevel: true, + unused: true, + } + input: { + var a; + function f() { + var b = [ c, c ], c = function() { + return (b = true | b) + (a = b *= 42); + }(); + } + f(); + console.log(a); + } + expect: { + void (c = c = ((c = [ c, c ]) | true) * 42); + var c; + console.log(c); + } + expect_stdout: "42" +} + +issue_5716_5: { + options = { + assignments: true, + reduce_vars: true, + } + input: { + console.log(function() { + return 0 || (a = 42 | a); + var a = function() { + return a; + }; + }()); + } + expect: { + console.log(function() { + return 0 || (a |= 42); + var a = function() { + return a; + }; + }()); + } + expect_stdout: "42" +}