From 3e2c51a4da6fa27733b666f7db56d7ff7539fba0 Mon Sep 17 00:00:00 2001 From: "Alex Lam S.L" Date: Tue, 5 Nov 2019 18:15:28 +0800 Subject: [PATCH] enhance `collapse_vars` (#3572) --- lib/compress.js | 36 +++++++++++++++++++++---- test/compress/collapse_vars.js | 48 ++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+), 5 deletions(-) diff --git a/lib/compress.js b/lib/compress.js index 87671d8ec8..ba789816d1 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -1235,7 +1235,7 @@ merge(Compressor.prototype, { var lvalues = get_lvalues(candidate); var lhs_local = is_lhs_local(lhs); if (!side_effects) side_effects = value_has_side_effects(candidate); - var replace_all = replace_all_symbols(); + var replace_all = replace_all_symbols(candidate); var may_throw = candidate.may_throw(compressor) ? in_try ? function(node) { return node.has_side_effects(compressor); } : side_effects_external : return_false; @@ -1312,6 +1312,7 @@ merge(Compressor.prototype, { function in_conditional(node, parent) { if (parent instanceof AST_Binary) return lazy_op[parent.operator] && parent.left !== node; + if (parent instanceof AST_Case) return parent.expression !== node; if (parent instanceof AST_Conditional) return parent.condition !== node; return parent instanceof AST_If && parent.condition !== node; } @@ -1477,19 +1478,43 @@ merge(Compressor.prototype, { if (parent instanceof AST_Call) return node; if (parent instanceof AST_Case) return node; if (parent instanceof AST_Conditional) return node; - if (parent instanceof AST_Definitions) return find_stop(parent, level + 1); + if (parent instanceof AST_Definitions) return find_stop_unused(parent, level + 1); if (parent instanceof AST_Exit) return node; if (parent instanceof AST_If) return node; if (parent instanceof AST_IterationStatement) return node; if (parent instanceof AST_PropAccess) return node; - if (parent instanceof AST_Sequence) return find_stop(parent, level + 1); - if (parent instanceof AST_SimpleStatement) return find_stop(parent, level + 1); + if (parent instanceof AST_Sequence) { + return (parent.tail_node() === node ? find_stop : find_stop_unused)(parent, level + 1); + } + if (parent instanceof AST_SimpleStatement) return find_stop_unused(parent, level + 1); if (parent instanceof AST_Switch) return node; if (parent instanceof AST_Unary) return node; if (parent instanceof AST_VarDef) return node; return null; } + function find_stop_unused(node, level) { + var parent = scanner.parent(level); + if (is_last_node(node, parent)) return node; + if (in_conditional(node, parent)) return node; + if (parent instanceof AST_Assign) return find_stop_unused(parent, level + 1); + if (parent instanceof AST_Binary) return find_stop_unused(parent, level + 1); + if (parent instanceof AST_Call) return find_stop_unused(parent, level + 1); + if (parent instanceof AST_Case) return find_stop_unused(parent, level + 1); + if (parent instanceof AST_Conditional) return find_stop_unused(parent, level + 1); + if (parent instanceof AST_Definitions) return find_stop_unused(parent, level + 1); + if (parent instanceof AST_Exit) return find_stop_unused(parent, level + 1); + if (parent instanceof AST_If) return find_stop_unused(parent, level + 1); + if (parent instanceof AST_IterationStatement) return node; + if (parent instanceof AST_PropAccess) return find_stop_unused(parent, level + 1); + if (parent instanceof AST_Sequence) return find_stop_unused(parent, level + 1); + if (parent instanceof AST_SimpleStatement) return find_stop_unused(parent, level + 1); + if (parent instanceof AST_Switch) return find_stop_unused(parent, level + 1); + if (parent instanceof AST_Unary) return find_stop_unused(parent, level + 1); + if (parent instanceof AST_VarDef) return find_stop_unused(parent, level + 1); + return null; + } + function mangleable_var(var_def) { var value = var_def.value; if (!(value instanceof AST_SymbolRef)) return; @@ -1656,7 +1681,8 @@ merge(Compressor.prototype, { return get_rvalue(expr).has_side_effects(compressor); } - function replace_all_symbols() { + function replace_all_symbols(expr) { + if (expr instanceof AST_Unary) return false; if (side_effects) return false; if (value_def) return true; if (lhs instanceof AST_SymbolRef) { diff --git a/test/compress/collapse_vars.js b/test/compress/collapse_vars.js index 31978c29a1..cf4e45a57c 100644 --- a/test/compress/collapse_vars.js +++ b/test/compress/collapse_vars.js @@ -6387,3 +6387,51 @@ issue_3562: { } expect_stdout: "PASS PASS" } + +dot_throw_assign_sequence: { + options = { + collapse_vars: true, + } + input: { + var a = "FAIL"; + try { + var b; + b[0] = (a = "PASS", 0); + a = 1 + a; + } catch (c) { + } + console.log(a); + } + expect: { + var a = "FAIL"; + try { + var b; + b[0] = (a = "PASS", 0); + a = 1 + a; + } catch (c) { + } + console.log(a); + } + expect_stdout: "PASS" +} + +call_assign_order: { + options = { + collapse_vars: true, + } + input: { + var a, b = 1, c = 0, log = console.log; + (function() { + a = b = "PASS"; + })((b = "FAIL", c++)); + log(a, b); + } + expect: { + var a, b = 1, c = 0, log = console.log; + (function() { + a = b = "PASS"; + })((b = "FAIL", c++)); + log(a, b); + } + expect_stdout: "PASS PASS" +}