From a84beafd1bbdb61ea5fc3662e349f6c960f1ba66 Mon Sep 17 00:00:00 2001 From: "Alex Lam S.L" Date: Wed, 24 Apr 2019 02:50:15 +0800 Subject: [PATCH] fix corner case in `assignments` (#3376) fixes #3375 --- lib/ast.js | 2 +- lib/compress.js | 20 ++++++++++++-------- test/compress/assignment.js | 22 ++++++++++++++++++++++ test/compress/drop-unused.js | 21 +++++++++++++++++++++ 4 files changed, 56 insertions(+), 9 deletions(-) diff --git a/lib/ast.js b/lib/ast.js index 09c29b416f..f496095abf 100644 --- a/lib/ast.js +++ b/lib/ast.js @@ -773,7 +773,7 @@ var AST_Label = DEFNODE("Label", "references", { } }, AST_Symbol); -var AST_SymbolRef = DEFNODE("SymbolRef", null, { +var AST_SymbolRef = DEFNODE("SymbolRef", "fixed", { $documentation: "Reference to some symbol (not definition/declaration)", }, AST_Symbol); diff --git a/lib/compress.js b/lib/compress.js index 87082807aa..3fb835f590 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -551,6 +551,7 @@ merge(Compressor.prototype, { mark_assignment_to_arguments(sym); return; } + if (sym.fixed) delete sym.fixed; var d = sym.definition(); var safe = safe_to_assign(tw, d, sym.scope, node.right); d.assignments++; @@ -560,7 +561,7 @@ merge(Compressor.prototype, { var value = eq ? node.right : node; if (is_modified(compressor, tw, node, value, 0)) return; if (!eq) d.chained = true; - d.fixed = eq ? function() { + sym.fixed = d.fixed = eq ? function() { return node.right; } : function() { return make_node(AST_Binary, node, { @@ -574,7 +575,7 @@ merge(Compressor.prototype, { mark(tw, d, false); node.right.walk(tw); mark(tw, d, true); - mark_escaped(tw, d, sym.scope, node, value, 0, 1); + if (eq) mark_escaped(tw, d, sym.scope, node, value, 0, 1); return true; }); def(AST_Binary, function(tw) { @@ -730,6 +731,7 @@ merge(Compressor.prototype, { this.definition().fixed = false; }); def(AST_SymbolRef, function(tw, descend, compressor) { + if (this.fixed) delete this.fixed; var d = this.definition(); d.references.push(this); if (d.references.length == 1 @@ -797,13 +799,14 @@ merge(Compressor.prototype, { mark_assignment_to_arguments(exp); return; } + if (exp.fixed) delete exp.fixed; var d = exp.definition(); var safe = safe_to_assign(tw, d, exp.scope, true); d.assignments++; var fixed = d.fixed; if (!fixed) return; d.chained = true; - d.fixed = function() { + exp.fixed = d.fixed = function() { return make_node(AST_Binary, node, { operator: node.operator.slice(0, -1), left: make_node(AST_UnaryPrefix, node, { @@ -874,10 +877,11 @@ merge(Compressor.prototype, { this.walk(tw); }); - AST_Symbol.DEFMETHOD("fixed_value", function() { + AST_Symbol.DEFMETHOD("fixed_value", function(final) { var fixed = this.definition().fixed; - if (!fixed || fixed instanceof AST_Node) return fixed; - return fixed(); + if (!fixed) return fixed; + if (!final && this.fixed) fixed = this.fixed; + return fixed instanceof AST_Node ? fixed : fixed(); }); AST_SymbolRef.DEFMETHOD("is_immutable", function() { @@ -3514,7 +3518,7 @@ merge(Compressor.prototype, { if (def.value.has_side_effects(compressor)) { def.value.walk(tw); } - if (!node_def.chained && def.name.fixed_value() === def.value) { + if (!node_def.chained && def.name.fixed_value(true) === def.value) { fixed_ids[node_def.id] = def; } } @@ -3785,7 +3789,7 @@ merge(Compressor.prototype, { if (node instanceof AST_Assign) { node.right.walk(tw); if (node.left === sym) { - if (!node_def.chained && sym.fixed_value() === node.right) { + if (!node_def.chained && sym.fixed_value(true) === node.right) { fixed_ids[node_def.id] = node; } if (!node.write_only) { diff --git a/test/compress/assignment.js b/test/compress/assignment.js index ba412583bf..ece0185d98 100644 --- a/test/compress/assignment.js +++ b/test/compress/assignment.js @@ -289,3 +289,25 @@ increment_decrement_2: { } expect_stdout: "42" } + +issue_3375: { + options = { + assignments: true, + reduce_vars: true, + } + input: { + console.log(typeof function(b) { + var a = b += 1; + --b; + return a; + }("object")); + } + expect: { + console.log(typeof function(b) { + var a = b += 1; + --b; + return a; + }("object")); + } + expect_stdout: "string" +} diff --git a/test/compress/drop-unused.js b/test/compress/drop-unused.js index b75c3ac549..74fe36937e 100644 --- a/test/compress/drop-unused.js +++ b/test/compress/drop-unused.js @@ -2005,3 +2005,24 @@ issue_3233: { } expect_stdout: "PASS" } + +issue_3375: { + options = { + reduce_vars: true, + toplevel: true, + unused: true, + } + input: { + var b = 1; + var a = c = [], c = --b + ("function" == typeof f && f()); + var a = c && c[a]; + console.log(a, b); + } + expect: { + var b = 1; + var a = [], c = --b + ("function" == typeof f && f()); + a = c && c[a]; + console.log(a, b); + } + expect_stdout: "0 0" +}