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

View File

@@ -1100,3 +1100,63 @@ issue_4458: {
expect_stdout: "PASS 42"
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"
}