enhance evaluate & reduce_vars (#5060)

This commit is contained in:
Alex Lam S.L
2021-07-07 17:29:23 +01:00
committed by GitHub
parent 2340feff87
commit 6577d641ac
4 changed files with 79 additions and 48 deletions

View File

@@ -734,7 +734,12 @@ merge(Compressor.prototype, {
var save = fixed; var save = fixed;
if (save) fixed = function() { if (save) fixed = function() {
var value = save(); var value = save();
return is_undefined(value) ? make_sequence(node, [ value, node.value ]) : node; var ev;
if (is_undefined(value, compressor)
|| (ev = fuzzy_eval(compressor, value, true)) === undefined) {
return make_sequence(node, [ value, node.value ]);
}
return ev instanceof AST_Node ? node : value;
}; };
node.name.walk(scanner); node.name.walk(scanner);
fixed = save; fixed = save;
@@ -7293,7 +7298,7 @@ merge(Compressor.prototype, {
node.in_bool = true; node.in_bool = true;
var value = node.value; var value = node.value;
if (value) { if (value) {
var ev = value.is_truthy() || value.evaluate(compressor, true); var ev = fuzzy_eval(compressor, value);
if (!ev) { if (!ev) {
value = value.drop_side_effect_free(compressor); value = value.drop_side_effect_free(compressor);
node.value = value ? make_sequence(node.value, [ node.value = value ? make_sequence(node.value, [
@@ -8006,7 +8011,7 @@ merge(Compressor.prototype, {
OPT(AST_Do, function(self, compressor) { OPT(AST_Do, function(self, compressor) {
if (!compressor.option("loops")) return self; if (!compressor.option("loops")) return self;
var cond = self.condition.is_truthy() || self.condition.evaluate(compressor, true); var cond = fuzzy_eval(compressor, self.condition);
if (!(cond instanceof AST_Node)) { if (!(cond instanceof AST_Node)) {
if (cond && !has_loop_control(self, compressor.parent(), AST_Continue)) return make_node(AST_For, self, { if (cond && !has_loop_control(self, compressor.parent(), AST_Continue)) return make_node(AST_For, self, {
body: make_node(AST_BlockStatement, self.body, { body: make_node(AST_BlockStatement, self.body, {
@@ -8174,36 +8179,25 @@ merge(Compressor.prototype, {
if (self.step) self.step = self.step.drop_side_effect_free(compressor); if (self.step) self.step = self.step.drop_side_effect_free(compressor);
} }
if (self.condition) { if (self.condition) {
var cond = self.condition.evaluate(compressor); var cond = fuzzy_eval(compressor, self.condition);
if (cond instanceof AST_Node) {
cond = self.condition.is_truthy() || self.condition.evaluate(compressor, true);
} else if (cond) {
self.condition = null;
}
if (!cond) { if (!cond) {
if (compressor.option("dead_code")) { if (compressor.option("dead_code")) {
var body = []; var body = [];
if (is_statement(self.init)) { if (is_statement(self.init)) {
body.push(self.init); body.push(self.init);
} else if (self.init) { } else if (self.init) {
body.push(make_node(AST_SimpleStatement, self.init, { body.push(make_node(AST_SimpleStatement, self.init, { body: self.init }));
body: self.init
}));
} }
body.push(make_node(AST_SimpleStatement, self.condition, { body.push(make_node(AST_SimpleStatement, self.condition, { body: self.condition }));
body: self.condition
}));
extract_declarations_from_unreachable_code(compressor, self.body, body); extract_declarations_from_unreachable_code(compressor, self.body, body);
return make_node(AST_BlockStatement, self, { body: body }).optimize(compressor); return make_node(AST_BlockStatement, self, { body: body }).optimize(compressor);
} }
} else if (self.condition && !(cond instanceof AST_Node)) { } else if (!(cond instanceof AST_Node)) {
self.body = make_node(AST_BlockStatement, self.body, { self.body = make_node(AST_BlockStatement, self.body, {
body: [ body: [
make_node(AST_SimpleStatement, self.condition, { make_node(AST_SimpleStatement, self.condition, { body: self.condition }),
body: self.condition self.body,
}), ],
self.body
]
}); });
self.condition = null; self.condition = null;
} }
@@ -8894,7 +8888,7 @@ merge(Compressor.prototype, {
if (!compressor.option("optional_chains")) return; if (!compressor.option("optional_chains")) return;
if (!self.optional) return; if (!self.optional) return;
var expr = self.expression; var expr = self.expression;
var ev = expr.evaluate(compressor, true); var ev = fuzzy_eval(compressor, expr, true);
if (ev == null) return make_node(AST_UnaryPrefix, self, { if (ev == null) return make_node(AST_UnaryPrefix, self, {
operator: "void", operator: "void",
expression: expr, expression: expr,
@@ -10492,7 +10486,7 @@ merge(Compressor.prototype, {
} }
// (x || false) && y ---> x ? y : false // (x || false) && y ---> x ? y : false
if (self.left.operator == "||") { if (self.left.operator == "||") {
var lr = self.left.right.evaluate(compressor, true); var lr = fuzzy_eval(compressor, self.left.right);
if (!lr) return make_node(AST_Conditional, self, { if (!lr) return make_node(AST_Conditional, self, {
condition: self.left.left, condition: self.left.left,
consequent: self.right, consequent: self.right,
@@ -10545,7 +10539,7 @@ merge(Compressor.prototype, {
} }
// x && true || y ---> x ? true : y // x && true || y ---> x ? true : y
if (!nullish && self.left.operator == "&&") { if (!nullish && self.left.operator == "&&") {
var lr = self.left.right.is_truthy() || self.left.right.evaluate(compressor, true); var lr = fuzzy_eval(compressor, self.left.right);
if (lr && !(lr instanceof AST_Node)) return make_node(AST_Conditional, self, { if (lr && !(lr instanceof AST_Node)) return make_node(AST_Conditional, self, {
condition: self.left.left, condition: self.left.left,
consequent: self.left.right, consequent: self.left.right,
@@ -11070,22 +11064,17 @@ merge(Compressor.prototype, {
} }
var local = self.fixed !== def.fixed; var local = self.fixed !== def.fixed;
if (fixed && (local || def.should_replace !== false)) { if (fixed && (local || def.should_replace !== false)) {
var init; var ev, init;
if (fixed instanceof AST_This) { if (fixed instanceof AST_This) {
if (!is_funarg(def) && same_scope(def)) { if (!is_funarg(def) && same_scope(def)) init = fixed;
init = fixed; } else if ((ev = fixed.evaluate(compressor, true)) !== fixed
}
} else {
var ev = fixed.evaluate(compressor, true);
if (ev !== fixed
&& typeof ev != "function" && typeof ev != "function"
&& (typeof ev != "object" && (ev === null
|| ev instanceof RegExp || typeof ev != "object"
&& compressor.option("unsafe_regexp") || compressor.option("unsafe_regexp")
&& !def.cross_loop && same_scope(def))) { && ev instanceof RegExp && !def.cross_loop && same_scope(def))) {
init = make_node_from_constant(ev, fixed); init = make_node_from_constant(ev, fixed);
} }
}
if (init) { if (init) {
if (!local && def.should_replace === undefined) { if (!local && def.should_replace === undefined) {
var value_length = init.optimize(compressor).print_to_string().length; var value_length = init.optimize(compressor).print_to_string().length;

View File

@@ -149,7 +149,7 @@ process_boolean_returns: {
} }
expect: { expect: {
console.log(function(a = console.log("FAIL 1")) { console.log(function(a = console.log("FAIL 1")) {
return a() ? "PASS" : "FAIL 2"; return 42 ? "PASS" : "FAIL 2";
}(function() { }(function() {
return 1; return 1;
})); }));
@@ -245,21 +245,64 @@ maintain_if: {
node_version: ">=6" node_version: ">=6"
} }
reduce_value: { reduce_funarg: {
options = { options = {
evaluate: true, evaluate: true,
keep_fargs: false,
reduce_vars: true, reduce_vars: true,
unused: true, unused: true,
} }
input: { input: {
console.log(function(a = "PASS") { console.log(...function(a = "foo", b = "bar", c = "baz") {
return a; return [ a, b, c ];
}()); }(void 0, null));
} }
expect: { expect: {
console.log("PASS"); console.log(...function() {
return [ "foo", null, "baz" ];
}());
} }
expect_stdout: "PASS" expect_stdout: "foo null baz"
node_version: ">=6"
}
reduce_array: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
unsafe: true,
unused: true,
}
input: {
var [ a = "foo", b = "bar", c = "baz" ] = [ void 0, null ];
console.log(a, b, c);
}
expect: {
var [ , , c = "baz" ] = [ void 0, null ];
console.log("foo", null, c);
}
expect_stdout: "foo null baz"
node_version: ">=6"
}
reduce_object: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
unsafe: true,
unused: true,
}
input: {
var { a = "foo", b = "bar", c = "baz" } = { a: void 0, b: null };
console.log(a, b, c);
}
expect: {
var { c = "baz" } = { a: void 0, b: null };
console.log("foo", null, c);
}
expect_stdout: "foo null baz"
node_version: ">=6" node_version: ">=6"
} }

View File

@@ -323,9 +323,7 @@ issue_4893_1: {
expect: { expect: {
try{ try{
(function f() { (function f() {
var b; null.p += 42;
b = null;
b.p += 42;
f; f;
})(); })();
} catch (e) { } catch (e) {

View File

@@ -1292,6 +1292,7 @@ toplevel_on_loops_3: {
loops: true, loops: true,
reduce_funcs: true, reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
side_effects: true,
toplevel: true, toplevel: true,
unused: true, unused: true,
} }