fix corner case in `if_return` (#4851)
authorAlex Lam S.L <alexlamsl@gmail.com>
Thu, 8 Apr 2021 00:57:59 +0000 (01:57 +0100)
committerGitHub <noreply@github.com>
Thu, 8 Apr 2021 00:57:59 +0000 (08:57 +0800)
fixes #4848

lib/compress.js
lib/scope.js
test/compress/classes.js
test/compress/const.js
test/compress/let.js

index 437baab..21eec7c 100644 (file)
@@ -3054,7 +3054,7 @@ merge(Compressor.prototype, {
                 });
             }
 
-            function can_merge_flow(ab) {
+            function can_drop_abort(ab) {
                 if (ab instanceof AST_Return) return in_lambda && is_return_void(ab.value);
                 if (!(ab instanceof AST_LoopControl)) return false;
                 var lct = compressor.loopcontrol_target(ab);
@@ -3063,16 +3063,35 @@ merge(Compressor.prototype, {
                 return match_target(lct);
             }
 
+            function can_merge_flow(ab) {
+                if (!can_drop_abort(ab)) return false;
+                for (var j = statements.length; --j > i;) {
+                    var stat = statements[j];
+                    if (stat instanceof AST_DefClass) {
+                        if (stat.name.definition().preinit) return false;
+                    } else if (stat instanceof AST_Const || stat instanceof AST_Let) {
+                        if (!all(stat.definitions, function(defn) {
+                            return !defn.name.match_symbol(function(node) {
+                                return node instanceof AST_SymbolDeclaration && node.definition().preinit;
+                            });
+                        })) return false;
+                    }
+                }
+                return true;
+            }
+
             function extract_functions() {
                 var defuns = [];
+                var lexical = false;
                 var tail = statements.splice(i + 1).filter(function(stat) {
                     if (stat instanceof AST_LambdaDefinition) {
                         defuns.push(stat);
                         return false;
                     }
+                    if (is_lexical_definition(stat)) lexical = true;
                     return true;
                 });
-                [].push.apply(all(tail, safe_to_trim) ? statements : tail, defuns);
+                [].push.apply(lexical ? tail : statements, defuns);
                 return tail;
             }
 
index 9d4b890..f0d4c92 100644 (file)
@@ -273,16 +273,18 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
             return true;
         }
         if (node instanceof AST_SymbolDeclaration) {
+            var def = node.definition();
+            def.preinit = def.references.length;
             if (node instanceof AST_SymbolCatch) {
                 // ensure mangling works if `catch` reuses a scope variable
-                var def = node.definition().redefined();
-                if (def) for (var s = node.scope; s; s = s.parent_scope) {
-                    push_uniq(s.enclosed, def);
-                    if (s === def.scope) break;
+                var redef = def.redefined();
+                if (redef) for (var s = node.scope; s; s = s.parent_scope) {
+                    push_uniq(s.enclosed, redef);
+                    if (s === redef.scope) break;
                 }
             } else if (node instanceof AST_SymbolConst) {
                 // ensure compression works if `const` reuses a scope variable
-                var redef = node.definition().redefined();
+                var redef = def.redefined();
                 if (redef) redef.const_redefs = true;
             }
             if (node.name != "arguments") return true;
index fe8c7e3..badcb2e 100644 (file)
@@ -1493,3 +1493,51 @@ mangle_properties: {
     expect_stdout: "PASS 42"
     node_version: ">=14.6"
 }
+
+issue_4848: {
+    options = {
+        if_return: true,
+    }
+    input: {
+        "use strict";
+        function f(a) {
+            a(function() {
+                new A();
+            });
+            if (!console)
+                return;
+            class A {
+                constructor() {
+                    console.log("PASS");
+                }
+            }
+        }
+        var g;
+        f(function(h) {
+            g = h;
+        });
+        g();
+    }
+    expect: {
+        "use strict";
+        function f(a) {
+            a(function() {
+                new A();
+            });
+            if (!console)
+                return;
+            class A {
+                constructor() {
+                    console.log("PASS");
+                }
+            }
+        }
+        var g;
+        f(function(h) {
+            g = h;
+        });
+        g();
+    }
+    expect_stdout: "PASS"
+    node_version: ">=4"
+}
index 4306fff..fce6ebe 100644 (file)
@@ -1498,3 +1498,40 @@ issue_4691: {
     }
     expect_stdout: "PASS"
 }
+
+issue_4848: {
+    options = {
+        if_return: true,
+    }
+    input: {
+        function f(a) {
+            a(function() {
+                console.log(b);
+            });
+            if (!console)
+                return;
+            const b = "PASS";
+        }
+        var g;
+        f(function(h) {
+            g = h;
+        });
+        g();
+    }
+    expect: {
+        function f(a) {
+            a(function() {
+                console.log(b);
+            });
+            if (!console)
+                return;
+            const b = "PASS";
+        }
+        var g;
+        f(function(h) {
+            g = h;
+        });
+        g();
+    }
+    expect_stdout: "PASS"
+}
index 90d9952..c59308c 100644 (file)
@@ -1506,3 +1506,43 @@ issue_4691: {
     expect_stdout: "PASS"
     node_version: ">=4"
 }
+
+issue_4848: {
+    options = {
+        if_return: true,
+    }
+    input: {
+        "use strict";
+        function f(a) {
+            a(function() {
+                console.log(b);
+            });
+            if (!console)
+                return;
+            let b = "PASS";
+        }
+        var g;
+        f(function(h) {
+            g = h;
+        });
+        g();
+    }
+    expect: {
+        "use strict";
+        function f(a) {
+            a(function() {
+                console.log(b);
+            });
+            if (!console)
+                return;
+            let b = "PASS";
+        }
+        var g;
+        f(function(h) {
+            g = h;
+        });
+        g();
+    }
+    expect_stdout: "PASS"
+    node_version: ">=4"
+}