From d5afe16bc8feafa3f20386872e69743021949667 Mon Sep 17 00:00:00 2001 From: "Alex Lam S.L" Date: Sun, 20 Feb 2022 17:25:37 +0000 Subject: [PATCH] enhance `booleans` & `evaluate` (#5364) --- lib/compress.js | 73 ++++++++++++++++----------------------- test/compress/booleans.js | 21 +++++++++++ test/compress/evaluate.js | 19 ++++++++++ 3 files changed, 70 insertions(+), 43 deletions(-) diff --git a/lib/compress.js b/lib/compress.js index 6b083d082f..6bab55792a 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -11134,21 +11134,17 @@ Compressor.prototype.compress = function(node) { } if (in_bool) switch (self.operator) { case "+": - var ll = self.left.evaluate(compressor); - var rr = self.right.evaluate(compressor); - if (ll && typeof ll == "string") { + var ev = self.left.evaluate(compressor, true); + if (ev && typeof ev == "string" || (ev = self.right.evaluate(compressor, true)) && typeof ev == "string") { AST_Node.warn("+ in boolean context always true [{file}:{line},{col}]", self.start); - return make_sequence(self, [ - self.right, - make_node(AST_True, self) - ]).optimize(compressor); - } - if (rr && typeof rr == "string") { - AST_Node.warn("+ in boolean context always true [{file}:{line},{col}]", self.start); - return make_sequence(self, [ - self.left, - make_node(AST_True, self) - ]).optimize(compressor); + var exprs = []; + if (self.left.evaluate(compressor) instanceof AST_Node) exprs.push(self.left); + if (self.right.evaluate(compressor) instanceof AST_Node) exprs.push(self.right); + if (exprs.length < 2) { + exprs.push(make_node(AST_True, self)); + return make_sequence(self, exprs).optimize(compressor); + } + self.truthy = true; } break; case "==": @@ -11231,20 +11227,15 @@ Compressor.prototype.compress = function(node) { AST_Node.warn("Condition left of && always true [{file}:{line},{col}]", self.start); return make_sequence(self, [ self.left, self.right ]).optimize(compressor); } - var rr = self.right.evaluate(compressor); - if (!rr) { - if (in_bool) { + if (!self.right.evaluate(compressor, true)) { + if (in_bool && !(self.right.evaluate(compressor) instanceof AST_Node)) { AST_Node.warn("Boolean && always false [{file}:{line},{col}]", self.start); - return make_sequence(self, [ - self.left, - make_node(AST_False, self) - ]).optimize(compressor); + return make_sequence(self, [ self.left, make_node(AST_False, self) ]).optimize(compressor); } else self.falsy = true; - } else if (!(rr instanceof AST_Node)) { - if (in_bool || parent.operator == "&&" && parent.left === compressor.self()) { - AST_Node.warn("Dropping side-effect-free && [{file}:{line},{col}]", self.start); - return self.left.optimize(compressor); - } + } else if ((in_bool || parent.operator == "&&" && parent.left === compressor.self()) + && !(self.right.evaluate(compressor) instanceof AST_Node)) { + AST_Node.warn("Dropping side-effect-free && [{file}:{line},{col}]", self.start); + return self.left.optimize(compressor); } // (x || false) && y ---> x ? y : false if (self.left.operator == "||") { @@ -11279,25 +11270,21 @@ Compressor.prototype.compress = function(node) { }); return maintain_this_binding(compressor, parent, compressor.self(), self.left).optimize(compressor); } - var rr = self.right.evaluate(compressor); - if (!rr) { - if (in_bool || parent.operator == "||" && parent.left === compressor.self()) { - AST_Node.warn("Dropping side-effect-free {operator} [{file}:{line},{col}]", { - operator: self.operator, - file: self.start.file, - line: self.start.line, - col: self.start.col, - }); - return self.left.optimize(compressor); - } - } else if (!nullish && !(rr instanceof AST_Node)) { - if (in_bool) { + var rr; + if (!nullish && (rr = self.right.evaluate(compressor, true)) && !(rr instanceof AST_Node)) { + if (in_bool && !(self.right.evaluate(compressor) instanceof AST_Node)) { AST_Node.warn("Boolean || always true [{file}:{line},{col}]", self.start); - return make_sequence(self, [ - self.left, - make_node(AST_True, self) - ]).optimize(compressor); + return make_sequence(self, [ self.left, make_node(AST_True, self) ]).optimize(compressor); } else self.truthy = true; + } else if ((in_bool || parent.operator == "||" && parent.left === compressor.self()) + && !self.right.evaluate(compressor)) { + AST_Node.warn("Dropping side-effect-free {operator} [{file}:{line},{col}]", { + operator: self.operator, + file: self.start.file, + line: self.start.line, + col: self.start.col, + }); + return self.left.optimize(compressor); } // x && true || y ---> x ? true : y if (!nullish && self.left.operator == "&&") { diff --git a/test/compress/booleans.js b/test/compress/booleans.js index 1bb3c993f6..a27eed08c8 100644 --- a/test/compress/booleans.js +++ b/test/compress/booleans.js @@ -427,6 +427,27 @@ negated_if: { expect_stdout: "PASS" } +concat_truthy: { + options = { + booleans: true, + evaluate: true, + } + input: { + console.log("foo") + (console.log("bar"), "baz") || console.log("moo"); + } + expect: { + console.log("foo") + (console.log("bar"), "baz"); + } + expect_stdout: [ + "foo", + "bar", + ] + expect_warnings: [ + "WARN: + in boolean context always true [test/compress/booleans.js:1,8]", + "WARN: Condition left of || always true [test/compress/booleans.js:1,8]", + ] +} + issue_3465_1: { options = { booleans: true, diff --git a/test/compress/evaluate.js b/test/compress/evaluate.js index da45378429..d6e2867d45 100644 --- a/test/compress/evaluate.js +++ b/test/compress/evaluate.js @@ -888,6 +888,25 @@ unsafe_charAt_noop: { expect_stdout: "f n" } +chained_side_effects: { + options = { + evaluate: true, + } + input: { + console.log("foo") || (console.log("bar"), "baz") || console.log("moo"); + } + expect: { + console.log("foo") || (console.log("bar"), "baz"); + } + expect_stdout: [ + "foo", + "bar", + ] + expect_warnings: [ + "WARN: Condition left of || always true [test/compress/evaluate.js:1,8]", + ] +} + issue_1649: { options = { evaluate: true,