enhance `compress` on arrow and `async` functions (#4616)
authorAlex Lam S.L <alexlamsl@gmail.com>
Sat, 6 Feb 2021 04:39:46 +0000 (04:39 +0000)
committerGitHub <noreply@github.com>
Sat, 6 Feb 2021 04:39:46 +0000 (12:39 +0800)
lib/compress.js
test/compress/arrows.js
test/compress/awaits.js
test/compress/evaluate.js
test/compress/pure_getters.js

index 781b59f..d4cf0da 100644 (file)
@@ -1843,7 +1843,7 @@ merge(Compressor.prototype, {
                 if (node instanceof AST_Call) {
                     if (!(lhs instanceof AST_PropAccess)) return false;
                     if (!lhs.equivalent_to(node.expression)) return false;
-                    return !(rvalue instanceof AST_Function && !rvalue.contains_this());
+                    return !(is_function(rvalue) && !rvalue.contains_this());
                 }
                 if (node instanceof AST_Debugger) return true;
                 if (node instanceof AST_Defun) return funarg && lhs.name === node.name.name;
@@ -2482,7 +2482,7 @@ merge(Compressor.prototype, {
                         if (modify_toplevel) return;
                         var exp = node.expression;
                         if (exp instanceof AST_PropAccess) return;
-                        if (exp instanceof AST_Function && !exp.contains_this()) return;
+                        if (is_function(exp) && !exp.contains_this()) return;
                         modify_toplevel = true;
                     } else if (node instanceof AST_PropAccess && may_be_global(node.expression)) {
                         if (node === lhs && !(expr instanceof AST_Unary)) {
@@ -4060,7 +4060,7 @@ merge(Compressor.prototype, {
                         key = key._eval(compressor, ignore_side_effects, cached, depth);
                         if (key === prop.key) return this;
                     }
-                    if (prop.value instanceof AST_Function && typeof Object.prototype[key] == "function") return this;
+                    if (key == "toString" || key == "valueOf") return this;
                     val[key] = prop.value._eval(compressor, ignore_side_effects, cached, depth);
                     if (val[key] === prop.value) return this;
                 }
@@ -5850,10 +5850,10 @@ merge(Compressor.prototype, {
                             }
                         } else if (compressor.option("functions")
                             && !compressor.option("ie8")
-                            && !(node instanceof AST_Const || node instanceof AST_Let)
+                            && node instanceof AST_Var
                             && var_defs[sym.id] == 1
                             && sym.assignments == 0
-                            && value instanceof AST_Function
+                            && (value instanceof AST_AsyncFunction || value instanceof AST_Function)
                             && (sym.references.length ? all(sym.references, function(ref) {
                                     return value === ref.fixed_value();
                                 }) : value === def.name.fixed_value())
@@ -5864,7 +5864,7 @@ merge(Compressor.prototype, {
                             && can_declare_defun()
                             && can_rename(value, def.name.name)) {
                             AST_Node.warn("Declaring {name} as function [{file}:{line},{col}]", template(def.name));
-                            var defun = make_node(AST_Defun, def, value);
+                            var defun = make_node(value instanceof AST_Function ? AST_Defun : AST_AsyncDefun, def, value);
                             defun.name = make_node(AST_SymbolDefun, def.name, def.name);
                             var name_def = def.name.scope.resolve().def_function(defun.name);
                             if (old_def) old_def.forEach(function(node) {
@@ -6902,7 +6902,7 @@ merge(Compressor.prototype, {
                 return exprs && make_sequence(self, exprs.map(convert_spread));
             }
             var def;
-            if (exp instanceof AST_Function
+            if ((is_arrow(exp) && !exp.value || exp instanceof AST_AsyncFunction || exp instanceof AST_Function)
                 && !(exp.name && (def = exp.name.definition()).references.length > def.replaced)) {
                 exp.process_expression(false, function(node) {
                     var value = node.value && node.value.drop_side_effect_free(compressor, true);
index 6d9f89d..57d8d39 100644 (file)
@@ -434,6 +434,46 @@ collapse_value: {
     node_version: ">=4"
 }
 
+collapse_property_lambda: {
+    options = {
+        collapse_vars: true,
+        pure_getters: "strict",
+    }
+    input: {
+        console.log(function f() {
+            f.g = () => 42;
+            return f.g();
+        }());
+    }
+    expect: {
+        console.log(function f() {
+            return (f.g = () => 42)();
+        }());
+    }
+    expect_stdout: "42"
+    node_version: ">=4"
+}
+
+drop_return: {
+    options = {
+        side_effects: true,
+    }
+    input: {
+        (a => {
+            while (!console);
+            return console.log(a);
+        })(42);
+    }
+    expect: {
+        (a => {
+            while (!console);
+            console.log(a);
+        })(42);
+    }
+    expect_stdout: "42"
+    node_version: ">=4"
+}
+
 reduce_iife_1: {
     options = {
         evaluate: true,
index c70635d..18012b4 100644 (file)
@@ -519,6 +519,160 @@ collapse_vars_3: {
     node_version: ">=8"
 }
 
+collapse_property_lambda: {
+    options = {
+        collapse_vars: true,
+        pure_getters: "strict",
+    }
+    input: {
+        (async function f() {
+            f.g = () => 42;
+            return f.g();
+        })().then(console.log);
+    }
+    expect: {
+        (async function f() {
+            return (f.g = () => 42)();
+        })().then(console.log);
+    }
+    expect_stdout: "42"
+    node_version: ">=8"
+}
+
+drop_return: {
+    options = {
+        side_effects: true,
+    }
+    input: {
+        (async function(a) {
+            while (!console);
+            return console.log(a);
+        })(42);
+    }
+    expect: {
+        (async function(a) {
+            while (!console);
+            console.log(a);
+        })(42);
+    }
+    expect_stdout: "42"
+    node_version: ">=8"
+}
+
+functions: {
+    options = {
+        functions: true,
+        reduce_vars: true,
+        unused: true,
+    }
+    input: {
+        !async function() {
+            var a = async function a() {
+                return a && "a";
+            };
+            var b = async function x() {
+                return !!x;
+            };
+            var c = async function(c) {
+                return c;
+            };
+            if (await c(await b(await a()))) {
+                var d = async function() {};
+                var e = async function y() {
+                    return typeof y;
+                };
+                var f = async function(f) {
+                    return f;
+                };
+                console.log(await a(await d()), await b(await e()), await c(await f(42)), typeof d, await e(), typeof f);
+            }
+        }();
+    }
+    expect: {
+        !async function() {
+            async function a() {
+                return a && "a";
+            }
+            async function b() {
+                return !!b;
+            }
+            var c = async function(c) {
+                return c;
+            };
+            if (await c(await b(await a()))) {
+                async function d() {}
+                async function e() {
+                    return typeof e;
+                }
+                var f = async function(f) {
+                    return f;
+                };
+                console.log(await a(await d()), await b(await e()), await c(await f(42)), typeof d, await e(), typeof f);
+            }
+        }();
+    }
+    expect_stdout: "a true 42 function function function"
+    node_version: ">=8"
+}
+
+functions_use_strict: {
+    options = {
+        functions: true,
+        reduce_vars: true,
+        unused: true,
+    }
+    input: {
+        "use strict";
+        !async function() {
+            var a = async function a() {
+                return a && "a";
+            };
+            var b = async function x() {
+                return !!x;
+            };
+            var c = async function(c) {
+                return c;
+            };
+            if (await c(await b(await a()))) {
+                var d = async function() {};
+                var e = async function y() {
+                    return typeof y;
+                };
+                var f = async function(f) {
+                    return f;
+                };
+                console.log(await a(await d()), await b(await e()), await c(await f(42)), typeof d, await e(), typeof f);
+            }
+        }();
+    }
+    expect: {
+        "use strict";
+        !async function() {
+            async function a() {
+                return a && "a";
+            }
+            async function b() {
+                return !!b;
+            }
+            var c = async function(c) {
+                return c;
+            };
+            if (await c(await b(await a()))) {
+                var d = async function() {};
+                var e = async function y() {
+                    return typeof y;
+                };
+                var f = async function(f) {
+                    return f;
+                };
+                console.log(await a(await d()), await b(await e()), await c(await f(42)), typeof d, await e(), typeof f);
+            }
+        }();
+    }
+    expect_stdout: "a true 42 function function function"
+    node_version: ">=8"
+}
+
 issue_4335_1: {
     options = {
         inline: true,
index 2b1bbc0..f579ee7 100644 (file)
@@ -703,6 +703,7 @@ prototype_function: {
         var g = 0();
         var h = 0();
     }
+    expect_stdout: true
 }
 
 call_args: {
@@ -2800,7 +2801,7 @@ operator_in: {
         console.log("PASS" in { });
         console.log("FAIL" in { });
         console.log("toString" in { });
-        console.log(true);
+        console.log("toString" in { toString: 3 });
     }
     expect_stdout: [
         "true",
index 5892041..6adc616 100644 (file)
@@ -248,6 +248,35 @@ issue_2110_2: {
     expect_stdout: "function"
 }
 
+issue_2110_3: {
+    options = {
+        collapse_vars: true,
+        pure_getters: "strict",
+        reduce_vars: true,
+    }
+    input: {
+        function g() {
+            return this;
+        }
+        console.log(typeof function() {
+            function f() {}
+            f.g = g;
+            return f.g();
+        }());
+    }
+    expect: {
+        function g() {
+            return this;
+        }
+        console.log(typeof function() {
+            function f() {}
+            f.g = g;
+            return f.g();
+        }());
+    }
+    expect_stdout: "function"
+}
+
 set_immutable_1: {
     options = {
         collapse_vars: true,