enhance conditionals (#5542)

This commit is contained in:
Alex Lam S.L
2022-07-07 05:17:23 +01:00
committed by GitHub
parent c8d98f4787
commit d89f0965aa
5 changed files with 554 additions and 62 deletions

View File

@@ -270,10 +270,6 @@ Compressor.prototype.compress = function(node) {
return self;
});
AST_Node.DEFMETHOD("equivalent_to", function(node) {
return this.TYPE == node.TYPE && this.print_to_string() == node.print_to_string();
});
AST_Toplevel.DEFMETHOD("hoist_exports", function(compressor) {
if (!compressor.option("hoist_exports")) return;
var body = this.body, props = [];
@@ -930,7 +926,7 @@ Compressor.prototype.compress = function(node) {
var scan = ld || left instanceof AST_Destructured;
switch (node.operator) {
case "=":
if (left.equivalent_to(right) && !left.has_side_effects(compressor)) {
if (left.equals(right) && !left.has_side_effects(compressor)) {
right.walk(tw);
walk_prop(left);
node.redundant = true;
@@ -2031,7 +2027,7 @@ Compressor.prototype.compress = function(node) {
}
// Cascade compound assignments
if (compound && scan_lhs && can_replace && !stop_if_hit
&& node instanceof AST_Assign && node.operator != "=" && node.left.equivalent_to(lhs)) {
&& node instanceof AST_Assign && node.operator != "=" && node.left.equals(lhs)) {
replaced++;
changed = true;
AST_Node.info("Cascading {node} [{file}:{line},{col}]", {
@@ -2075,7 +2071,7 @@ Compressor.prototype.compress = function(node) {
// Replace variable with assignment when found
var hit_rhs;
if (!(node instanceof AST_SymbolDeclaration)
&& (scan_lhs && lhs.equivalent_to(node)
&& (scan_lhs && lhs.equals(node)
|| scan_rhs && (hit_rhs = scan_rhs(node, this)))) {
if (!can_replace || stop_if_hit && (hit_rhs || !lhs_local || !replace_all)) {
if (!hit_rhs && !value_def) abort = true;
@@ -2420,11 +2416,11 @@ Compressor.prototype.compress = function(node) {
if (node !== parent.init) return true;
}
if (node instanceof AST_Assign) {
return node.operator != "=" && lhs.equivalent_to(node.left);
return node.operator != "=" && lhs.equals(node.left);
}
if (node instanceof AST_Call) {
if (!(lhs instanceof AST_PropAccess)) return false;
if (!lhs.equivalent_to(node.expression)) return false;
if (!lhs.equals(node.expression)) return false;
return !(rvalue instanceof AST_LambdaExpression && !rvalue.contains_this());
}
if (node instanceof AST_Class) return !compressor.has_directive("use strict");
@@ -3102,7 +3098,7 @@ Compressor.prototype.compress = function(node) {
return !circular && rhs_exact_match;
function rhs_exact_match(node) {
return expr.equivalent_to(node);
return expr.equals(node);
}
}
@@ -3400,7 +3396,7 @@ Compressor.prototype.compress = function(node) {
var changed = false;
var parent = compressor.parent();
var self = compressor.self();
var exit, exit_defs, merge_exit;
var exit, merge_exit;
var in_iife = in_lambda && parent && parent.TYPE == "Call" && parent.expression === self;
var chain_if_returns = in_lambda && compressor.option("conditionals") && compressor.option("sequences");
var multiple_if_returns = has_multiple_if_returns(statements);
@@ -3548,7 +3544,6 @@ Compressor.prototype.compress = function(node) {
if (stat instanceof AST_Exit) {
exit = stat;
exit_defs = null;
continue;
}
@@ -3578,30 +3573,15 @@ Compressor.prototype.compress = function(node) {
if (exit.TYPE != ab.TYPE) return false;
var value = ab.value;
if (!value) return false;
var equals = exit.equivalent_to(ab);
var equals = exit.equals(ab);
if (!equals && value instanceof AST_Sequence) {
value = value.tail_node();
if (exit.value && exit.value.equivalent_to(value)) equals = 2;
if (exit.value && exit.value.equals(value)) equals = 2;
}
if (!equals && !exact && exit.value instanceof AST_Sequence) {
if (exit.value.tail_node().equivalent_to(value)) equals = 3;
if (exit.value.tail_node().equals(value)) equals = 3;
}
if (!equals) return false;
if (exit_defs == null) {
exit_defs = new Dictionary();
exit.walk(new TreeWalker(function(node) {
if (node instanceof AST_SymbolRef) exit_defs.set(node.name, node.definition());
}));
if (!exit_defs.size()) exit_defs = false;
}
var abort = false;
if (exit_defs) value.walk(new TreeWalker(function(node) {
if (abort) return true;
if (node instanceof AST_SymbolRef && exit_defs.get(node.name) !== node.definition()) {
return abort = true;
}
}));
return !abort && equals;
return equals;
}
function can_drop_abort(ab) {
@@ -4635,7 +4615,7 @@ Compressor.prototype.compress = function(node) {
if (keep_unary
&& fixed instanceof AST_UnaryPrefix
&& fixed.operator == "+"
&& fixed.expression.equivalent_to(this)) {
&& fixed.expression.equals(this)) {
return false;
}
this.is_number = return_false;
@@ -9456,10 +9436,10 @@ Compressor.prototype.compress = function(node) {
}
function match(cond) {
if (node.equivalent_to(cond)) return true;
if (node.equals(cond)) return true;
if (!(cond instanceof AST_UnaryPrefix)) return false;
if (cond.operator != "!") return false;
if (!node.equivalent_to(cond.expression)) return false;
if (!node.equals(cond.expression)) return false;
negated = true;
return true;
}
@@ -9633,9 +9613,43 @@ Compressor.prototype.compress = function(node) {
self.alternative = null;
return make_node(AST_BlockStatement, self, { body: [ self, body ] }).optimize(compressor);
}
if (self.alternative) {
var body_stats = as_array(self.body);
var body_index = last_index(body_stats);
var alt_stats = as_array(self.alternative);
var alt_index = last_index(alt_stats);
for (var stats = []; body_index >= 0 && alt_index >= 0;) {
var stat = body_stats[body_index];
if (!stat.equals(alt_stats[alt_index])) break;
body_stats.splice(body_index--, 1);
alt_stats.splice(alt_index--, 1);
stats.unshift(stat);
}
if (stats.length > 0) {
self.body = body_stats.length > 0 ? make_node(AST_BlockStatement, self, {
body: body_stats,
}) : make_node(AST_EmptyStatement, self);
self.alternative = alt_stats.length > 0 ? make_node(AST_BlockStatement, self, {
body: alt_stats,
}) : null;
stats.unshift(self);
return make_node(AST_BlockStatement, self, { body: stats }).optimize(compressor);
}
}
if (compressor.option("typeofs")) mark_locally_defined(self.condition, self.body, self.alternative);
return self;
function as_array(node) {
return node instanceof AST_BlockStatement ? node.body : [ node ];
}
function last_index(stats) {
for (var index = stats.length; --index >= 0;) {
if (!is_declaration(stats[index], true)) break;
}
return index;
}
function sequencesize(stat, defuns, var_defs, refs) {
if (stat == null) return [];
if (stat instanceof AST_BlockStatement) {
@@ -9753,7 +9767,7 @@ Compressor.prototype.compress = function(node) {
case 0:
var prev_block = make_node(AST_BlockStatement, prev, prev);
var next_block = make_node(AST_BlockStatement, branch, { body: statements });
if (prev_block.equivalent_to(next_block)) prev.body = [];
if (prev_block.equals(next_block)) prev.body = [];
}
}
if (side_effects.length) {
@@ -11457,7 +11471,7 @@ Compressor.prototype.compress = function(node) {
if (self.left instanceof AST_SymbolRef
&& assign instanceof AST_Assign
&& assign.operator == "="
&& self.left.equivalent_to(assign.left)) {
&& self.left.equals(assign.left)) {
return make_node(AST_Assign, self, {
operator: "=",
left: assign.left,
@@ -11483,7 +11497,7 @@ Compressor.prototype.compress = function(node) {
if ((self.left.is_string(compressor) && self.right.is_string(compressor)) ||
(self.left.is_number(compressor) && self.right.is_number(compressor)) ||
(self.left.is_boolean(compressor) && self.right.is_boolean(compressor)) ||
repeatable(compressor, self.left) && self.left.equivalent_to(self.right)) {
repeatable(compressor, self.left) && self.left.equals(self.right)) {
self.operator = self.operator.slice(0, 2);
}
// XXX: intentionally falling down to the next case
@@ -11530,7 +11544,7 @@ Compressor.prototype.compress = function(node) {
&& (is_undefined(lhs.left, compressor) && self.right.left instanceof AST_Null
|| lhs.left instanceof AST_Null && is_undefined(self.right.left, compressor))
&& !expr.has_side_effects(compressor)
&& expr.equivalent_to(self.right.right)) {
&& expr.equals(self.right.right)) {
lhs.operator = lhs.operator.slice(0, -1);
lhs.left = make_node(AST_Null, self);
return self.left;
@@ -11542,7 +11556,7 @@ Compressor.prototype.compress = function(node) {
if (compressor.option("booleans")) {
var lhs = self.left;
if (lazy_op[self.operator] && !lhs.has_side_effects(compressor)) {
if (lhs.equivalent_to(self.right)) {
if (lhs.equals(self.right)) {
return maintain_this_binding(compressor, parent, compressor.self(), lhs).optimize(compressor);
}
mark_duplicate_condition(compressor, lhs);
@@ -12494,7 +12508,7 @@ Compressor.prototype.compress = function(node) {
exprs.push(self.right);
return make_sequence(self, exprs).optimize(compressor);
}
if (self.left.equivalent_to(self.right) && !self.left.has_side_effects(compressor)) {
if (self.left.equals(self.right) && !self.left.has_side_effects(compressor)) {
return self.right;
}
var exp = self.left.expression;
@@ -12510,7 +12524,7 @@ Compressor.prototype.compress = function(node) {
}
} else if (self.left instanceof AST_SymbolRef && can_drop_symbol(self.left, compressor)) {
var parent;
if (self.operator == "=" && self.left.equivalent_to(self.right)
if (self.operator == "=" && self.left.equals(self.right)
&& !((parent = compressor.parent()) instanceof AST_UnaryPrefix && parent.operator == "delete")) {
return self.right;
}
@@ -12697,13 +12711,13 @@ Compressor.prototype.compress = function(node) {
var alternative = self.alternative;
if (repeatable(compressor, condition)) {
// x ? x : y ---> x || y
if (condition.equivalent_to(consequent)) return make_node(AST_Binary, self, {
if (condition.equals(consequent)) return make_node(AST_Binary, self, {
operator: "||",
left: condition,
right: alternative,
}).optimize(compressor);
// x ? y : x ---> x && y
if (condition.equivalent_to(alternative)) return make_node(AST_Binary, self, {
if (condition.equals(alternative)) return make_node(AST_Binary, self, {
operator: "&&",
left: condition,
right: consequent,
@@ -12720,7 +12734,7 @@ Compressor.prototype.compress = function(node) {
if ((is_eq || consequent === seq_tail)
&& alt_tail instanceof AST_Assign
&& seq_tail.operator == alt_tail.operator
&& seq_tail.left.equivalent_to(alt_tail.left)
&& seq_tail.left.equals(alt_tail.left)
&& (is_eq && seq_tail.left instanceof AST_SymbolRef
|| !condition.has_side_effects(compressor)
&& can_shift_lhs_of_tail(consequent)
@@ -12737,7 +12751,7 @@ Compressor.prototype.compress = function(node) {
}
}
// x ? y : y ---> x, y
if (consequent.equivalent_to(alternative)) return make_sequence(self, [
if (consequent.equals(alternative)) return make_sequence(self, [
condition,
consequent
]).optimize(compressor);
@@ -12751,7 +12765,7 @@ Compressor.prototype.compress = function(node) {
if (consequent instanceof AST_Call
&& alternative.TYPE == consequent.TYPE
&& (arg_index = arg_diff(consequent, alternative)) >= 0
&& consequent.expression.equivalent_to(alternative.expression)
&& consequent.expression.equals(alternative.expression)
&& !condition.has_side_effects(compressor)
&& !consequent.expression.has_side_effects(compressor)) {
var node = consequent.clone();
@@ -12771,7 +12785,7 @@ Compressor.prototype.compress = function(node) {
}
// x ? (y ? a : b) : b ---> x && y ? a : b
if (consequent instanceof AST_Conditional
&& consequent.alternative.equivalent_to(alternative)) {
&& consequent.alternative.equals(alternative)) {
return make_node(AST_Conditional, self, {
condition: make_node(AST_Binary, self, {
left: condition,
@@ -12784,7 +12798,7 @@ Compressor.prototype.compress = function(node) {
}
// x ? (y ? a : b) : a ---> !x || y ? a : b
if (consequent instanceof AST_Conditional
&& consequent.consequent.equivalent_to(alternative)) {
&& consequent.consequent.equals(alternative)) {
return make_node(AST_Conditional, self, {
condition: make_node(AST_Binary, self, {
left: negated,
@@ -12797,7 +12811,7 @@ Compressor.prototype.compress = function(node) {
}
// x ? a : (y ? a : b) ---> x || y ? a : b
if (alternative instanceof AST_Conditional
&& consequent.equivalent_to(alternative.consequent)) {
&& consequent.equals(alternative.consequent)) {
return make_node(AST_Conditional, self, {
condition: make_node(AST_Binary, self, {
left: condition,
@@ -12810,7 +12824,7 @@ Compressor.prototype.compress = function(node) {
}
// x ? b : (y ? a : b) ---> !x && y ? a : b
if (alternative instanceof AST_Conditional
&& consequent.equivalent_to(alternative.alternative)) {
&& consequent.equals(alternative.alternative)) {
return make_node(AST_Conditional, self, {
condition: make_node(AST_Binary, self, {
left: negated,
@@ -12823,7 +12837,7 @@ Compressor.prototype.compress = function(node) {
}
// x ? (a, c) : (b, c) ---> x ? a : b, c
if ((consequent instanceof AST_Sequence || alternative instanceof AST_Sequence)
&& consequent.tail_node().equivalent_to(alternative.tail_node())) {
&& consequent.tail_node().equals(alternative.tail_node())) {
return make_sequence(self, [
make_node(AST_Conditional, self, {
condition: condition,
@@ -12836,7 +12850,7 @@ Compressor.prototype.compress = function(node) {
// x ? y && a : a ---> (!x || y) && a
if (consequent instanceof AST_Binary
&& consequent.operator == "&&"
&& consequent.right.equivalent_to(alternative)) {
&& consequent.right.equals(alternative)) {
return make_node(AST_Binary, self, {
operator: "&&",
left: make_node(AST_Binary, self, {
@@ -12850,7 +12864,7 @@ Compressor.prototype.compress = function(node) {
// x ? y || a : a ---> x && y || a
if (consequent instanceof AST_Binary
&& consequent.operator == "||"
&& consequent.right.equivalent_to(alternative)) {
&& consequent.right.equals(alternative)) {
return make_node(AST_Binary, self, {
operator: "||",
left: make_node(AST_Binary, self, {
@@ -12864,7 +12878,7 @@ Compressor.prototype.compress = function(node) {
// x ? a : y && a ---> (x || y) && a
if (alternative instanceof AST_Binary
&& alternative.operator == "&&"
&& alternative.right.equivalent_to(consequent)) {
&& alternative.right.equals(consequent)) {
return make_node(AST_Binary, self, {
operator: "&&",
left: make_node(AST_Binary, self, {
@@ -12878,7 +12892,7 @@ Compressor.prototype.compress = function(node) {
// x ? a : y || a ---> !x && y || a
if (alternative instanceof AST_Binary
&& alternative.operator == "||"
&& alternative.right.equivalent_to(consequent)) {
&& alternative.right.equals(consequent)) {
return make_node(AST_Binary, self, {
operator: "||",
left: make_node(AST_Binary, self, {
@@ -12974,10 +12988,10 @@ Compressor.prototype.compress = function(node) {
var len = a.length;
if (len != b.length) return -2;
for (var i = 0; i < len; i++) {
if (!a[i].equivalent_to(b[i])) {
if (!a[i].equals(b[i])) {
if (a[i] instanceof AST_Spread !== b[i] instanceof AST_Spread) return -3;
for (var j = i + 1; j < len; j++) {
if (!a[j].equivalent_to(b[j])) return -2;
if (!a[j].equals(b[j])) return -2;
}
return i;
}
@@ -12998,7 +13012,7 @@ Compressor.prototype.compress = function(node) {
if (!(consequent instanceof AST_PropAccess)) return;
var p = consequent.property;
var q = alternative.property;
return (p instanceof AST_Node ? p.equivalent_to(q) : p == q)
return (p instanceof AST_Node ? p.equals(q) : p == q)
&& !(consequent.expression instanceof AST_Super || alternative.expression instanceof AST_Super);
}