enhance conditionals, if_return & side_effects (#5348)

This commit is contained in:
Alex Lam S.L
2022-02-12 15:18:07 +00:00
committed by GitHub
parent 6d0bb58d68
commit a14555a39e
11 changed files with 162 additions and 164 deletions

View File

@@ -3336,23 +3336,24 @@ Compressor.prototype.compress = function(node) {
if (ab.label) remove(ab.label.thedef.references, ab); if (ab.label) remove(ab.label.thedef.references, ab);
changed = true; changed = true;
stat = stat.clone(); stat = stat.clone();
stat.condition = stat.condition.negate(compressor);
var body = as_statement_array_with_return(stat.body, ab);
stat.body = make_node(AST_BlockStatement, stat, { stat.body = make_node(AST_BlockStatement, stat, {
body: as_statement_array_with_return(stat.body, ab),
});
stat.alternative = make_node(AST_BlockStatement, stat, {
body: as_statement_array(stat.alternative).concat(extract_functions()), body: as_statement_array(stat.alternative).concat(extract_functions()),
}); });
stat.alternative = make_node(AST_BlockStatement, stat, { body: body });
statements[i] = stat; statements[i] = stat;
statements[i] = stat.transform(compressor); statements[i] = stat.transform(compressor);
continue; continue;
} }
if (ab && !stat.alternative && stat.body instanceof AST_BlockStatement && next instanceof AST_Jump) { if (ab && !stat.alternative && next instanceof AST_Jump) {
var negated = stat.condition.negate(compressor); var cond = stat.condition;
if (negated.print_to_string().length <= stat.condition.print_to_string().length) { cond = best_of_expression(cond, cond.negate(compressor), stat.body instanceof AST_BlockStatement);
if (cond !== stat.condition) {
changed = true; changed = true;
stat = stat.clone(); stat = stat.clone();
stat.condition = negated; stat.condition = cond;
statements[j] = stat.body; statements[j] = stat.body;
stat.body = next; stat.body = next;
statements[i] = stat; statements[i] = stat;
@@ -3369,8 +3370,9 @@ Compressor.prototype.compress = function(node) {
stat.body = make_node(AST_BlockStatement, stat.body, { stat.body = make_node(AST_BlockStatement, stat.body, {
body: as_statement_array(stat.body).concat(extract_functions()), body: as_statement_array(stat.body).concat(extract_functions()),
}); });
var body = as_statement_array_with_return(stat.alternative, alt); stat.alternative = make_node(AST_BlockStatement, stat.alternative, {
stat.alternative = make_node(AST_BlockStatement, stat.alternative, { body: body }); body: as_statement_array_with_return(stat.alternative, alt),
});
statements[i] = stat; statements[i] = stat;
statements[i] = stat.transform(compressor); statements[i] = stat.transform(compressor);
continue; continue;
@@ -3392,15 +3394,6 @@ Compressor.prototype.compress = function(node) {
var value = stat.body.value; var value = stat.body.value;
var in_bool = stat.body.in_bool || next instanceof AST_Return && next.in_bool; var in_bool = stat.body.in_bool || next instanceof AST_Return && next.in_bool;
//--- //---
// pretty silly case, but:
// if (foo()) return; return; ---> foo(); return;
if (!value && !stat.alternative
&& (in_lambda && !next || next instanceof AST_Return && !next.value)) {
changed = true;
statements[i] = make_node(AST_SimpleStatement, stat.condition, { body: stat.condition });
continue;
}
//---
// if (foo()) return x; return y; ---> return foo() ? x : y; // if (foo()) return x; return y; ---> return foo() ? x : y;
if (!stat.alternative && next instanceof AST_Return) { if (!stat.alternative && next instanceof AST_Return) {
changed = true; changed = true;
@@ -8211,12 +8204,12 @@ Compressor.prototype.compress = function(node) {
node.right = rhs.drop_side_effect_free(compressor); node.right = rhs.drop_side_effect_free(compressor);
} }
if (op == "??") return node; if (op == "??") return node;
var negated = make_node(AST_Binary, this, { var negated = node.clone();
operator: op == "&&" ? "||" : "&&", negated.operator = op == "&&" ? "||" : "&&";
left: left.negate(compressor, first_in_statement), negated.left = left.negate(compressor, first_in_statement);
right: node.right, if (negated.operator == negated.right.operator) swap_chain(negated);
}); var best = first_in_statement ? best_of_statement : best_of_expression;
return first_in_statement ? best_of_statement(node, negated) : best_of_expression(node, negated); return op == "&&" ? best(node, negated) : best(negated, node);
} }
var lhs = left.drop_side_effect_free(compressor, first_in_statement); var lhs = left.drop_side_effect_free(compressor, first_in_statement);
if (!lhs) return rhs; if (!lhs) return rhs;
@@ -9082,8 +9075,8 @@ Compressor.prototype.compress = function(node) {
// here because they are only used in an equality comparison later on. // here because they are only used in an equality comparison later on.
self.condition = negated; self.condition = negated;
var tmp = self.body; var tmp = self.body;
self.body = self.alternative || make_node(AST_EmptyStatement, self); self.body = self.alternative;
self.alternative = tmp; self.alternative = is_empty(tmp) ? null : tmp;
} }
var body_defuns = []; var body_defuns = [];
var body_var_defs = []; var body_var_defs = [];
@@ -9220,10 +9213,12 @@ Compressor.prototype.compress = function(node) {
var line = stat.body[i]; var line = stat.body[i];
if (line instanceof AST_EmptyStatement) continue; if (line instanceof AST_EmptyStatement) continue;
if (line instanceof AST_Exit) { if (line instanceof AST_Exit) {
if (exprs.length == 0) return; if (i == 0) return;
if (exprs.length > 0) {
line = line.clone(); line = line.clone();
exprs.push(line.value || make_node(AST_Undefined, line).transform(compressor)); exprs.push(line.value || make_node(AST_Undefined, line).transform(compressor));
line.value = make_sequence(stat, exprs); line.value = make_sequence(stat, exprs);
}
var block = stat.clone(); var block = stat.clone();
block.body = block.body.slice(i + 1); block.body = block.body.slice(i + 1);
block.body.unshift(line); block.body.unshift(line);
@@ -10962,6 +10957,23 @@ Compressor.prototype.compress = function(node) {
return !node.has_side_effects(compressor); return !node.has_side_effects(compressor);
} }
function swap_chain(self, compressor) {
var rhs = self.right;
self.left = make_node(AST_Binary, self, {
operator: self.operator,
left: self.left,
right: rhs.left,
start: self.left.start,
end: rhs.left.end
});
self.right = rhs.right;
if (compressor) {
self.left = self.left.transform(compressor);
} else if (self.operator == rhs.left.operator) {
swap_chain(self.left);
}
}
OPT(AST_Binary, function(self, compressor) { OPT(AST_Binary, function(self, compressor) {
if (commutativeOperators[self.operator] if (commutativeOperators[self.operator]
&& self.right.is_constant() && self.right.is_constant()
@@ -11132,7 +11144,7 @@ Compressor.prototype.compress = function(node) {
&& lazy_op[self.operator] && lazy_op[self.operator]
&& self.right instanceof AST_Binary && self.right instanceof AST_Binary
&& self.operator == self.right.operator) { && self.operator == self.right.operator) {
swap_chain(); swap_chain(self, compressor);
} }
if (compressor.option("strings") && self.operator == "+") { if (compressor.option("strings") && self.operator == "+") {
// "foo" + 42 + "" ---> "foo" + 42 // "foo" + 42 + "" ---> "foo" + 42
@@ -11164,7 +11176,7 @@ Compressor.prototype.compress = function(node) {
&& (self.left.is_string(compressor) && self.right.is_string(compressor) && (self.left.is_string(compressor) && self.right.is_string(compressor)
|| self.right.left.is_string(compressor) || self.right.left.is_string(compressor)
&& (self.left.is_constant() || !self.right.right.has_side_effects(compressor)))) { && (self.left.is_constant() || !self.right.right.has_side_effects(compressor)))) {
swap_chain(); swap_chain(self, compressor);
} }
} }
if (compressor.option("evaluate")) { if (compressor.option("evaluate")) {
@@ -11631,19 +11643,6 @@ Compressor.prototype.compress = function(node) {
self.right = tmp; self.right = tmp;
} }
} }
function swap_chain() {
var rhs = self.right;
self.left = make_node(AST_Binary, self, {
operator: self.operator,
left: self.left,
right: rhs.left,
start: self.left.start,
end: rhs.left.end
});
self.right = rhs.right;
self.left = self.left.transform(compressor);
}
}); });
OPT(AST_SymbolExport, function(self) { OPT(AST_SymbolExport, function(self) {
@@ -12747,7 +12746,7 @@ Compressor.prototype.compress = function(node) {
if (flatten && value.has_side_effects(compressor)) flatten = false; if (flatten && value.has_side_effects(compressor)) flatten = false;
} }
} }
if (!flatten) values.unshift(retValue); values.unshift(retValue);
while (--i >= 0) { while (--i >= 0) {
var value = elements[i].drop_side_effect_free(compressor); var value = elements[i].drop_side_effect_free(compressor);
if (value) { if (value) {
@@ -12758,10 +12757,7 @@ Compressor.prototype.compress = function(node) {
index--; index--;
} }
} }
if (flatten) { return flatten ? make_sequence(self, values).optimize(compressor) : make_node(AST_Sub, self, {
values.push(retValue);
return make_sequence(self, values).optimize(compressor);
} else return make_node(AST_Sub, self, {
expression: make_node(AST_Array, expr, { elements: values }), expression: make_node(AST_Array, expr, { elements: values }),
property: make_node(AST_Number, prop, { value: index }), property: make_node(AST_Number, prop, { value: index }),
}); });

View File

@@ -489,7 +489,7 @@ issue_3413: {
} }
expect: { expect: {
var b; var b;
void 0 !== ("" < b || void 0) || console.log("PASS"); void 0 === ("" < b || void 0) && console.log("PASS");
} }
expect_stdout: "PASS" expect_stdout: "PASS"
} }

View File

@@ -597,8 +597,7 @@ do_if_continue_1: {
} }
expect: { expect: {
do { do {
if (!console); if (console) {
else {
console.log("PASS"); console.log("PASS");
{ {
const a = 0; const a = 0;
@@ -628,8 +627,7 @@ do_if_continue_2: {
} }
expect: { expect: {
do { do {
if (!console); if (console) {
else {
console.log("PASS"); console.log("PASS");
{ {
const a = 0; const a = 0;
@@ -1518,6 +1516,7 @@ issue_4689: {
issue_4691: { issue_4691: {
options = { options = {
conditionals: true,
if_return: true, if_return: true,
toplevel: true, toplevel: true,
} }

View File

@@ -7981,6 +7981,7 @@ issue_5264_2: {
issue_5283: { issue_5283: {
options = { options = {
conditionals: true,
if_return: true, if_return: true,
inline: true, inline: true,
pure_getters: "strict", pure_getters: "strict",
@@ -8005,11 +8006,10 @@ issue_5283: {
var a = "FAIL 1"; var a = "FAIL 1";
(function() { (function() {
a = "PASS"; a = "PASS";
if (!console) console || function(a) {
(function(a) {
console.log("FAIL 2"); console.log("FAIL 2");
a.p; a.p;
})(); }();
})(); })();
console.log(a); console.log(a);
} }

View File

@@ -698,7 +698,9 @@ iife_if_return_simple: {
nested_if_break: { nested_if_break: {
options = { options = {
conditionals: true,
if_return: true, if_return: true,
side_effects: true,
} }
input: { input: {
for (var i = 0; i < 3; i++) for (var i = 0; i < 3; i++)
@@ -709,8 +711,7 @@ nested_if_break: {
} }
expect: { expect: {
for (var i = 0; i < 3; i++) for (var i = 0; i < 3; i++)
L1: if ("number" == typeof i) L1: "number" == typeof i && 0 !== i && console.log(i);
if (0 !== i) console.log(i);
} }
expect_stdout: [ expect_stdout: [
"1", "1",
@@ -749,11 +750,11 @@ nested_if_continue: {
function f(n) { function f(n) {
for (var i = 0; for (var i = 0;
"number" == typeof n "number" == typeof n
&& (0 !== n && (0 === n
? 1 !== n ? console.log("even", i)
? i++ : 1 === n
: console.log("odd", i) ? console.log("odd", i)
: console.log("even", i)), : i++),
0 <= (n -= 2);); 0 <= (n -= 2););
} }
f(37); f(37);

View File

@@ -5,9 +5,8 @@ multiple_functions: {
} }
input: { input: {
(function() { (function() {
if ( !window ) { if (!window)
return; return;
}
function f() {} function f() {}
function g() {} function g() {}
})(); })();
@@ -30,9 +29,8 @@ single_function: {
} }
input: { input: {
(function() { (function() {
if ( !window ) { if (!window)
return; return;
}
function f() {} function f() {}
})(); })();
} }
@@ -51,14 +49,12 @@ deeply_nested: {
} }
input: { input: {
(function() { (function() {
if ( !window ) { if (!window)
return; return;
}
function f() {} function f() {}
function g() {} function g() {}
if ( !document ) { if (!document)
return; return;
}
function h() {} function h() {}
})(); })();
} }
@@ -66,8 +62,8 @@ deeply_nested: {
(function() { (function() {
// NOTE: other compression steps will reduce this // NOTE: other compression steps will reduce this
// down to just `window`. // down to just `window`.
if ( window ) if (!window);
if ( !document ); else if (!document);
function f() {} function f() {}
function g() {} function g() {}
function h() {} function h() {}
@@ -82,16 +78,16 @@ not_hoisted_when_already_nested: {
} }
input: { input: {
(function() { (function() {
if ( !window ) { if (!window)
return; return;
}
if (foo) function f() {} if (foo) function f() {}
})(); })();
} }
expect: { expect: {
(function() { (function() {
if ( window ) if (!window);
if ( foo ) function f() {} else if (foo)
function f() {}
})(); })();
} }
} }
@@ -104,15 +100,19 @@ defun_if_return: {
input: { input: {
function e() { function e() {
function f() {} function f() {}
if (!window) return; if (!window)
else function g() {} return;
else
function g() {}
function h() {} function h() {}
} }
} }
expect: { expect: {
function e() { function e() {
function f() {} function f() {}
if (window) function g() {} if (!window);
else
function g() {}
function h() {} function h() {}
} }
} }
@@ -126,8 +126,10 @@ defun_hoist_funs: {
input: { input: {
function e() { function e() {
function f() {} function f() {}
if (!window) return; if (!window)
else function g() {} return;
else
function g() {}
function h() {} function h() {}
} }
} }
@@ -136,7 +138,7 @@ defun_hoist_funs: {
function f() {} function f() {}
function g() {} function g() {}
function h() {} function h() {}
if (window); if (!window);
} }
} }
} }
@@ -149,15 +151,18 @@ defun_else_if_return: {
input: { input: {
function e() { function e() {
function f() {} function f() {}
if (window) function g() {} if (window)
else return; function g() {}
else
return;
function h() {} function h() {}
} }
} }
expect: { expect: {
function e() { function e() {
function f() {} function f() {}
if (window) function g() {} if (window)
function g() {}
function h() {} function h() {}
} }
} }

View File

@@ -40,6 +40,9 @@ conditional_false_stray_else_in_loop: {
console.log(i); console.log(i);
} }
} }
expect_exact: "for(var i=1;i<=4;++i)if(!(i<=2))console.log(i);" expect_exact: "for(var i=1;i<=4;++i)if(i<=2);else console.log(i);"
expect_stdout: true expect_stdout: [
"3",
"4",
]
} }

View File

@@ -1,4 +1,4 @@
issue979_reported: { reported: {
options = { options = {
booleans: true, booleans: true,
comparisons: true, comparisons: true,
@@ -17,18 +17,15 @@ issue979_reported: {
} }
input: { input: {
function f1() { function f1() {
if (a == 1 || b == 2) { if (a == 1 || b == 2)
foo(); foo();
} }
}
function f2() { function f2() {
if (!(a == 1 || b == 2)) { if (!(a == 1 || b == 2));
} else
else {
foo(); foo();
} }
} }
}
expect: { expect: {
function f1() { function f1() {
1 != a && 2 != b || foo(); 1 != a && 2 != b || foo();
@@ -39,7 +36,7 @@ issue979_reported: {
} }
} }
issue979_test_negated_is_best: { test_negated_is_best: {
options = { options = {
booleans: true, booleans: true,
comparisons: true, comparisons: true,
@@ -58,38 +55,30 @@ issue979_test_negated_is_best: {
} }
input: { input: {
function f3() { function f3() {
if (a == 1 | b == 2) { if (a == 1 | b == 2)
foo(); foo();
} }
}
function f4() { function f4() {
if (!(a == 1 | b == 2)) { if (!(a == 1 | b == 2));
} else
else {
foo(); foo();
} }
}
function f5() { function f5() {
if (a == 1 && b == 2) { if (a == 1 && b == 2)
foo(); foo();
} }
}
function f6() { function f6() {
if (!(a == 1 && b == 2)) { if (!(a == 1 && b == 2));
} else
else {
foo(); foo();
} }
}
function f7() { function f7() {
if (a == 1 || b == 2) { if (a == 1 || b == 2)
foo(); foo();
} else
else {
return bar(); return bar();
} }
} }
}
expect: { expect: {
function f3() { function f3() {
1 == a | 2 == b && foo(); 1 == a | 2 == b && foo();
@@ -101,10 +90,12 @@ issue979_test_negated_is_best: {
1 == a && 2 == b && foo(); 1 == a && 2 == b && foo();
} }
function f6() { function f6() {
1!=a||2!=b||foo(); 1 == a && 2 == b && foo();
} }
function f7() { function f7() {
if(1!=a&&2!=b)return bar();foo() if (1 != a && 2 != b)
return bar();
foo();
} }
} }
} }

View File

@@ -912,8 +912,7 @@ do_if_continue_1: {
expect: { expect: {
"use strict"; "use strict";
do { do {
if (!console); if (console) {
else {
console.log("PASS"); console.log("PASS");
{ {
let a = 0; let a = 0;
@@ -946,8 +945,7 @@ do_if_continue_2: {
expect: { expect: {
"use strict"; "use strict";
do { do {
if (!console); if (console) {
else {
console.log("FAIL"); console.log("FAIL");
{ {
let a = 0; let a = 0;
@@ -1667,9 +1665,7 @@ issue_4438: {
expect: { expect: {
"use strict"; "use strict";
function f() { function f() {
if (!console) if (console) {
;
else {
let a = console.log; let a = console.log;
void a("PASS"); void a("PASS");
} }
@@ -1757,6 +1753,7 @@ issue_4689: {
issue_4691: { issue_4691: {
options = { options = {
conditionals: true,
if_return: true, if_return: true,
toplevel: true, toplevel: true,
} }

View File

@@ -617,7 +617,7 @@ issue_4730_2: {
} }
expect: { expect: {
var a; var a;
!console.log("PASS") || a && a[a.p]; console.log("PASS") && a && a[a.p];
} }
expect_stdout: "PASS" expect_stdout: "PASS"
} }

View File

@@ -307,7 +307,7 @@ typeof_defined_1: {
} }
expect: { expect: {
"undefined" == typeof A && A; "undefined" == typeof A && A;
"undefined" != typeof A || A; "undefined" == typeof A && A;
} }
} }
@@ -324,7 +324,7 @@ typeof_defined_2: {
} }
expect: { expect: {
"function" != typeof A && A; "function" != typeof A && A;
"function" == typeof A || A; "function" != typeof A && A;
} }
} }
@@ -355,16 +355,19 @@ typeof_defined_3: {
"undefined" == typeof A && "undefined" == typeof B && (A, B); "undefined" == typeof A && "undefined" == typeof B && (A, B);
"undefined" == typeof A && "undefined" != typeof B && A; "undefined" == typeof A && "undefined" != typeof B && A;
"undefined" != typeof A && "undefined" == typeof B && B; "undefined" != typeof A && "undefined" == typeof B && B;
// dropped
"undefined" == typeof A && "undefined" == typeof B || (A, B); "undefined" == typeof A && "undefined" == typeof B || (A, B);
"undefined" == typeof A && "undefined" != typeof B || (A, B); "undefined" == typeof A && "undefined" != typeof B || (A, B);
"undefined" != typeof A && "undefined" == typeof B || (A, B); "undefined" != typeof A && "undefined" == typeof B || (A, B);
"undefined" != typeof A && "undefined" != typeof B || (A, B); "undefined" != typeof A && "undefined" != typeof B || (A, B);
"undefined" == typeof A || "undefined" == typeof B && B; "undefined" != typeof A && "undefined" == typeof B && B;
"undefined" != typeof A || "undefined" == typeof B && (A, B); // dropped
"undefined" != typeof A || "undefined" != typeof B && A; "undefined" == typeof A && "undefined" == typeof B && (A, B);
"undefined" == typeof A || "undefined" != typeof B || B; "undefined" == typeof A && "undefined" != typeof B && A;
"undefined" != typeof A || "undefined" == typeof B || A; // dropped
"undefined" != typeof A || "undefined" != typeof B || (A, B); "undefined" != typeof A && "undefined" == typeof B && B;
"undefined" == typeof A && "undefined" != typeof B && A;
"undefined" == typeof A && "undefined" == typeof B && (A, B);
} }
} }
@@ -392,6 +395,7 @@ typeof_defined_4: {
"object" != typeof A || "object" != typeof B || (A, B); "object" != typeof A || "object" != typeof B || (A, B);
} }
expect: { expect: {
// dropped
"object" == typeof A && "object" != typeof B && B; "object" == typeof A && "object" != typeof B && B;
"object" != typeof A && "object" == typeof B && A; "object" != typeof A && "object" == typeof B && A;
"object" != typeof A && "object" != typeof B && (A, B); "object" != typeof A && "object" != typeof B && (A, B);
@@ -399,12 +403,14 @@ typeof_defined_4: {
"object" == typeof A && "object" != typeof B || (A, B); "object" == typeof A && "object" != typeof B || (A, B);
"object" != typeof A && "object" == typeof B || (A, B); "object" != typeof A && "object" == typeof B || (A, B);
"object" != typeof A && "object" != typeof B || (A, B); "object" != typeof A && "object" != typeof B || (A, B);
"object" == typeof A || "object" == typeof B && A; "object" != typeof A && "object" == typeof B && A;
"object" == typeof A || "object" != typeof B && (A, B); "object" != typeof A && "object" != typeof B && (A, B);
"object" != typeof A || "object" != typeof B && B; // dropped
"object" == typeof A || "object" == typeof B || (A, B); "object" == typeof A && "object" != typeof B && B;
"object" == typeof A || "object" != typeof B || A; "object" != typeof A && "object" != typeof B && (A, B);
"object" != typeof A || "object" == typeof B || B; "object" != typeof A && "object" == typeof B && A;
"object" == typeof A && "object" != typeof B && B;
// dropped
} }
} }