enhance collapse_vars (#5268)
This commit is contained in:
@@ -1943,16 +1943,46 @@ Compressor.prototype.compress = function(node) {
|
|||||||
if (stop_after === node) abort = true;
|
if (stop_after === node) abort = true;
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
// Stop immediately if these node types are encountered
|
|
||||||
var parent = scanner.parent();
|
var parent = scanner.parent();
|
||||||
if (should_stop(node, parent)) {
|
|
||||||
abort = true;
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
// Stop only if candidate is found within conditional branches
|
// Stop only if candidate is found within conditional branches
|
||||||
if (!stop_if_hit && in_conditional(node, parent)) {
|
if (!stop_if_hit && in_conditional(node, parent)) {
|
||||||
stop_if_hit = parent;
|
stop_if_hit = parent;
|
||||||
}
|
}
|
||||||
|
// Cascade compound assignments
|
||||||
|
if (compound && scan_lhs && can_replace && !stop_if_hit
|
||||||
|
&& node instanceof AST_Assign && node.operator != "=" && node.left.equivalent_to(lhs)) {
|
||||||
|
replaced++;
|
||||||
|
changed = true;
|
||||||
|
AST_Node.info("Cascading {node} [{file}:{line},{col}]", {
|
||||||
|
node: node,
|
||||||
|
file: node.start.file,
|
||||||
|
line: node.start.line,
|
||||||
|
col: node.start.col,
|
||||||
|
});
|
||||||
|
can_replace = false;
|
||||||
|
node.right.transform(scanner);
|
||||||
|
clear_write_only(candidate);
|
||||||
|
var assign = make_node(AST_Assign, node, {
|
||||||
|
operator: "=",
|
||||||
|
left: node.left,
|
||||||
|
right: make_node(AST_Binary, node, {
|
||||||
|
operator: node.operator.slice(0, -1),
|
||||||
|
left: abort ? candidate : make_node(AST_Binary, candidate, {
|
||||||
|
operator: compound,
|
||||||
|
left: lhs,
|
||||||
|
right: rvalue,
|
||||||
|
}),
|
||||||
|
right: node.right,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
abort = true;
|
||||||
|
return assign;
|
||||||
|
}
|
||||||
|
// Stop immediately if these node types are encountered
|
||||||
|
if (should_stop(node, parent)) {
|
||||||
|
abort = true;
|
||||||
|
return node;
|
||||||
|
}
|
||||||
// Skip transient nodes caused by single-use variable replacement
|
// Skip transient nodes caused by single-use variable replacement
|
||||||
if (node.single_use && parent instanceof AST_VarDef && parent.value === node) return node;
|
if (node.single_use && parent instanceof AST_VarDef && parent.value === node) return node;
|
||||||
// Replace variable with assignment when found
|
// Replace variable with assignment when found
|
||||||
@@ -2006,13 +2036,8 @@ Compressor.prototype.compress = function(node) {
|
|||||||
right: rvalue,
|
right: rvalue,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
var assign = candidate;
|
clear_write_only(candidate);
|
||||||
while (assign.write_only) {
|
var assign = candidate.clone();
|
||||||
assign.write_only = false;
|
|
||||||
if (!(assign instanceof AST_Assign)) break;
|
|
||||||
assign = assign.right;
|
|
||||||
}
|
|
||||||
assign = candidate.clone();
|
|
||||||
assign.right = rvalue;
|
assign.right = rvalue;
|
||||||
return assign;
|
return assign;
|
||||||
}
|
}
|
||||||
@@ -2095,6 +2120,12 @@ Compressor.prototype.compress = function(node) {
|
|||||||
if (node instanceof AST_SymbolRef && node.definition() === def) {
|
if (node instanceof AST_SymbolRef && node.definition() === def) {
|
||||||
if (is_lhs(node, multi_replacer.parent())) return node;
|
if (is_lhs(node, multi_replacer.parent())) return node;
|
||||||
if (!--replaced) abort = true;
|
if (!--replaced) abort = true;
|
||||||
|
AST_Node.info("Replacing {node} [{file}:{line},{col}]", {
|
||||||
|
node: node,
|
||||||
|
file: node.start.file,
|
||||||
|
line: node.start.line,
|
||||||
|
col: node.start.col,
|
||||||
|
});
|
||||||
var ref = rvalue.clone();
|
var ref = rvalue.clone();
|
||||||
ref.scope = node.scope;
|
ref.scope = node.scope;
|
||||||
ref.reference();
|
ref.reference();
|
||||||
@@ -2138,6 +2169,7 @@ Compressor.prototype.compress = function(node) {
|
|||||||
var scan_lhs = lhs && !side_effects && !is_lhs_read_only(lhs, compressor);
|
var scan_lhs = lhs && !side_effects && !is_lhs_read_only(lhs, compressor);
|
||||||
var scan_rhs = foldable(candidate);
|
var scan_rhs = foldable(candidate);
|
||||||
if (!scan_lhs && !scan_rhs) continue;
|
if (!scan_lhs && !scan_rhs) continue;
|
||||||
|
var compound = candidate instanceof AST_Assign && candidate.operator.slice(0, -1);
|
||||||
var funarg = candidate.name instanceof AST_SymbolFunarg;
|
var funarg = candidate.name instanceof AST_SymbolFunarg;
|
||||||
var may_throw = return_false;
|
var may_throw = return_false;
|
||||||
if (candidate.may_throw(compressor)) {
|
if (candidate.may_throw(compressor)) {
|
||||||
@@ -2154,13 +2186,7 @@ Compressor.prototype.compress = function(node) {
|
|||||||
var lvalues = get_lvalues(candidate);
|
var lvalues = get_lvalues(candidate);
|
||||||
var lhs_local = is_lhs_local(lhs);
|
var lhs_local = is_lhs_local(lhs);
|
||||||
var rhs_value = get_rvalue(candidate);
|
var rhs_value = get_rvalue(candidate);
|
||||||
var rvalue;
|
var rvalue = !compound && rhs_value instanceof AST_Sequence ? rhs_value.tail_node() : rhs_value;
|
||||||
if (rhs_value instanceof AST_Sequence
|
|
||||||
&& !(candidate instanceof AST_Assign && candidate.operator != "=")) {
|
|
||||||
rvalue = rhs_value.tail_node();
|
|
||||||
} else {
|
|
||||||
rvalue = rhs_value;
|
|
||||||
}
|
|
||||||
if (!side_effects) side_effects = value_has_side_effects();
|
if (!side_effects) side_effects = value_has_side_effects();
|
||||||
var check_destructured = in_try || !lhs_local ? function(node) {
|
var check_destructured = in_try || !lhs_local ? function(node) {
|
||||||
return node instanceof AST_Destructured;
|
return node instanceof AST_Destructured;
|
||||||
@@ -2834,7 +2860,6 @@ Compressor.prototype.compress = function(node) {
|
|||||||
function get_lhs(expr) {
|
function get_lhs(expr) {
|
||||||
if (expr instanceof AST_Assign) {
|
if (expr instanceof AST_Assign) {
|
||||||
var lhs = expr.left;
|
var lhs = expr.left;
|
||||||
if (expr.operator != "=") return lhs;
|
|
||||||
if (!(lhs instanceof AST_SymbolRef)) return lhs;
|
if (!(lhs instanceof AST_SymbolRef)) return lhs;
|
||||||
var def = lhs.definition();
|
var def = lhs.definition();
|
||||||
if (scope.uses_arguments && is_funarg(def)) return lhs;
|
if (scope.uses_arguments && is_funarg(def)) return lhs;
|
||||||
@@ -2849,7 +2874,7 @@ Compressor.prototype.compress = function(node) {
|
|||||||
assign_pos = 0;
|
assign_pos = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mangleable_var(expr.right);
|
if (expr.operator == "=") mangleable_var(expr.right);
|
||||||
return lhs;
|
return lhs;
|
||||||
}
|
}
|
||||||
if (expr instanceof AST_Binary) return expr.right.left;
|
if (expr instanceof AST_Binary) return expr.right.left;
|
||||||
@@ -2952,6 +2977,14 @@ Compressor.prototype.compress = function(node) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function clear_write_only(assign) {
|
||||||
|
while (assign.write_only) {
|
||||||
|
assign.write_only = false;
|
||||||
|
if (!(assign instanceof AST_Assign)) break;
|
||||||
|
assign = assign.right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function may_be_global(node) {
|
function may_be_global(node) {
|
||||||
if (node instanceof AST_SymbolRef) {
|
if (node instanceof AST_SymbolRef) {
|
||||||
node = node.fixed_value();
|
node = node.fixed_value();
|
||||||
@@ -3118,12 +3151,13 @@ Compressor.prototype.compress = function(node) {
|
|||||||
|
|
||||||
function is_lhs_local(lhs) {
|
function is_lhs_local(lhs) {
|
||||||
var sym = root_expr(lhs);
|
var sym = root_expr(lhs);
|
||||||
return sym instanceof AST_SymbolRef
|
if (!(sym instanceof AST_SymbolRef)) return false;
|
||||||
&& sym.definition().scope.resolve() === scope
|
if (sym.definition().scope.resolve() !== scope) return false;
|
||||||
&& !(in_loop
|
if (!in_loop) return true;
|
||||||
&& (lvalues.has(sym.name) && lvalues.get(sym.name)[0] !== lhs
|
if (compound) return false;
|
||||||
|| candidate instanceof AST_Unary
|
if (candidate instanceof AST_Unary) return false;
|
||||||
|| candidate instanceof AST_Assign && candidate.operator != "="));
|
var lvalue = lvalues.get(sym.name);
|
||||||
|
return !lvalue || lvalue[0] === lhs;
|
||||||
}
|
}
|
||||||
|
|
||||||
function value_has_side_effects() {
|
function value_has_side_effects() {
|
||||||
@@ -7099,7 +7133,7 @@ Compressor.prototype.compress = function(node) {
|
|||||||
log(node.name, text);
|
log(node.name, text);
|
||||||
} else {
|
} else {
|
||||||
AST_Node.info(text + " [{file}:{line},{col}]", {
|
AST_Node.info(text + " [{file}:{line},{col}]", {
|
||||||
name: node.print_to_string(),
|
name: node,
|
||||||
file: node.start.file,
|
file: node.start.file,
|
||||||
line: node.start.line,
|
line: node.start.line,
|
||||||
col : node.start.col,
|
col : node.start.col,
|
||||||
|
|||||||
@@ -530,6 +530,25 @@ logical_collapse_vars_2: {
|
|||||||
node_version: ">=15"
|
node_version: ">=15"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logical_collapse_vars_3: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = 6;
|
||||||
|
a *= 7;
|
||||||
|
a ??= "FAIL";
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = 6;
|
||||||
|
a = a * 7 ?? "FAIL";
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect_stdout: "42"
|
||||||
|
node_version: ">=15"
|
||||||
|
}
|
||||||
|
|
||||||
logical_reduce_vars: {
|
logical_reduce_vars: {
|
||||||
options = {
|
options = {
|
||||||
evaluate: true,
|
evaluate: true,
|
||||||
|
|||||||
@@ -2995,6 +2995,43 @@ compound_assignment_4: {
|
|||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
compound_assignment_5: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = 0, b;
|
||||||
|
a += 42;
|
||||||
|
b && (a *= null);
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = 0, b;
|
||||||
|
a += 42;
|
||||||
|
b && (a *= null);
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect_stdout: "42"
|
||||||
|
}
|
||||||
|
|
||||||
|
compound_assignment_6: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a;
|
||||||
|
a ^= 6;
|
||||||
|
a *= a + 1;
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a;
|
||||||
|
a = (a ^= 6) * (a + 1);
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect_stdout: "42"
|
||||||
|
}
|
||||||
|
|
||||||
issue_2187_1: {
|
issue_2187_1: {
|
||||||
options = {
|
options = {
|
||||||
collapse_vars: true,
|
collapse_vars: true,
|
||||||
|
|||||||
@@ -774,7 +774,7 @@ side_effects_cascade_3: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
function f(a, b) {
|
function f(a, b) {
|
||||||
(b += a) || (b = a) || (b -= a, b ^= a),
|
(b += a) || (b = a) || (b = b - a ^ a),
|
||||||
a--;
|
a--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user