improve `class` compatibility in `side_effects` (#5279)
authorAlex Lam S.L <alexlamsl@gmail.com>
Sun, 9 Jan 2022 13:15:42 +0000 (13:15 +0000)
committerGitHub <noreply@github.com>
Sun, 9 Jan 2022 13:15:42 +0000 (21:15 +0800)
lib/compress.js
test/compress/classes.js
test/ufuzz/index.js

index 24d0d04..5cf1606 100644 (file)
@@ -8290,17 +8290,26 @@ Compressor.prototype.compress = function(node) {
                 if (!base && !values) return null;
                 exprs = [];
             }
-            if (base) {
+            if (base || !compressor.has_directive("use strict")) {
                 var node = to_class_expr(self, true);
+                if (!base) node.extends = null;
                 node.properties = [];
-                if (exprs.length) node.properties.push(make_node(AST_ClassMethod, self, {
-                    key: make_sequence(self, exprs),
-                    value: make_node(AST_Function, self, {
-                        argnames: [],
-                        body: [],
-                    }).init_vars(node),
-                }));
-                exprs = [ node ];
+                if (values) {
+                    node.properties.push(make_node(AST_ClassField, self, {
+                        static: true,
+                        key: exprs.length ? make_sequence(self, exprs) : "c",
+                        value: make_sequence(self, values),
+                    }));
+                } else if (exprs.length) {
+                    node.properties.push(make_node(AST_ClassMethod, self, {
+                        key: make_sequence(self, exprs),
+                        value: make_node(AST_Function, self, {
+                            argnames: [],
+                            body: [],
+                        }).init_vars(node),
+                    }));
+                }
+                return node;
             }
             if (values) exprs.push(make_node(AST_Call, self, {
                 expression: make_node(AST_Arrow, self, {
index bad695f..c55b41f 100644 (file)
@@ -434,6 +434,33 @@ static_side_effects: {
         console.log(a);
     }
     expect: {
+        var a = "FAIL 1";
+        (class {
+            static c = a = "PASS";
+        });
+        console.log(a);
+    }
+    expect_stdout: "PASS"
+    node_version: ">=12"
+}
+
+static_side_effects_strict: {
+    options = {
+        inline: true,
+        toplevel: true,
+        unused: true,
+    }
+    input: {
+        "use strict";
+        var a = "FAIL 1";
+        class A {
+            static p = a = "PASS";
+            q = a = "FAIL 2";
+        }
+        console.log(a);
+    }
+    expect: {
+        "use strict";
         var a = "FAIL 1";
         a = "PASS";
         console.log(a);
@@ -807,6 +834,33 @@ unused_await: {
         })();
     }
     expect: {
+        var await = "PASS";
+        (async function() {
+            (class {
+                static c = console.log(await);
+            });
+        })();
+    }
+    expect_stdout: true
+    node_version: ">=12 <16"
+}
+
+unused_await_strict: {
+    options = {
+        inline: true,
+        unused: true,
+    }
+    input: {
+        "use strict";
+        var await = "PASS";
+        (async function() {
+            class A {
+                static p = console.log(await);
+            }
+        })();
+    }
+    expect: {
+        "use strict";
         var await = "PASS";
         (async function() {
             (() => console.log(await))();
@@ -1149,6 +1203,31 @@ issue_4705: {
         }
     }
     expect: {
+        (class {
+            [console.log("PASS")]() {}
+        });
+    }
+    expect_stdout: "PASS"
+    node_version: ">=12"
+}
+
+issue_4705_strict: {
+    options = {
+        evaluate: true,
+        reduce_vars: true,
+        toplevel: true,
+        unused: true,
+    }
+    input: {
+        "use strict";
+        var a = "PASS";
+        class A {
+            p = a = "FAIL";
+            [console.log(a)];
+        }
+    }
+    expect: {
+        "use strict";
         console.log("PASS");
     }
     expect_stdout: "PASS"
@@ -1371,9 +1450,40 @@ issue_4756: {
     expect: {
         try {
             (class extends 42 {
-                [console.log("foo")]() {}
-            }),
-            (() => console.log("bar"))();
+                static [console.log("foo")] = console.log("bar");
+            });
+        } catch (e) {
+            console.log("baz");
+        }
+    }
+    expect_stdout: [
+        "foo",
+        "baz",
+    ]
+    node_version: ">=12"
+}
+
+issue_4756_strict: {
+    options = {
+        toplevel: true,
+        unused: true,
+    }
+    input: {
+        "use strict";
+        try {
+            class A extends 42 {
+                static [console.log("foo")] = console.log("bar");
+            }
+        } catch (e) {
+            console.log("baz");
+        }
+    }
+    expect: {
+        "use strict";
+        try {
+            (class extends 42 {
+                static [console.log("foo")] = console.log("bar");
+            });
         } catch (e) {
             console.log("baz");
         }
@@ -1440,7 +1550,7 @@ issue_4829_1: {
     input: {
         "use strict";
         try {
-            class A extends { f(){} }.f {}
+            class A extends { f() {} }.f {}
         } catch (e) {
             console.log("PASS");
         }
@@ -1646,6 +1756,37 @@ issue_4962_1: {
         })(function g() {});
     }
     expect: {
+        (function g() {}),
+        void class {
+            static c = function() {
+                while (console.log(typeof g));
+            }();
+        };
+    }
+    expect_stdout: "undefined"
+    node_version: ">=12"
+}
+
+issue_4962_1_strict: {
+    options = {
+        ie: true,
+        inline: true,
+        reduce_vars: true,
+        unused: true,
+    }
+    input: {
+        "use strict";
+        (function() {
+            function f() {
+                while (console.log(typeof g));
+            }
+            class A {
+                static p = f();
+            }
+        })(function g() {});
+    }
+    expect: {
+        "use strict";
         (function g() {});
         while (console.log(typeof g));
     }
@@ -1671,6 +1812,36 @@ issue_4962_2: {
         }, typeof g));
     }
     expect: {
+        console.log(function f() {}(function g() {
+            (class {
+                static c = f;
+            });
+        }));
+    }
+    expect_stdout: "undefined"
+    node_version: ">=12"
+}
+
+issue_4962_2_strict: {
+    options = {
+        ie: true,
+        inline: true,
+        reduce_vars: true,
+        unused: true,
+    }
+    input: {
+        "use strict";
+        console.log(function f() {}(function g() {
+            function h() {
+                f;
+            }
+            class A {
+                static p = h();
+            }
+        }, typeof g));
+    }
+    expect: {
+        "use strict";
         console.log(function f() {}(function g() {
             f;
         }));
@@ -2026,6 +2197,40 @@ issue_5082_1: {
         })();
     }
     expect: {
+        (function() {
+            class A {
+                p = console.log("PASS");
+                q() {}
+            }
+            (class {
+                static c = new A();
+            });
+        })();
+    }
+    expect_stdout: "PASS"
+    node_version: ">=12"
+}
+
+issue_5082_1_strict: {
+    options = {
+        inline: true,
+        reduce_vars: true,
+        unused: true,
+    }
+    input: {
+        "use strict";
+        (function() {
+            class A {
+                p = console.log("PASS");
+                q() {}
+            }
+            class B {
+                static P = new A();
+            }
+        })();
+    }
+    expect: {
+        "use strict";
         (function() {
             class A {
                 p = console.log("PASS");
@@ -2057,6 +2262,41 @@ issue_5082_2: {
         })();
     }
     expect: {
+        (function() {
+            class A {
+                p = console.log("PASS");
+                q() {}
+            }
+            (class {
+                static c = new A();
+            });
+        })();
+    }
+    expect_stdout: "PASS"
+    node_version: ">=12"
+}
+
+issue_5082_2_static: {
+    options = {
+        inline: true,
+        passes: 2,
+        reduce_vars: true,
+        unused: true,
+    }
+    input: {
+        "use strict";
+        (function() {
+            class A {
+                p = console.log("PASS");
+                q() {}
+            }
+            class B {
+                static P = new A();
+            }
+        })();
+    }
+    expect: {
+        "use strict";
         void new class {
             p = console.log("PASS");
             q() {}
index 8747418..d58c196 100644 (file)
@@ -2501,7 +2501,7 @@ for (var round = 1; round <= num_iterations; round++) {
                 }
             }
             // ignore declaration order of global variables
-            if (!ok && !toplevel) {
+            if (!ok && !toplevel && uglify_result.name != "SyntaxError" && original_result.name != "SyntaxError") {
                 ok = sandbox.same_stdout(run_code(sort_globals(original_code)), run_code(sort_globals(uglify_code)));
             }
             // ignore numerical imprecision caused by `unsafe_math`
@@ -2519,14 +2519,8 @@ for (var round = 1; round <= num_iterations; round++) {
             // ignore difference in error message caused by Temporal Dead Zone
             if (!ok && errored && uglify_result.name == "ReferenceError" && original_result.name == "ReferenceError") ok = true;
             // ignore difference due to implicit strict-mode in `class`
-            if (!ok && /\bclass\b/.test(original_code)) {
-                var original_strict = run_code('"use strict";\n' + original_code, toplevel);
-                var uglify_strict = run_code('"use strict";\n' + uglify_code, toplevel);
-                if (typeof original_strict != "string") {
-                    ok = typeof uglify_strict != "string";
-                } else {
-                    ok = sandbox.same_stdout(original_strict, uglify_strict);
-                }
+            if (!ok && uglify_result.name == "SyntaxError" && /\bclass\b/.test(original_code)) {
+                ok = typeof run_code('"use strict";\n' + original_code, toplevel) != "string";
             }
             // ignore difference in error message caused by `import` symbol redeclaration
             if (!ok && errored && /\bimport\b/.test(original_code)) {