From: Alex Lam S.L Date: Thu, 7 Dec 2017 17:15:31 +0000 (+0800) Subject: account for side-effects in conditional call inversion (#2562) X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=3e34f62a1c48ab45db34cfb08d8dd2118c5780f0;p=UglifyJS.git account for side-effects in conditional call inversion (#2562) fixes #2560 --- diff --git a/lib/compress.js b/lib/compress.js index 4195ab24..e59dce63 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -4652,18 +4652,22 @@ merge(Compressor.prototype, { }); } // x ? y(a) : y(b) --> y(x ? a : b) + var arg_index; if (consequent instanceof AST_Call && alternative.TYPE === consequent.TYPE - && consequent.args.length == 1 - && alternative.args.length == 1 + && consequent.args.length > 0 + && consequent.args.length == alternative.args.length && consequent.expression.equivalent_to(alternative.expression) - && !consequent.expression.has_side_effects(compressor)) { - consequent.args[0] = make_node(AST_Conditional, self, { + && !self.condition.has_side_effects(compressor) + && !consequent.expression.has_side_effects(compressor) + && typeof (arg_index = single_arg_diff()) == "number") { + var node = consequent.clone(); + node.args[arg_index] = make_node(AST_Conditional, self, { condition: self.condition, - consequent: consequent.args[0], - alternative: alternative.args[0] + consequent: consequent.args[arg_index], + alternative: alternative.args[arg_index] }); - return consequent; + return node; } // x?y?z:a:a --> x&&y?z:a if (consequent instanceof AST_Conditional @@ -4760,6 +4764,19 @@ merge(Compressor.prototype, { && node.expression instanceof AST_Constant && node.expression.getValue()); } + + function single_arg_diff() { + var a = consequent.args; + var b = alternative.args; + for (var i = 0, len = a.length; i < len; i++) { + if (!a[i].equivalent_to(b[i])) { + for (var j = i + 1; j < len; j++) { + if (!a[j].equivalent_to(b[j])) return; + } + return i; + } + } + } }); OPT(AST_Boolean, function(self, compressor){ diff --git a/test/compress/conditionals.js b/test/compress/conditionals.js index 89c05263..143ece4a 100644 --- a/test/compress/conditionals.js +++ b/test/compress/conditionals.js @@ -166,22 +166,24 @@ cond_1: { conditionals: true }; input: { - var do_something; // if undeclared it's assumed to have side-effects - if (some_condition()) { - do_something(x); - } else { - do_something(y); - } - if (some_condition()) { - side_effects(x); - } else { - side_effects(y); + function foo(do_something, some_condition) { + if (some_condition) { + do_something(x); + } else { + do_something(y); + } + if (some_condition) { + side_effects(x); + } else { + side_effects(y); + } } } expect: { - var do_something; - do_something(some_condition() ? x : y); - some_condition() ? side_effects(x) : side_effects(y); + function foo(do_something, some_condition) { + do_something(some_condition ? x : y); + some_condition ? side_effects(x) : side_effects(y); + } } } @@ -190,16 +192,18 @@ cond_2: { conditionals: true }; input: { - var x, FooBar; - if (some_condition()) { - x = new FooBar(1); - } else { - x = new FooBar(2); + function foo(x, FooBar, some_condition) { + if (some_condition) { + x = new FooBar(1); + } else { + x = new FooBar(2); + } } } expect: { - var x, FooBar; - x = new FooBar(some_condition() ? 1 : 2); + function foo(x, FooBar, some_condition) { + x = new FooBar(some_condition ? 1 : 2); + } } } @@ -605,6 +609,42 @@ cond_8c: { } } +cond_9: { + options = { + conditionals: true, + } + input: { + function f(x, y) { + g() ? x(1) : x(2); + x ? (y || x)() : (y || x)(); + x ? y(a, b) : y(d, b, c); + x ? y(a, b, c) : y(a, b, c); + x ? y(a, b, c) : y(a, b, f); + x ? y(a, b, c) : y(a, e, c); + x ? y(a, b, c) : y(a, e, f); + x ? y(a, b, c) : y(d, b, c); + x ? y(a, b, c) : y(d, b, f); + x ? y(a, b, c) : y(d, e, c); + x ? y(a, b, c) : y(d, e, f); + } + } + expect: { + function f(x, y) { + g() ? x(1) : x(2); + x, (y || x)(); + x ? y(a, b) : y(d, b, c); + x, y(a, b, c); + y(a, b, x ? c : f); + y(a, x ? b : e, c); + x ? y(a, b, c) : y(a, e, f); + y(x ? a : d, b, c); + x ? y(a, b, c) : y(d, b, f); + x ? y(a, b, c) : y(d, e, c); + x ? y(a, b, c) : y(d, e, f); + } + } +} + ternary_boolean_consequent: { options = { collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true, @@ -1115,3 +1155,51 @@ issue_2535_2: { "false", ] } + +issue_2560: { + options = { + conditionals: true, + inline: true, + reduce_funcs: true, + reduce_vars: true, + toplevel: true, + unused: true, + } + input: { + function log(x) { + console.log(x); + } + function foo() { + return log; + } + function bar() { + if (x !== (x = foo())) { + x(1); + } else { + x(2); + } + } + var x = function() { + console.log("init"); + }; + bar(); + bar(); + } + expect: { + function log(x) { + console.log(x); + } + function bar() { + x !== (x = log) ? x(1) : x(2); + } + var x = function() { + console.log("init"); + }; + bar(); + bar(); + } + expect_stdout: [ + "1", + "2", + ] +}