diff options
-rw-r--r-- | lib/compress.js | 41 | ||||
-rw-r--r-- | test/compress/conditionals.js | 31 |
2 files changed, 53 insertions, 19 deletions
diff --git a/lib/compress.js b/lib/compress.js index 4534d9c8..74c0febb 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -7463,6 +7463,15 @@ merge(Compressor.prototype, { || node instanceof AST_Object; } + function repeatable(compressor, node) { + if (node instanceof AST_Dot) return repeatable(compressor, node.expression); + if (node instanceof AST_Sub) { + return repeatable(compressor, node.expression) && repeatable(compressor, node.property); + } + if (node instanceof AST_Symbol) return true; + return !node.has_side_effects(compressor); + } + OPT(AST_Binary, function(self, compressor) { function reversible() { return self.left.is_constant() @@ -7531,7 +7540,7 @@ merge(Compressor.prototype, { 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)) || - can_self_compare(self.left) && self.left.equivalent_to(self.right)) { + repeatable(compressor, self.left) && self.left.equivalent_to(self.right)) { self.operator = self.operator.slice(0, 2); } // XXX: intentionally falling down to the next case @@ -8036,13 +8045,6 @@ merge(Compressor.prototype, { } return try_evaluate(compressor, self); - function can_self_compare(node) { - if (node instanceof AST_Dot) return can_self_compare(node.expression); - if (node instanceof AST_Sub) return can_self_compare(node.expression) && can_self_compare(node.property); - if (node instanceof AST_Symbol) return true; - return !node.has_side_effects(compressor); - } - function align(ref, op) { switch (ref) { case "-": @@ -8504,14 +8506,13 @@ merge(Compressor.prototype, { }); OPT(AST_Conditional, function(self, compressor) { - if (!compressor.option("conditionals")) return self; - // This looks like lift_sequences(), should probably be under "sequences" - if (self.condition instanceof AST_Sequence) { + if (compressor.option("sequences") && self.condition instanceof AST_Sequence) { var expressions = self.condition.expressions.slice(); self.condition = expressions.pop(); expressions.push(self); return make_sequence(self, expressions); } + if (!compressor.option("conditionals")) return self; var condition = self.condition.is_truthy() || self.condition.evaluate(compressor, true); if (!condition) { AST_Node.warn("Condition always false [{file}:{line},{col}]", self.start); @@ -8532,15 +8533,19 @@ merge(Compressor.prototype, { } var consequent = self.consequent; var alternative = self.alternative; - // x ? x : y => x || y - if (condition instanceof AST_SymbolRef - && consequent instanceof AST_SymbolRef - && condition.definition() === consequent.definition()) { - return make_node(AST_Binary, self, { + if (repeatable(compressor, condition)) { + // x ? x : y => x || y + if (condition.equivalent_to(consequent)) return make_node(AST_Binary, self, { operator: "||", left: condition, - right: alternative - }); + right: alternative, + }).optimize(compressor); + // x ? y : x => x && y + if (condition.equivalent_to(alternative)) return make_node(AST_Binary, self, { + operator: "&&", + left: condition, + right: consequent, + }).optimize(compressor); } // if (foo) exp = something; else exp = something_else; // | diff --git a/test/compress/conditionals.js b/test/compress/conditionals.js index 4d54b83a..5dfd17bc 100644 --- a/test/compress/conditionals.js +++ b/test/compress/conditionals.js @@ -1159,7 +1159,7 @@ issue_1645_2: { expect_stdout: true } -condition_symbol_matches_consequent: { +condition_matches_consequent: { options = { conditionals: true, } @@ -1188,6 +1188,35 @@ condition_symbol_matches_consequent: { expect_stdout: "3 7 true 4" } +condition_matches_alternative: { + options = { + conditionals: true, + } + input: { + function foo(x, y) { + return x.p ? y[0] : x.p; + } + function bar() { + return g ? h : g; + } + var g = 4; + var h = 5; + console.log(foo({ p: 3 }, [ null ]), foo({ p: 0 }, [ 7 ]), foo({ p: true } , [ false ]), bar()); + } + expect: { + function foo(x, y) { + return x.p && y[0]; + } + function bar() { + return g && h; + } + var g = 4; + var h = 5; + console.log(foo({ p: 3 }, [ null ]), foo({ p: 0 }, [ 7 ]), foo({ p: true } , [ false ]), bar()); + } + expect_stdout: "null 0 false 5" +} + delete_conditional_1: { options = { booleans: true, |