From 7889192cae3dbbf6b19d69df693a96660eea14a9 Mon Sep 17 00:00:00 2001 From: "Alex Lam S.L" Date: Sun, 2 Jan 2022 13:24:41 +0000 Subject: [PATCH] fix corner cases in `inline` (#5255) fixes #5254 --- lib/compress.js | 42 +++++++----- test/compress/const.js | 25 ++++++++ test/compress/functions.js | 127 ++++++++++++++++++++++++++++++++++++- test/compress/let.js | 28 ++++++++ 4 files changed, 204 insertions(+), 18 deletions(-) diff --git a/lib/compress.js b/lib/compress.js index 2e38368c..5997a4ba 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -10317,7 +10317,7 @@ Compressor.prototype.compress = function(node) { function flatten_vars(decls, expressions) { var args = [ insert, 0 ]; - var decl_var = [], expr_var = [], expr_loop = [], exprs = []; + var decl_var = [], expr_fn = [], expr_var = [], expr_loop = [], exprs = []; fn.body.filter(in_loop ? function(stat) { if (!(stat instanceof AST_LambdaDefinition)) return true; var name = make_node(AST_SymbolVar, stat.name, flatten_var(stat.name)); @@ -10325,7 +10325,7 @@ Compressor.prototype.compress = function(node) { def.fixed = false; def.orig.push(name); def.eliminated++; - append_var(decls, expressions, name, to_func_expr(stat, true)); + append_var(decls, expr_fn, name, to_func_expr(stat, true)); return false; } : function(stat) { if (!(stat instanceof AST_LambdaDefinition)) return true; @@ -10351,20 +10351,23 @@ Compressor.prototype.compress = function(node) { exprs = []; } append_var(decl_var, expr_var, name, value); - if (in_loop && !arg_used.has(name.name) && !fn.functions.has(name.name)) { - var def = fn.variables.get(name.name); - var sym = make_node(AST_SymbolRef, name, name); - def.references.push(sym); - expr_loop.push(make_node(AST_Assign, var_def, { - operator: "=", - left: sym, - right: make_node(AST_Undefined, name), - })); - } + if (!in_loop) continue; + if (arg_used.has(name.name)) continue; + var def = fn.variables.get(name.name); + if (fn.functions.has(name.name) && def.orig.length == 1) continue; + var def = fn.variables.get(name.name); + var sym = make_node(AST_SymbolRef, name, name); + def.references.push(sym); + expr_loop.push(make_node(AST_Assign, var_def, { + operator: "=", + left: sym, + right: make_node(AST_Undefined, name), + })); } }); [].push.apply(decls, decl_var); [].push.apply(expressions, expr_loop); + [].push.apply(expressions, expr_fn); [].push.apply(expressions, expr_var); return args; } @@ -12986,12 +12989,17 @@ Compressor.prototype.compress = function(node) { scope.enclosed.push(def); scope.variables.set(name, def); def.single_use = false; - if (!in_loop || fn.functions.has(name)) return; + if (!in_loop) return; + if (fn.functions.has(name) && def.orig.length == 1) return; if (def.references.length == def.replaced) return; - var sym = flatten_var(def.orig[0]); - if (sym.TYPE != "SymbolVar") return; - var ref = make_node(AST_SymbolRef, sym, sym); - sym.definition().references.push(ref); + if (!all(def.orig, function(sym) { + return !(sym instanceof AST_SymbolConst + || sym instanceof AST_SymbolFunarg + || sym instanceof AST_SymbolLet); + })) return; + var sym = def.orig[0]; + var ref = make_node(AST_SymbolRef, sym, flatten_var(sym)); + ref.definition().references.push(ref); body.push(make_node(AST_SimpleStatement, sym, { body: make_node(AST_Assign, sym, { operator: "=", diff --git a/test/compress/const.js b/test/compress/const.js index 60c686c2..96210a55 100644 --- a/test/compress/const.js +++ b/test/compress/const.js @@ -1727,3 +1727,28 @@ issue_4965_2: { expect_stdout: "undefined" node_version: ">=4" } + +issue_5254: { + options = { + inline: true, + toplevel: true, + } + input: { + do { + (function() { + const a = console.log; + a && a("foo"); + })(); + } while (console.log("bar")); + } + expect: { + do { + const a = console.log; + a && a("foo"); + } while (console.log("bar")); + } + expect_stdout: [ + "foo", + "bar", + ] +} diff --git a/test/compress/functions.js b/test/compress/functions.js index bb951d2b..a56e1075 100644 --- a/test/compress/functions.js +++ b/test/compress/functions.js @@ -944,6 +944,7 @@ inline_loop_5: { } expect: { for (var a in "foo") + f = void 0, f = function() {}, void console.log(typeof f, a - f); var f; @@ -971,6 +972,7 @@ inline_loop_6: { } expect: { for (var a in "foo") + f = void 0, f = function() {}, void console.log(typeof f, a - f); var f; @@ -983,6 +985,64 @@ inline_loop_6: { } inline_loop_7: { + options = { + inline: true, + toplevel: true, + } + input: { + for (var a in "foo") { + (function() { + function f() {} + var f; + while (console.log(typeof f, a - f)); + })(); + } + } + expect: { + for (var a in "foo") { + f = void 0; + var f = function() {}; + var f; + while (console.log(typeof f, a - f)); + } + } + expect_stdout: [ + "function NaN", + "function NaN", + "function NaN", + ] +} + +inline_loop_8: { + options = { + inline: true, + toplevel: true, + } + input: { + for (var a in "foo") { + (function() { + var f; + function f() {} + while (console.log(typeof f, a - f)); + })(); + } + } + expect: { + for (var a in "foo") { + f = void 0; + var f = function() {}; + var f; + while (console.log(typeof f, a - f)); + } + } + expect_stdout: [ + "function NaN", + "function NaN", + "function NaN", + ] +} + +inline_loop_9: { options = { inline: true, toplevel: true, @@ -6797,10 +6857,10 @@ issue_4753_2: { } expect: { do { + a = void 0, f = function() { return "PASS"; }, - a = void 0, a = f(), console.log(a); } while (0); @@ -7750,3 +7810,68 @@ issue_5249_2: { } expect_stdout: "undefined" } + +issue_5254_1: { + options = { + inline: 3, + unused: true, + } + input: { + (function(a) { + while (a--) + (function f() { + var f = new function() { + console.log(f); + }(); + })(); + })(2); + } + expect: { + (function(a) { + while (a--) + f = void 0, + f = new function() { + console.log(f); + }(), + void 0; + var f; + })(2); + } + expect_stdout: [ + "undefined", + "undefined", + ] +} + +issue_5254_2: { + options = { + inline: true, + unused: true, + } + input: { + (function(a) { + while (a--) + (function f() { + var f = new function() { + console.log(f); + }(); + while (!console); + })(); + })(2); + } + expect: { + (function(a) { + while (a--) { + f = void 0; + var f = new function() { + console.log(f); + }(); + while (!console); + } + })(2); + } + expect_stdout: [ + "undefined", + "undefined", + ] +} diff --git a/test/compress/let.js b/test/compress/let.js index 5ecef2e1..a689fd5c 100644 --- a/test/compress/let.js +++ b/test/compress/let.js @@ -1878,3 +1878,31 @@ issue_5240: { ] node_version: ">=4" } + +issue_5254: { + options = { + inline: true, + toplevel: true, + } + input: { + "use strict"; + do { + (function() { + let a = console.log; + a && a("foo"); + })(); + } while (console.log("bar")); + } + expect: { + "use strict"; + do { + let a = console.log; + a && a("foo"); + } while (console.log("bar")); + } + expect_stdout: [ + "foo", + "bar", + ] + node_version: ">=4" +}