From 6a3fe9d1dfd3ec4543dc71b72e990bed2c6022ef Mon Sep 17 00:00:00 2001 From: "Alex Lam S.L" Date: Fri, 23 Jul 2021 10:17:20 +0100 Subject: [PATCH] fix corner cases in `reduce_vars` (#5097) fixes #5096 --- lib/compress.js | 58 ++++++++++-------- test/compress/arrows.js | 39 +++++++++++- test/compress/functions.js | 122 +++++++++++++++++++++++++++++++++++++ 3 files changed, 191 insertions(+), 28 deletions(-) diff --git a/lib/compress.js b/lib/compress.js index 5bb378e5bb..e025264643 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -884,15 +884,12 @@ merge(Compressor.prototype, { } if (ld && right instanceof AST_LambdaExpression) { walk_assign(); - if (ld.escaped.length) { - right.walk(tw); - } else { - right.parent_scope.resolve().fn_defs.push(right); - right.safe_ids = null; - if (!node.write_only) mark_fn_def(tw, ld, right); - } + right.parent_scope.resolve().fn_defs.push(right); + right.safe_ids = null; + if (!ld.fixed || !node.write_only) mark_fn_def(tw, ld, right); return true; - } else if (scan) { + } + if (scan) { right.walk(tw); walk_assign(); return true; @@ -1397,31 +1394,38 @@ merge(Compressor.prototype, { var node = this; var value = node.value; if (value instanceof AST_LambdaExpression && node.name instanceof AST_SymbolDeclaration) { + walk_defn(); value.parent_scope.resolve().fn_defs.push(value); value.safe_ids = null; + var ld = node.name.definition(); + if (!ld.fixed) mark_fn_def(tw, ld, value); } else if (value) { value.walk(tw); - } else if (!(tw.parent() instanceof AST_Let)) { - return; + walk_defn(); + } else if (tw.parent() instanceof AST_Let) { + walk_defn(); } - scan_declaration(tw, compressor, node.name, function() { - return node.value || make_node(AST_Undefined, node); - }, function(name, fixed) { - var d = name.definition(); - if (fixed && safe_to_assign(tw, d, true)) { - mark(tw, d); - tw.loop_ids[d.id] = tw.in_loop; - d.fixed = fixed; - d.fixed.assigns = [ node ]; - if (name instanceof AST_SymbolConst && d.redefined() - || !(can_drop_symbol(name) || is_safe_lexical(d))) { - d.single_use = false; - } - } else { - d.fixed = false; - } - }); return true; + + function walk_defn() { + scan_declaration(tw, compressor, node.name, function() { + return node.value || make_node(AST_Undefined, node); + }, function(name, fixed) { + var d = name.definition(); + if (fixed && safe_to_assign(tw, d, true)) { + mark(tw, d); + tw.loop_ids[d.id] = tw.in_loop; + d.fixed = fixed; + d.fixed.assigns = [ node ]; + if (name instanceof AST_SymbolConst && d.redefined() + || !(can_drop_symbol(name) || is_safe_lexical(d))) { + d.single_use = false; + } + } else { + d.fixed = false; + } + }); + } }); def(AST_While, function(tw, descend) { var save_loop = tw.in_loop; diff --git a/test/compress/arrows.js b/test/compress/arrows.js index abbbbf9004..5cbf56bc33 100644 --- a/test/compress/arrows.js +++ b/test/compress/arrows.js @@ -556,7 +556,7 @@ reduce_iife_3: { node_version: ">=4" } -reduce_lambda: { +reduce_lambda_1: { options = { evaluate: true, reduce_vars: true, @@ -588,6 +588,43 @@ reduce_lambda: { node_version: ">=4" } +reduce_lambda_2: { + options = { + evaluate: true, + passes: 2, + reduce_vars: true, + side_effects: true, + unused: true, + } + input: { + (function(f, a, b) { + f = () => { + console.log(a, b); + }; + a = "foo", b = 42; + f(); + b = "bar"; + f(); + })(); + } + expect: { + (function(f, a, b) { + f = () => { + console.log("foo", b); + }; + b = 42; + f(); + b = "bar"; + f(); + })(); + } + expect_stdout: [ + "foo 42", + "foo bar", + ] + node_version: ">=4" +} + single_use_recursive: { options = { reduce_vars: true, diff --git a/test/compress/functions.js b/test/compress/functions.js index 257ff7a253..ff727da4c7 100644 --- a/test/compress/functions.js +++ b/test/compress/functions.js @@ -6413,3 +6413,125 @@ issue_5067: { } expect: {} } + +issue_5096_1: { + options = { + evaluate: true, + passes: 2, + reduce_vars: true, + side_effects: true, + toplevel: true, + } + input: { + var a, b = "FAIL", c = 1; + do { + a && a(); + a = function() { + b = "PASS"; + }; + } while (c--); + console.log(b); + } + expect: { + var a, b = "FAIL", c = 1; + do { + a && a(); + a = function() { + b = "PASS"; + }; + } while (c--); + console.log(b); + } + expect_stdout: "PASS" +} + +issue_5096_2: { + options = { + passes: 2, + reduce_vars: true, + side_effects: true, + toplevel: true, + unused: true, + } + input: { + var a, b = "FAIL", c = 1; + do { + a && a(); + a = function() { + b = "PASS"; + }; + } while (c--); + console.log(b); + } + expect: { + var a, b = "FAIL", c = 1; + do { + a && a(); + a = function() { + b = "PASS"; + }; + } while (c--); + console.log(b); + } + expect_stdout: "PASS" +} + +issue_5096_3: { + options = { + evaluate: true, + reduce_vars: true, + side_effects: true, + toplevel: true, + } + input: { + var b = "FAIL", c = 1; + do { + a && a(); + var a = function() { + b = "PASS"; + }; + } while (c--); + console.log(b); + } + expect: { + var b = "FAIL", c = 1; + do { + a && a(); + var a = function() { + b = "PASS"; + }; + } while (c--); + console.log(b); + } + expect_stdout: "PASS" +} + +issue_5096_4: { + options = { + reduce_vars: true, + side_effects: true, + toplevel: true, + unused: true, + } + input: { + var b = "FAIL", c = 1; + do { + a && a(); + var a = function() { + b = "PASS"; + }; + } while (c--); + console.log(b); + } + expect: { + var b = "FAIL", c = 1; + do { + a && a(); + var a = function() { + b = "PASS"; + }; + } while (c--); + console.log(b); + } + expect_stdout: "PASS" +}