From 835d130ccf526b0347846857143158d25c1dbde4 Mon Sep 17 00:00:00 2001 From: "Alex Lam S.L" Date: Sun, 26 Dec 2021 08:39:06 +0800 Subject: [PATCH] fix corner cases in `inline` (#5241) fixes #5239 fixes #5240 --- lib/compress.js | 30 ++++++++--- test/compress/functions.js | 102 +++++++++++++++++++++++++++++++++++++ test/compress/let.js | 45 ++++++++++++++++ 3 files changed, 169 insertions(+), 8 deletions(-) diff --git a/lib/compress.js b/lib/compress.js index da9034f2..22cbdd19 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -1840,7 +1840,7 @@ Compressor.prototype.compress = function(node) { var in_lambda = last_of(compressor, function(node) { return node instanceof AST_Lambda; }); - var in_loop, in_try, scope; + var block_scope, in_loop, in_try, scope; find_loop_scope_try(); var changed, last_changed, max_iter = 10; do { @@ -1890,6 +1890,7 @@ Compressor.prototype.compress = function(node) { function find_loop_scope_try() { var node = compressor.self(), level = 0; do { + if (!block_scope && node.variables) block_scope = node; if (node instanceof AST_Catch) { if (compressor.parent(level).bfinally) { if (!in_try) in_try = {}; @@ -3488,7 +3489,7 @@ Compressor.prototype.compress = function(node) { var inlined = make_node(AST_UnaryPrefix, stat, { operator: "void", expression: body, - }).try_inline(compressor, scope); + }).try_inline(compressor, block_scope); if (!inlined) return false; statements[index] = inlined; return true; @@ -12777,9 +12778,6 @@ Compressor.prototype.compress = function(node) { (function(def) { def(AST_Node, noop); - function process(sym, argname) { - argname.definition().orig.push(sym); - } def(AST_Call, function(compressor, scope) { if (compressor.option("inline") < 4) return; var call = this; @@ -12789,10 +12787,17 @@ Compressor.prototype.compress = function(node) { if (fn.name) return; if (fn.uses_arguments) return; if (fn.contains_this()) return; - if (!scope) scope = compressor.find_parent(AST_Scope); + if (!scope) scope = find_scope(compressor); + var defined = new Dictionary(); + while (!(scope instanceof AST_Scope)) { + scope.variables.each(function(def) { + defined.set(def.name, true); + }); + scope = scope.parent_scope; + } var names = scope.var_names(); if (!fn.variables.all(function(def, name) { - if (!names.has(name)) return true; + if (!defined.has(name) && !names.has(name)) return true; if (name != "arguments") return false; if (scope.uses_arguments) return false; return def.references.length == def.replaced; @@ -12819,7 +12824,7 @@ Compressor.prototype.compress = function(node) { right: make_node(AST_Number, node, { value: 0 }), }); })); - var body = []; + var body = [], defs = Object.create(null), syms = new Dictionary(); if (fn.rest || !all(fn.argnames, function(argname) { return argname instanceof AST_SymbolFunarg; }) || !all(call.args, function(arg) { @@ -12856,9 +12861,18 @@ Compressor.prototype.compress = function(node) { body: make_sequence(call, values), })); } + syms.each(function(orig, id) { + [].unshift.apply(defs[id].orig, orig); + }); return make_node(AST_BlockStatement, call, { body: body.concat(fn.body, make_node(AST_Return, call, { value: null })), }); + + function process(sym, argname) { + var def = argname.definition(); + defs[def.id] = def; + syms.add(def.id, sym); + } }); def(AST_New, noop); def(AST_Sequence, function(compressor, scope) { diff --git a/test/compress/functions.js b/test/compress/functions.js index c31d2823..002db1b3 100644 --- a/test/compress/functions.js +++ b/test/compress/functions.js @@ -7135,3 +7135,105 @@ issue_5237: { "undefined", ] } + +issue_5239: { + options = { + functions: true, + inline: true, + reduce_vars: true, + unused: true, + } + input: { + (function() { + (function(f) { + var a = 42, f = function() {}; + while (console.log(f.p || a++)); + })(); + })(); + } + expect: { + (function() { + var f = void 0; + var a = 42, f = function() {}; + while (console.log(f.p || a++)); + return; + })(); + } + expect_stdout: "42" +} + +issue_5240_1: { + options = { + inline: true, + } + input: { + function f() { + try { + throw "FAIL 1"; + } catch (e) { + return function() { + if (console) { + console.log(e); + var e = "FAIL 2"; + } + }(); + } + } + f(); + } + expect: { + function f() { + try { + throw "FAIL 1"; + } catch (e) { + return function() { + if (console) { + console.log(e); + var e = "FAIL 2"; + } + }(); + } + } + f(); + } + expect_stdout: "undefined" +} + +issue_5240_2: { + options = { + inline: true, + } + input: { + function f() { + try { + throw "FAIL 1"; + } catch (e) { + { + return function() { + if (console) { + console.log(e); + var e = "FAIL 2"; + } + }(); + } + } + } + f(); + } + expect: { + function f() { + try { + throw "FAIL 1"; + } catch (e) { + return function() { + if (console) { + console.log(e); + var e = "FAIL 2"; + } + }(); + } + } + f(); + } + expect_stdout: "undefined" +} diff --git a/test/compress/let.js b/test/compress/let.js index cdf54fcb..629119e7 100644 --- a/test/compress/let.js +++ b/test/compress/let.js @@ -1747,3 +1747,48 @@ issue_4985: { expect_stdout: "undefined" node_version: ">=4" } + +issue_5240: { + options = { + inline: true, + } + input: { + "use strict"; + function f() { + if (console) { + let g = function() { + e; + }, e; + (function() { + if (console) { + console.log(e); + var e = "FAIL"; + } + })(console.log(e)); + } + } + f(); + } + expect: { + "use strict"; + function f() { + if (console) { + let g = function() { + e; + }, e; + (function() { + if (console) { + console.log(e); + var e = "FAIL"; + } + })(console.log(e)); + } + } + f(); + } + expect_stdout: [ + "undefined", + "undefined", + ] + node_version: ">=4" +}