From bc6e105174eb67547c2bd988899e4c4f2d8f6ada Mon Sep 17 00:00:00 2001 From: "Alex Lam S.L" Date: Tue, 6 Oct 2020 02:20:41 +0100 Subject: [PATCH] fix corner case in `ie8` (#4187) fixes #4186 --- lib/ast.js | 3 --- lib/compress.js | 23 +++++++++++++---- test/compress/functions.js | 51 ++++++++++++++++++++++++++++++++++++++ test/compress/ie8.js | 40 ++++++++++++++++++++++++++++++ test/reduce.js | 49 +++++++++++++++--------------------- 5 files changed, 129 insertions(+), 37 deletions(-) diff --git a/lib/ast.js b/lib/ast.js index 08b4b65c..ac779cb9 100644 --- a/lib/ast.js +++ b/lib/ast.js @@ -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, { diff --git a/lib/compress.js b/lib/compress.js index 8c28d450..29cc82a9 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -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, { diff --git a/test/compress/functions.js b/test/compress/functions.js index 3abfb30f..4e65b128 100644 --- a/test/compress/functions.js +++ b/test/compress/functions.js @@ -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" +} diff --git a/test/compress/ie8.js b/test/compress/ie8.js index 4d74d44e..f2132579 100644 --- a/test/compress/ie8.js +++ b/test/compress/ie8.js @@ -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" +} diff --git a/test/reduce.js b/test/reduce.js index 4ca88eff..f1d2b448 100644 --- a/test/reduce.js +++ b/test/reduce.js @@ -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) { -- 2.34.1