Skip to content

Commit 19c471c

Browse files
authored
fix corner cases in reduce_vars (#5717)
fixes #5716
1 parent 8319bad commit 19c471c

File tree

2 files changed

+178
-41
lines changed

2 files changed

+178
-41
lines changed

Diff for: lib/compress.js

+43-41
Original file line numberDiff line numberDiff line change
@@ -501,6 +501,23 @@ Compressor.prototype.compress = function(node) {
501501
if (parent instanceof AST_VarDef) return parent.value === node;
502502
}
503503

504+
function make_ref(ref, fixed) {
505+
var node = make_node(AST_SymbolRef, ref);
506+
node.fixed = fixed || make_node(AST_Undefined, ref);
507+
return node;
508+
}
509+
510+
function replace_ref(resolve, fixed) {
511+
return function(node) {
512+
var ref = resolve(node);
513+
var node = make_ref(ref, fixed);
514+
var def = ref.definition();
515+
def.references.push(node);
516+
def.replaced++;
517+
return node;
518+
};
519+
}
520+
504521
var RE_POSITIVE_INTEGER = /^(0|[1-9][0-9]*)$/;
505522
(function(def) {
506523
def(AST_Node, noop);
@@ -705,22 +722,6 @@ Compressor.prototype.compress = function(node) {
705722
});
706723
}
707724

708-
function make_ref(ref, fixed) {
709-
var node = make_node(AST_SymbolRef, ref);
710-
node.fixed = fixed || make_node(AST_Undefined, ref);
711-
return node;
712-
}
713-
714-
function replace_ref(ref, fixed) {
715-
return function() {
716-
var node = make_ref(ref, fixed);
717-
var def = ref.definition();
718-
def.references.push(node);
719-
def.replaced++;
720-
return node;
721-
};
722-
}
723-
724725
function ref_once(compressor, def) {
725726
return compressor.option("unused")
726727
&& !def.scope.pinned()
@@ -1021,7 +1022,9 @@ Compressor.prototype.compress = function(node) {
10211022
};
10221023
left.fixed.assigns = !fixed || !fixed.assigns ? [ ld.orig[0] ] : fixed.assigns.slice();
10231024
left.fixed.assigns.push(node);
1024-
left.fixed.to_binary = replace_ref(left, fixed);
1025+
left.fixed.to_binary = replace_ref(function(node) {
1026+
return node.left;
1027+
}, fixed);
10251028
} else {
10261029
left.walk(tw);
10271030
ld.fixed = false;
@@ -1529,7 +1532,9 @@ Compressor.prototype.compress = function(node) {
15291532
});
15301533
};
15311534
exp.fixed.assigns = fixed && fixed.assigns;
1532-
exp.fixed.to_prefix = replace_ref(exp, d.fixed);
1535+
exp.fixed.to_prefix = replace_ref(function(node) {
1536+
return node.expression;
1537+
}, d.fixed);
15331538
}
15341539
} else {
15351540
exp.walk(tw);
@@ -2156,7 +2161,7 @@ Compressor.prototype.compress = function(node) {
21562161
abort = true;
21572162
folded = make_node(AST_Binary, candidate, {
21582163
operator: compound,
2159-
left: lhs.fixed && lhs.definition().fixed ? lhs.fixed.to_binary() : lhs,
2164+
left: lhs.fixed && lhs.definition().fixed ? lhs.fixed.to_binary(candidate) : lhs,
21602165
right: rvalue,
21612166
});
21622167
}
@@ -2220,7 +2225,7 @@ Compressor.prototype.compress = function(node) {
22202225
}
22212226
if (candidate instanceof AST_UnaryPostfix) return make_node(AST_UnaryPrefix, candidate, {
22222227
operator: candidate.operator,
2223-
expression: lhs.fixed && lhs.definition().fixed ? lhs.fixed.to_prefix() : lhs,
2228+
expression: lhs.fixed && lhs.definition().fixed ? lhs.fixed.to_prefix(candidate) : lhs,
22242229
});
22252230
if (candidate instanceof AST_UnaryPrefix) {
22262231
clear_write_only(candidate);
@@ -12780,34 +12785,19 @@ Compressor.prototype.compress = function(node) {
1278012785
}
1278112786
if (compressor.option("assignments")) {
1278212787
if (self.operator == "=" && self.left instanceof AST_SymbolRef && self.right instanceof AST_Binary) {
12783-
var ref;
1278412788
// x = expr1 OP expr2
12785-
if ((ref = self.right.left) instanceof AST_SymbolRef
12786-
&& ref.name == self.left.name
12789+
if (self.right.left instanceof AST_SymbolRef
12790+
&& self.right.left.name == self.left.name
1278712791
&& ASSIGN_OPS[self.right.operator]) {
1278812792
// x = x - 2 ---> x -= 2
12789-
if (self.left.fixed) self.left.fixed.to_binary = function() {
12790-
return ref;
12791-
};
12792-
return make_node(AST_Assign, self, {
12793-
operator: self.right.operator + "=",
12794-
left: self.left,
12795-
right: self.right.right,
12796-
});
12793+
return make_compound(self.right.right);
1279712794
}
12798-
if ((ref = self.right.right) instanceof AST_SymbolRef
12799-
&& ref.name == self.left.name
12795+
if (self.right.right instanceof AST_SymbolRef
12796+
&& self.right.right.name == self.left.name
1280012797
&& ASSIGN_OPS_COMMUTATIVE[self.right.operator]
1280112798
&& !self.right.left.has_side_effects(compressor)) {
1280212799
// x = 2 & x ---> x &= 2
12803-
if (self.left.fixed) self.left.fixed.to_binary = function() {
12804-
return ref;
12805-
};
12806-
return make_node(AST_Assign, self, {
12807-
operator: self.right.operator + "=",
12808-
left: self.left,
12809-
right: self.right.left,
12810-
});
12800+
return make_compound(self.right.left);
1281112801
}
1281212802
}
1281312803
if ((self.operator == "-=" || self.operator == "+="
@@ -12870,6 +12860,18 @@ Compressor.prototype.compress = function(node) {
1287012860
return find_try(compressor, level, node, scope, may_throw, sync);
1287112861
}
1287212862

12863+
function make_compound(rhs) {
12864+
var fixed = self.left.fixed;
12865+
if (fixed) fixed.to_binary = replace_ref(function(node) {
12866+
return node.left;
12867+
}, fixed);
12868+
return make_node(AST_Assign, self, {
12869+
operator: self.right.operator + "=",
12870+
left: self.left,
12871+
right: rhs,
12872+
});
12873+
}
12874+
1287312875
function strip_assignment(def) {
1287412876
if (def) def.fixed = false;
1287512877
return (self.operator != "=" ? make_node(AST_Binary, self, {

Diff for: test/compress/reduce_vars.js

+135
Original file line numberDiff line numberDiff line change
@@ -7927,3 +7927,138 @@ issue_5623: {
79277927
}
79287928
expect_stdout: "1"
79297929
}
7930+
7931+
issue_5716_1: {
7932+
options = {
7933+
collapse_vars: true,
7934+
inline: true,
7935+
merge_vars: true,
7936+
reduce_vars: true,
7937+
toplevel: true,
7938+
unused: true,
7939+
}
7940+
input: {
7941+
var a;
7942+
function f() {
7943+
var b = [ c, c ], c = function() {
7944+
return b++ + (a = b);
7945+
}();
7946+
}
7947+
f();
7948+
console.log(a);
7949+
}
7950+
expect: {
7951+
c = [ c, c ],
7952+
void (c = ++c);
7953+
var c;
7954+
console.log(c);
7955+
}
7956+
expect_stdout: "NaN"
7957+
}
7958+
7959+
issue_5716_2: {
7960+
options = {
7961+
collapse_vars: true,
7962+
inline: true,
7963+
merge_vars: true,
7964+
reduce_vars: true,
7965+
toplevel: true,
7966+
unused: true,
7967+
}
7968+
input: {
7969+
var a;
7970+
function f() {
7971+
var b = [ c, c ], c = function() {
7972+
return (b += 4) + (a = b += 2);
7973+
}();
7974+
}
7975+
f();
7976+
console.log(a);
7977+
}
7978+
expect: {
7979+
void (c = c = (c = [ c, c ]) + 4 + 2);
7980+
var c;
7981+
console.log(c);
7982+
}
7983+
expect_stdout: ",42"
7984+
}
7985+
7986+
issue_5716_3: {
7987+
options = {
7988+
assignments: true,
7989+
collapse_vars: true,
7990+
inline: true,
7991+
merge_vars: true,
7992+
reduce_vars: true,
7993+
toplevel: true,
7994+
unused: true,
7995+
}
7996+
input: {
7997+
var a;
7998+
function f() {
7999+
var b = [ c, c ], c = function() {
8000+
return (b = b + 4) + (a = b += 2);
8001+
}();
8002+
}
8003+
f();
8004+
console.log(a);
8005+
}
8006+
expect: {
8007+
void (c = c = (c = [ c, c ]) + 4 + 2);
8008+
var c;
8009+
console.log(c);
8010+
}
8011+
expect_stdout: ",42"
8012+
}
8013+
8014+
issue_5716_4: {
8015+
options = {
8016+
assignments: true,
8017+
collapse_vars: true,
8018+
inline: true,
8019+
merge_vars: true,
8020+
reduce_vars: true,
8021+
toplevel: true,
8022+
unused: true,
8023+
}
8024+
input: {
8025+
var a;
8026+
function f() {
8027+
var b = [ c, c ], c = function() {
8028+
return (b = true | b) + (a = b *= 42);
8029+
}();
8030+
}
8031+
f();
8032+
console.log(a);
8033+
}
8034+
expect: {
8035+
void (c = c = ((c = [ c, c ]) | true) * 42);
8036+
var c;
8037+
console.log(c);
8038+
}
8039+
expect_stdout: "42"
8040+
}
8041+
8042+
issue_5716_5: {
8043+
options = {
8044+
assignments: true,
8045+
reduce_vars: true,
8046+
}
8047+
input: {
8048+
console.log(function() {
8049+
return 0 || (a = 42 | a);
8050+
var a = function() {
8051+
return a;
8052+
};
8053+
}());
8054+
}
8055+
expect: {
8056+
console.log(function() {
8057+
return 0 || (a |= 42);
8058+
var a = function() {
8059+
return a;
8060+
};
8061+
}());
8062+
}
8063+
expect_stdout: "42"
8064+
}

0 commit comments

Comments
 (0)