Skip to content

Commit 111746b

Browse files
authored
fix corner case in reduce_vars (#5964)
fixes #5963
1 parent d02156d commit 111746b

File tree

4 files changed

+213
-23
lines changed

4 files changed

+213
-23
lines changed

Diff for: lib/compress.js

+22-23
Original file line numberDiff line numberDiff line change
@@ -691,6 +691,15 @@ Compressor.prototype.compress = function(node) {
691691
return !assigned || assigned === seq;
692692
}
693693

694+
function dot(expr, tw) {
695+
while (expr instanceof AST_Assign && expr.operator == "=") {
696+
var lhs = expr.left;
697+
if (lhs instanceof AST_SymbolRef) access(tw, lhs.definition());
698+
expr = expr.right;
699+
}
700+
if (expr instanceof AST_SymbolRef) access(tw, expr.definition());
701+
}
702+
694703
function mark(tw, def) {
695704
tw.safe_ids[def.id] = {};
696705
}
@@ -1032,7 +1041,9 @@ Compressor.prototype.compress = function(node) {
10321041
return true;
10331042
}
10341043
mark_assignment_to_arguments(left);
1035-
return;
1044+
descend();
1045+
if (left instanceof AST_PropAccess) dot(left.expression, tw);
1046+
return true;
10361047
case "&&=":
10371048
case "||=":
10381049
case "??=":
@@ -1108,6 +1119,7 @@ Compressor.prototype.compress = function(node) {
11081119
if (!(sym instanceof AST_SymbolRef)) {
11091120
mark_assignment_to_arguments(sym);
11101121
walk();
1122+
if (sym instanceof AST_PropAccess) dot(sym.expression, tw);
11111123
return;
11121124
}
11131125
var d = sym.definition();
@@ -1291,15 +1303,7 @@ Compressor.prototype.compress = function(node) {
12911303
def(AST_Dot, function(tw, descend) {
12921304
descend();
12931305
var node = this;
1294-
var expr = node.expression;
1295-
if (!node.optional) {
1296-
while (expr instanceof AST_Assign && expr.operator == "=") {
1297-
var lhs = expr.left;
1298-
if (lhs instanceof AST_SymbolRef) access(tw, lhs.definition());
1299-
expr = expr.right;
1300-
}
1301-
if (expr instanceof AST_SymbolRef) access(tw, expr.definition());
1302-
}
1306+
if (!node.optional && !is_direct_assignment(node, tw.parent())) dot(node.expression, tw);
13031307
return true;
13041308
});
13051309
def(AST_For, function(tw, descend, compressor) {
@@ -1410,12 +1414,7 @@ Compressor.prototype.compress = function(node) {
14101414
prop.walk(tw);
14111415
pop(tw);
14121416
} else {
1413-
while (expr instanceof AST_Assign && expr.operator == "=") {
1414-
var lhs = expr.left;
1415-
if (lhs instanceof AST_SymbolRef) access(tw, lhs.definition());
1416-
expr = expr.right;
1417-
}
1418-
if (expr instanceof AST_SymbolRef) access(tw, expr.definition());
1417+
if (!is_direct_assignment(node, tw.parent())) dot(expr, tw);
14191418
prop.walk(tw);
14201419
}
14211420
return true;
@@ -1974,6 +1973,13 @@ Compressor.prototype.compress = function(node) {
19741973
return array;
19751974
}
19761975

1976+
function is_direct_assignment(node, parent) {
1977+
if (parent instanceof AST_Assign) return parent.operator == "=" && parent.left === node;
1978+
if (parent instanceof AST_DefaultValue) return parent.name === node;
1979+
if (parent instanceof AST_DestructuredArray) return true;
1980+
if (parent instanceof AST_DestructuredKeyVal) return parent.value === node;
1981+
}
1982+
19771983
function is_lexical_definition(stat) {
19781984
return stat instanceof AST_Const || stat instanceof AST_DefClass || stat instanceof AST_Let;
19791985
}
@@ -2614,13 +2620,6 @@ Compressor.prototype.compress = function(node) {
26142620
}
26152621
}
26162622

2617-
function is_direct_assignment(node, parent) {
2618-
if (parent instanceof AST_Assign) return parent.operator == "=" && parent.left === node;
2619-
if (parent instanceof AST_DefaultValue) return parent.name === node;
2620-
if (parent instanceof AST_DestructuredArray) return true;
2621-
if (parent instanceof AST_DestructuredKeyVal) return parent.value === node;
2622-
}
2623-
26242623
function should_stop(node, parent) {
26252624
if (node === rvalue) return true;
26262625
if (parent instanceof AST_For) {

Diff for: test/compress/default-values.js

+23
Original file line numberDiff line numberDiff line change
@@ -3135,3 +3135,26 @@ issue_5863: {
31353135
expect_stdout: "function"
31363136
node_version: ">=6"
31373137
}
3138+
3139+
issue_5963: {
3140+
options = {
3141+
pure_getters: "strict",
3142+
reduce_vars: true,
3143+
side_effects: true,
3144+
}
3145+
input: {
3146+
var a = Object.create(null);
3147+
[ a.PASS = 42 ] = [];
3148+
a.FAIL;
3149+
for (var p in a)
3150+
console.log(p);
3151+
}
3152+
expect: {
3153+
var a = Object.create(null);
3154+
[ a.PASS = 42 ] = [];
3155+
for (var p in a)
3156+
console.log(p);
3157+
}
3158+
expect_stdout: "PASS"
3159+
node_version: ">=6"
3160+
}

Diff for: test/compress/destructured.js

+46
Original file line numberDiff line numberDiff line change
@@ -4289,3 +4289,49 @@ issue_5899_2: {
42894289
]
42904290
node_version: ">=6"
42914291
}
4292+
4293+
issue_5963_array: {
4294+
options = {
4295+
pure_getters: "strict",
4296+
reduce_vars: true,
4297+
side_effects: true,
4298+
}
4299+
input: {
4300+
var a = Object.create(null);
4301+
[ a.PASS ] = [ 42 ];
4302+
a.FAIL;
4303+
for (var p in a)
4304+
console.log(p);
4305+
}
4306+
expect: {
4307+
var a = Object.create(null);
4308+
[ a.PASS ] = [ 42 ];
4309+
for (var p in a)
4310+
console.log(p);
4311+
}
4312+
expect_stdout: "PASS"
4313+
node_version: ">=6"
4314+
}
4315+
4316+
issue_5963_object: {
4317+
options = {
4318+
pure_getters: "strict",
4319+
reduce_vars: true,
4320+
side_effects: true,
4321+
}
4322+
input: {
4323+
var a = Object.create(null);
4324+
({ p: a.PASS } = { p: 42 });
4325+
a.FAIL;
4326+
for (var p in a)
4327+
console.log(p);
4328+
}
4329+
expect: {
4330+
var a = Object.create(null);
4331+
({ p: a.PASS } = { p: 42 });
4332+
for (var p in a)
4333+
console.log(p);
4334+
}
4335+
expect_stdout: "PASS"
4336+
node_version: ">=6"
4337+
}

Diff for: test/compress/properties.js

+122
Original file line numberDiff line numberDiff line change
@@ -2046,3 +2046,125 @@ issue_5949_2: {
20462046
}
20472047
expect_stdout: "PASS"
20482048
}
2049+
2050+
issue_5963_dot: {
2051+
options = {
2052+
collapse_vars: true,
2053+
evaluate: true,
2054+
pure_getters: "strict",
2055+
reduce_vars: true,
2056+
}
2057+
input: {
2058+
var a = "PASS", b;
2059+
try {
2060+
b.p = (b.q = null, a = "FAIL 1", !0);
2061+
console.log("FAIL 2")
2062+
} catch (e) {
2063+
console.log(a);
2064+
}
2065+
}
2066+
expect: {
2067+
var a = "PASS", b;
2068+
try {
2069+
b.p = (b.q = null, a = "FAIL 1", !0);
2070+
console.log("FAIL 2")
2071+
} catch (e) {
2072+
console.log(a);
2073+
}
2074+
}
2075+
expect_stdout: "PASS"
2076+
}
2077+
2078+
issue_5963_sub: {
2079+
options = {
2080+
collapse_vars: true,
2081+
evaluate: true,
2082+
pure_getters: "strict",
2083+
reduce_vars: true,
2084+
}
2085+
input: {
2086+
var a = "PASS", b;
2087+
try {
2088+
b[42] = (b.q = null, a = "FAIL 1", !0);
2089+
console.log("FAIL 2")
2090+
} catch (e) {
2091+
console.log(a);
2092+
}
2093+
}
2094+
expect: {
2095+
var a = "PASS", b;
2096+
try {
2097+
b[42] = (b.q = null, a = "FAIL 1", !0);
2098+
console.log("FAIL 2")
2099+
} catch (e) {
2100+
console.log(a);
2101+
}
2102+
}
2103+
expect_stdout: "PASS"
2104+
}
2105+
2106+
issue_5963_assign: {
2107+
options = {
2108+
pure_getters: "strict",
2109+
reduce_vars: true,
2110+
side_effects: true,
2111+
}
2112+
input: {
2113+
var a = Object.create(null);
2114+
a.PASS = 42;
2115+
a.FAIL;
2116+
for (var p in a)
2117+
console.log(p);
2118+
}
2119+
expect: {
2120+
var a = Object.create(null);
2121+
a.PASS = 42;
2122+
for (var p in a)
2123+
console.log(p);
2124+
}
2125+
expect_stdout: "PASS"
2126+
}
2127+
2128+
issue_5963_compound_assign: {
2129+
options = {
2130+
pure_getters: "strict",
2131+
reduce_vars: true,
2132+
side_effects: true,
2133+
}
2134+
input: {
2135+
var a = Object.create(null);
2136+
a.PASS ^= 42;
2137+
a.FAIL;
2138+
for (var p in a)
2139+
console.log(p);
2140+
}
2141+
expect: {
2142+
var a = Object.create(null);
2143+
a.PASS ^= 42;
2144+
for (var p in a)
2145+
console.log(p);
2146+
}
2147+
expect_stdout: "PASS"
2148+
}
2149+
2150+
issue_5963_unary: {
2151+
options = {
2152+
pure_getters: "strict",
2153+
reduce_vars: true,
2154+
side_effects: true,
2155+
}
2156+
input: {
2157+
var a = Object.create(null);
2158+
a.PASS++;
2159+
a.FAIL;
2160+
for (var p in a)
2161+
console.log(p);
2162+
}
2163+
expect: {
2164+
var a = Object.create(null);
2165+
a.PASS++;
2166+
for (var p in a)
2167+
console.log(p);
2168+
}
2169+
expect_stdout: "PASS"
2170+
}

0 commit comments

Comments
 (0)