From 8a828226547bcb898b95b69a3f55f6a0dc74d592 Mon Sep 17 00:00:00 2001 From: "Alex Lam S.L" Date: Thu, 8 Apr 2021 01:57:59 +0100 Subject: [PATCH] fix corner case in `if_return` (#4851) fixes #4848 --- lib/compress.js | 23 +++++++++++++++++-- lib/scope.js | 12 +++++----- test/compress/classes.js | 48 ++++++++++++++++++++++++++++++++++++++++ test/compress/const.js | 37 +++++++++++++++++++++++++++++++ test/compress/let.js | 40 +++++++++++++++++++++++++++++++++ 5 files changed, 153 insertions(+), 7 deletions(-) diff --git a/lib/compress.js b/lib/compress.js index 437baabfe5..21eec7c311 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -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; } diff --git a/lib/scope.js b/lib/scope.js index 9d4b890059..f0d4c921ed 100644 --- a/lib/scope.js +++ b/lib/scope.js @@ -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; diff --git a/test/compress/classes.js b/test/compress/classes.js index fe8c7e3c60..badcb2e6e2 100644 --- a/test/compress/classes.js +++ b/test/compress/classes.js @@ -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" +} diff --git a/test/compress/const.js b/test/compress/const.js index 4306fff295..fce6ebeaa6 100644 --- a/test/compress/const.js +++ b/test/compress/const.js @@ -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" +} diff --git a/test/compress/let.js b/test/compress/let.js index 90d99524fc..c59308c404 100644 --- a/test/compress/let.js +++ b/test/compress/let.js @@ -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" +}