fix corner cases in collapse_vars (#4462)

fixes #4460
fixes #4461
This commit is contained in:
Alex Lam S.L
2020-12-26 05:40:31 +00:00
committed by GitHub
parent 95aea0e33c
commit be1f5199f4
2 changed files with 111 additions and 33 deletions

View File

@@ -931,19 +931,25 @@ merge(Compressor.prototype, {
tw.in_loop = this; tw.in_loop = this;
push(tw); push(tw);
var init = this.init; var init = this.init;
init.walk(tw);
if (init instanceof AST_Definitions) { if (init instanceof AST_Definitions) {
init.definitions[0].name.match_symbol(function(node) { init.definitions[0].name.mark_symbol(function(node) {
if (node instanceof AST_SymbolDeclaration) { if (node instanceof AST_SymbolDeclaration) {
var def = node.definition(); var def = node.definition();
def.assignments++; def.assignments++;
def.fixed = false; def.fixed = false;
} }
}, true); }, tw);
} else if (init instanceof AST_SymbolRef) { } else if (init instanceof AST_Destructured || init instanceof AST_SymbolRef) {
var def = init.definition(); init.mark_symbol(function(node) {
if (node instanceof AST_SymbolRef) {
var def = node.definition();
push_ref(def, node);
def.assignments++; def.assignments++;
if (!init.is_immutable()) def.fixed = false; if (!node.is_immutable()) def.fixed = false;
}
}, tw);
} else {
init.walk(tw);
} }
this.body.walk(tw); this.body.walk(tw);
pop(tw); pop(tw);
@@ -1259,16 +1265,17 @@ merge(Compressor.prototype, {
AST_Node.DEFMETHOD("match_symbol", function(predicate) { AST_Node.DEFMETHOD("match_symbol", function(predicate) {
return predicate(this); return predicate(this);
}); });
AST_Destructured.DEFMETHOD("match_symbol", function(predicate, allow_computed_keys) { AST_Destructured.DEFMETHOD("match_symbol", function(predicate, ignore_side_effects) {
var found = false; var found = false;
var tw = new TreeWalker(function(node) { var tw = new TreeWalker(function(node) {
if (found) return true; if (found) return true;
if (node instanceof AST_DefaultValue) { if (node instanceof AST_DefaultValue) {
if (!ignore_side_effects) return found = true;
node.name.walk(tw); node.name.walk(tw);
return true; return true;
} }
if (node instanceof AST_DestructuredKeyVal) { if (node instanceof AST_DestructuredKeyVal) {
if (!allow_computed_keys && node.key instanceof AST_Node) return found = true; if (!ignore_side_effects && node.key instanceof AST_Node) return found = true;
node.value.walk(tw); node.value.walk(tw);
return true; return true;
} }
@@ -1605,13 +1612,12 @@ merge(Compressor.prototype, {
can_replace = replace; can_replace = replace;
return signal_abort(node); return signal_abort(node);
} }
// Scan but don't replace inside destructuring LHS // Scan but don't replace inside destructuring expression
if (node instanceof AST_Assign && node.left instanceof AST_Destructured) { if (node instanceof AST_Destructured) {
var replace = can_replace; var replace = can_replace;
can_replace = false; can_replace = false;
node.left = node.left.transform(scanner); descend(node, scanner);
can_replace = replace; can_replace = replace;
node.right = node.right.transform(scanner);
return signal_abort(node); return signal_abort(node);
} }
// Scan but don't replace inside default value // Scan but don't replace inside default value
@@ -1710,8 +1716,8 @@ merge(Compressor.prototype, {
var assign_used = false; var assign_used = false;
var can_replace = !args || !hit; var can_replace = !args || !hit;
if (!can_replace) { if (!can_replace) {
for (var j = candidate.index + 1; !abort && j < args.length; j++) { for (var j = candidate.arg_index + 1; !abort && j < args.length; j++) {
args[j].transform(scanner); if (args[j]) args[j].transform(scanner);
} }
can_replace = true; can_replace = true;
} }
@@ -1911,7 +1917,7 @@ merge(Compressor.prototype, {
return (node.value || parent instanceof AST_Let) && node.name.match_symbol(function(node) { return (node.value || parent instanceof AST_Let) && node.name.match_symbol(function(node) {
return node instanceof AST_SymbolDeclaration return node instanceof AST_SymbolDeclaration
&& (lvalues.has(node.name) || side_effects && may_modify(node)); && (lvalues.has(node.name) || side_effects && may_modify(node));
}); }, true);
} }
var sym = is_lhs(node.left, node); var sym = is_lhs(node.left, node);
if (!sym) return false; if (!sym) return false;
@@ -1920,7 +1926,7 @@ merge(Compressor.prototype, {
return sym.match_symbol(function(node) { return sym.match_symbol(function(node) {
return node instanceof AST_SymbolRef return node instanceof AST_SymbolRef
&& (lvalues.has(node.name) || read_toplevel && compressor.exposed(node.definition())); && (lvalues.has(node.name) || read_toplevel && compressor.exposed(node.definition()));
}); }, true);
} }
function extract_args() { function extract_args() {
@@ -1959,21 +1965,17 @@ merge(Compressor.prototype, {
return true; return true;
} }
}); });
var len = fn.argnames.length; args = iife.args.slice();
args = iife.args.slice(len);
var names = Object.create(null); var names = Object.create(null);
for (var i = len; --i >= 0;) { for (var i = fn.argnames.length; --i >= 0;) {
var sym = fn.argnames[i]; var sym = fn.argnames[i];
var arg = iife.args[i]; var arg = iife.args[i];
var value; var value;
if (sym instanceof AST_DefaultValue) { if (sym instanceof AST_DefaultValue) {
value = sym.value; value = sym.value;
sym = sym.name; sym = sym.name;
args[iife.args.length + i] = value;
} }
args.unshift(make_node(AST_VarDef, sym, {
name: sym,
value: value ? arg ? make_sequence(iife, [ arg, value ]) : value : arg,
}));
if (sym instanceof AST_Destructured) { if (sym instanceof AST_Destructured) {
if (!sym.match_symbol(return_false)) continue; if (!sym.match_symbol(return_false)) continue;
candidates.length = 0; candidates.length = 0;
@@ -1994,7 +1996,8 @@ merge(Compressor.prototype, {
name: sym, name: sym,
value: arg value: arg
}); });
candidate.index = i; candidate.name_index = i;
candidate.arg_index = value ? iife.args.length + i : i;
candidates.unshift([ candidate ]); candidates.unshift([ candidate ]);
} }
} }
@@ -2198,9 +2201,7 @@ merge(Compressor.prototype, {
if (is_last_node(node, parent)) return node; if (is_last_node(node, parent)) return node;
if (in_conditional(node, parent)) return node; if (in_conditional(node, parent)) return node;
if (parent instanceof AST_Array) return find_stop_unused(parent, level + 1); if (parent instanceof AST_Array) return find_stop_unused(parent, level + 1);
if (parent instanceof AST_Assign) { if (parent instanceof AST_Assign) return check_assignment(parent.left);
return may_throw(parent) ? node : find_stop_unused(parent, level + 1);
}
if (parent instanceof AST_Await) return node; if (parent instanceof AST_Await) return node;
if (parent instanceof AST_Binary) return find_stop_unused(parent, level + 1); if (parent instanceof AST_Binary) return find_stop_unused(parent, level + 1);
if (parent instanceof AST_Call) return find_stop_unused(parent, level + 1); if (parent instanceof AST_Call) return find_stop_unused(parent, level + 1);
@@ -2231,10 +2232,27 @@ merge(Compressor.prototype, {
if (parent instanceof AST_Spread) return node; if (parent instanceof AST_Spread) return node;
if (parent instanceof AST_Switch) return find_stop_unused(parent, level + 1); if (parent instanceof AST_Switch) return find_stop_unused(parent, level + 1);
if (parent instanceof AST_Unary) return find_stop_unused(parent, level + 1); if (parent instanceof AST_Unary) return find_stop_unused(parent, level + 1);
if (parent instanceof AST_VarDef) { if (parent instanceof AST_VarDef) return check_assignment(parent.name);
return may_throw(parent) ? node : find_stop_unused(parent, level + 1);
}
return null; return null;
function check_assignment(lhs) {
if (may_throw(parent)) return node;
if (lhs !== node && lhs instanceof AST_Destructured) {
var replace = can_replace;
can_replace = false;
var after = stop_after;
var if_hit = stop_if_hit;
lhs.transform(scanner);
stop_if_hit = if_hit;
stop_after = after;
can_replace = replace;
if (abort) {
abort = false;
return node;
}
}
return find_stop_unused(parent, level + 1);
}
} }
function mangleable_var(value) { function mangleable_var(value) {
@@ -2389,7 +2407,7 @@ merge(Compressor.prototype, {
} }
function remove_candidate(expr) { function remove_candidate(expr) {
var index = expr.index; var index = expr.name_index;
if (index >= 0) { if (index >= 0) {
var argname = scope.argnames[index]; var argname = scope.argnames[index];
if (argname instanceof AST_DefaultValue) { if (argname instanceof AST_DefaultValue) {
@@ -7018,7 +7036,7 @@ merge(Compressor.prototype, {
if ((name instanceof AST_Destructured || name instanceof AST_SymbolLet) if ((name instanceof AST_Destructured || name instanceof AST_SymbolLet)
&& !name.match_symbol(function(node) { && !name.match_symbol(function(node) {
if (node instanceof AST_SymbolDeclaration) return may_overlap(compressor, node.definition()); if (node instanceof AST_SymbolDeclaration) return may_overlap(compressor, node.definition());
})) { }, true)) {
self.init = to_var(self.init); self.init = to_var(self.init);
} }
} }

View File

@@ -1100,3 +1100,63 @@ issue_4458: {
expect_stdout: "PASS 42" expect_stdout: "PASS 42"
node_version: ">=6" node_version: ">=6"
} }
issue_4460: {
options = {
collapse_vars: true,
}
input: {
var log = console.log, a = "FAIL";
var [ b = a ] = (a = "PASS", []);
log(a, b);
}
expect: {
var log = console.log, a = "FAIL";
var [ b = a ] = (a = "PASS", []);
log(a, b);
}
expect_stdout: "PASS PASS"
node_version: ">=6"
}
issue_4461_1: {
options = {
collapse_vars: true,
unused: true,
}
input: {
var a = 0;
(function(b = a && console.log("PASS"), c) {
return c;
})(void 0, a++);
}
expect: {
var a = 0;
(function(b = a && console.log("PASS"), c) {
return c;
})(void 0, a++);
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_4461_2: {
options = {
collapse_vars: true,
unused: true,
}
input: {
var a = 0;
(function([ b = a && console.log("PASS") ], c) {
return c;
})([], a++);
}
expect: {
var a = 0;
(function([ b = a && console.log("PASS") ], c) {
return c;
})([], a++);
}
expect_stdout: "PASS"
node_version: ">=6"
}