fix corner case in `ie8` (#4187)
authorAlex Lam S.L <alexlamsl@gmail.com>
Tue, 6 Oct 2020 01:20:41 +0000 (02:20 +0100)
committerGitHub <noreply@github.com>
Tue, 6 Oct 2020 01:20:41 +0000 (09:20 +0800)
fixes #4186

lib/ast.js
lib/compress.js
test/compress/functions.js
test/compress/ie8.js
test/reduce.js

index 08b4b65..ac779cb 100644 (file)
@@ -282,9 +282,6 @@ var AST_BlockScope = DEFNODE("BlockScope", "cname enclosed functions make_def pa
 
 var AST_BlockStatement = DEFNODE("BlockStatement", null, {
     $documentation: "A block statement",
-    initialize: function() {
-        this.variables = new Dictionary();
-    },
 }, AST_BlockScope);
 
 var AST_EmptyStatement = DEFNODE("EmptyStatement", null, {
index 8c28d45..29cc82a 100644 (file)
@@ -1018,6 +1018,13 @@ merge(Compressor.prototype, {
         return sym instanceof AST_SymbolLambda && def.scope.name === sym;
     });
 
+    function find_scope(compressor) {
+        var level = 0, node;
+        while (node = compressor.parent(level++)) {
+            if (node.variables) return node;
+        }
+    }
+
     function is_lhs_read_only(lhs, compressor) {
         if (lhs instanceof AST_This) return true;
         if (lhs instanceof AST_SymbolRef) {
@@ -6885,7 +6892,7 @@ merge(Compressor.prototype, {
                 && !fn.pinned()
                 && !(fn.name && fn instanceof AST_Function)
                 && (exp === fn || !recursive_ref(compressor, def = exp.definition())
-                    && fn.is_constant_expression(compressor.find_parent(AST_BlockScope)))
+                    && fn.is_constant_expression(find_scope(compressor)))
                 && (value = can_flatten_body(stat))
                 && !fn.contains_this()) {
                 var replacing = exp === fn || compressor.option("unused") && def.references.length - def.replaced == 1;
@@ -8303,9 +8310,16 @@ merge(Compressor.prototype, {
         return lhs instanceof AST_SymbolRef || lhs.TYPE === self.TYPE;
     }
 
+    function find_variable(compressor, name) {
+        var level = 0, node;
+        while (node = compressor.parent(level++)) {
+            if (node.variables) return node.find_variable(name);
+        }
+    }
+
     OPT(AST_Undefined, function(self, compressor) {
         if (compressor.option("unsafe_undefined")) {
-            var undef = compressor.find_parent(AST_BlockScope).find_variable("undefined");
+            var undef = find_scope(compressor).find_variable("undefined");
             if (undef) {
                 var ref = make_node(AST_SymbolRef, self, {
                     name   : "undefined",
@@ -8331,7 +8345,7 @@ merge(Compressor.prototype, {
         if (lhs && is_atomic(lhs, self)) return self;
         if (compressor.option("keep_infinity")
             && !(lhs && !is_atomic(lhs, self))
-            && !compressor.find_parent(AST_BlockScope).find_variable("Infinity"))
+            && !find_scope(compressor).find_variable("Infinity"))
             return self;
         return make_node(AST_Binary, self, {
             operator: "/",
@@ -8346,8 +8360,7 @@ merge(Compressor.prototype, {
 
     OPT(AST_NaN, function(self, compressor) {
         var lhs = is_lhs(compressor.self(), compressor.parent());
-        if (lhs && !is_atomic(lhs, self)
-            || compressor.find_parent(AST_BlockScope).find_variable("NaN")) {
+        if (lhs && !is_atomic(lhs, self) || find_scope(compressor).find_variable("NaN")) {
             return make_node(AST_Binary, self, {
                 operator: "/",
                 left: make_node(AST_Number, self, {
index 3abfb30..4e65b12 100644 (file)
@@ -5025,3 +5025,54 @@ catch_no_argname: {
     ]
     node_version: ">=10"
 }
+
+issue_4186: {
+    options = {
+        conditionals: true,
+        inline: true,
+        reduce_funcs: true,
+        reduce_vars: true,
+        sequences: true,
+        unused: true,
+    }
+    input: {
+        console.log(typeof function() {
+            return function() {
+                function f() {
+                    if (1)
+                        g();
+                    else
+                        (function() {
+                            return f;
+                        });
+                }
+                return f;
+                function g() {
+                    if (1) {
+                        if (0)
+                            h;
+                        else
+                            h();
+                        var key = 0;
+                    }
+                }
+                function h() {
+                    return factory;
+                }
+            };
+        }()());
+    }
+    expect: {
+        console.log(typeof function() {
+            return function f() {
+                1 ? void (1 && (0 ? h : h(), 0)) : function() {
+                    return f;
+                };
+            };
+            function h() {
+                return factory;
+            }
+        }());
+    }
+    expect_stdout: "function"
+}
index 4d74d44..f213257 100644 (file)
@@ -2819,3 +2819,43 @@ direct_inline_catch_redefined: {
     }
     expect_stdout: true
 }
+
+issue_4186: {
+    options = {
+        dead_code: true,
+        evaluate: true,
+        ie8: true,
+        reduce_vars: true,
+        toplevel: true,
+        unused: true,
+    }
+    mangle = {
+        ie8: true,
+        toplevel: true,
+    }
+    input: {
+        function f() {
+            (function NaN() {
+                var a = 1;
+                while (a--)
+                    try {} finally {
+                        console.log(0/0);
+                        var b;
+                    }
+            })(f);
+        }
+        f();
+        NaN;
+    }
+    expect: {
+        (function() {
+            (function NaN() {
+                var n = 1;
+                while (n--)
+                    console.log(0/0);
+            })();
+        })();
+        NaN;
+    }
+    expect_stdout: "NaN"
+}
index 4ca88ef..f1d2b44 100644 (file)
@@ -499,7 +499,26 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
                 log("// reduce test pass " + pass + ": " + testcase.length + " bytes");
             }
         }
-        testcase = try_beautify(testcase, minify_options, differs.unminified_result, result_cache, max_timeout);
+        var beautified = U.minify(testcase, {
+            compress: false,
+            mangle: false,
+            output: {
+                beautify: true,
+                braces: true,
+                comments: true,
+            },
+        });
+        testcase = {
+            code: testcase,
+        };
+        if (!beautified.error) {
+            diff = test_for_diff(beautified.code, minify_options, result_cache, max_timeout);
+            if (diff && !diff.timed_out && !diff.error) {
+                testcase = beautified;
+                testcase.code = "// (beautified)\n" + testcase.code;
+                differs = diff;
+            }
+        }
         var lines = [ "" ];
         if (isNaN(max_timeout)) {
             lines.push("// minify error: " + to_comment(strip_color_codes(differs.minified_result.stack)));
@@ -538,34 +557,6 @@ function trim_trailing_whitespace(value) {
     return ("" + value).replace(/\s+$/, "");
 }
 
-function try_beautify(testcase, minify_options, expected, result_cache, timeout) {
-    var result = U.minify(testcase, {
-        compress: false,
-        mangle: false,
-        output: {
-            beautify: true,
-            braces: true,
-            comments: true,
-        },
-    });
-    if (result.error) return {
-        code: testcase,
-    };
-    var toplevel = sandbox.has_toplevel(minify_options);
-    if (isNaN(timeout)) {
-        if (!U.minify(result.code, minify_options).error) return {
-            code: testcase,
-        };
-    } else {
-        var actual = run_code(result.code, toplevel, result_cache, timeout).result;
-        if (!sandbox.same_stdout(expected, actual)) return {
-            code: testcase,
-        };
-    }
-    result.code = "// (beautified)\n" + result.code;
-    return result;
-}
-
 function has_exit(fn) {
     var found = false;
     var tw = new U.TreeWalker(function(node) {