Improve optimizing `function() { if(c){return foo} bar();}`
authorAnthony Van de Gejuchte <anthonyvdgent@gmail.com>
Sat, 18 Feb 2017 10:56:18 +0000 (18:56 +0800)
committeralexlamsl <alexlamsl@gmail.com>
Sat, 18 Feb 2017 10:56:18 +0000 (18:56 +0800)
closes #1437

lib/compress.js
test/compress/if_return.js
test/compress/issue-979.js
test/mocha/cli.js

index 4e45df9..04aa107 100644 (file)
@@ -546,7 +546,7 @@ merge(Compressor.prototype, {
             var self = compressor.self();
             var multiple_if_returns = has_multiple_if_returns(statements);
             var in_lambda = self instanceof AST_Lambda;
-            var ret = [];
+            var ret = []; // Optimized statements, build from tail to front
             loop: for (var i = statements.length; --i >= 0;) {
                 var stat = statements[i];
                 switch (true) {
@@ -607,19 +607,21 @@ merge(Compressor.prototype, {
                             ret = funs.concat([ stat.transform(compressor) ]);
                             continue loop;
                         }
+
                         //---
-                        // XXX: what was the intention of this case?
+                        // if (a) return b; if (c) return d; e; ==> return a ? b : c ? d : void e;
+                        //
                         // if sequences is not enabled, this can lead to an endless loop (issue #866).
                         // however, with sequences on this helps producing slightly better output for
                         // the example code.
                         if (compressor.option("sequences")
+                            && i > 0 && statements[i - 1] instanceof AST_If && statements[i - 1].body instanceof AST_Return
                             && ret.length == 1 && in_lambda && ret[0] instanceof AST_SimpleStatement
-                            && (!stat.alternative || stat.alternative instanceof AST_SimpleStatement)) {
+                            && !stat.alternative) {
                             CHANGED = true;
                             ret.push(make_node(AST_Return, ret[0], {
                                 value: make_node(AST_Undefined, ret[0])
                             }).transform(compressor));
-                            ret = as_statement_array(stat.alternative).concat(ret);
                             ret.unshift(stat);
                             continue loop;
                         }
index 78a6e81..0ac45c3 100644 (file)
@@ -170,8 +170,51 @@ if_return_7: {
         }
     }
     expect: {
-        // suboptimal
-        function f(x){return!!x||(foo(),void bar())}
+        function f(x){if(x)return!0;foo(),bar()}
+    }
+}
+
+if_return_8: {
+    options = {
+        if_return:     true,
+        sequences:     true,
+        conditionals:  true,
+        side_effects : true,
+    }
+    input: {
+        function f(e) {
+            if (2 == e) return foo();
+            if (3 == e) return bar();
+            if (4 == e) return baz();
+            fail(e);
+        }
+
+        function g(e) {
+            if (a(e)) return foo();
+            if (b(e)) return bar();
+            if (c(e)) return baz();
+            fail(e);
+        }
+
+        function h(e) {
+            if (a(e)) return foo();
+            else if (b(e)) return bar();
+            else if (c(e)) return baz();
+            else fail(e);
+        }
+
+        function i(e) {
+            if (a(e)) return foo();
+            else if (b(e)) return bar();
+            else if (c(e)) return baz();
+            fail(e);
+        }
+    }
+    expect: {
+        function f(e){return 2==e?foo():3==e?bar():4==e?baz():void fail(e)}
+        function g(e){return a(e)?foo():b(e)?bar():c(e)?baz():void fail(e)}
+        function h(e){return a(e)?foo():b(e)?bar():c(e)?baz():void fail(e)}
+        function i(e){return a(e)?foo():b(e)?bar():c(e)?baz():void fail(e)}
     }
 }
 
@@ -205,3 +248,57 @@ issue_1089: {
         }
     }
 }
+
+issue_1437: {
+    options = {
+        if_return    : true,
+        sequences    : true,
+        conditionals : false
+    }
+    input: {
+        function x() {
+            if (a())
+                return b();
+            if (c())
+                return d();
+            else
+                e();
+            f();
+        }
+    }
+    expect: {
+        function x() {
+            if (a())
+                return b();
+            if (c())
+                return d();
+            else
+                e()
+            f();
+        }
+    }
+}
+
+issue_1437_conditionals: {
+    options = {
+        conditionals : true,
+        if_return    : true,
+        sequences    : true
+    }
+    input: {
+        function x() {
+            if (a())
+                return b();
+            if (c())
+                return d();
+            else
+                e();
+            f();
+        }
+    }
+    expect: {
+        function x() {
+            return a() ? b() : c() ? d() : (e(), f(), void 0);
+        }
+    }
+}
index bae15db..7ed5801 100644 (file)
@@ -82,7 +82,7 @@ issue979_test_negated_is_best: {
             1!=a||2!=b||foo();
         }
         function f7() {
-            return 1!=a&&2!=b?bar():void foo();
+            if(1!=a&&2!=b)return bar();foo()
         }
     }
 }
index a8de05c..c5b571b 100644 (file)
@@ -4,7 +4,7 @@ var exec = require("child_process").exec;
 describe("bin/uglifyjs", function () {
     var uglifyjscmd = '"' + process.argv[0] + '" bin/uglifyjs';
     it("should produce a functional build when using --self", function (done) {
-        this.timeout(5000);
+        this.timeout(15000);
 
         var command = uglifyjscmd + ' --self -cm --wrap WrappedUglifyJS';