diff options
-rw-r--r-- | lib/compress.js | 51 | ||||
-rw-r--r-- | test/compress/dead-code.js | 29 | ||||
-rw-r--r-- | test/compress/drop-unused.js | 34 |
3 files changed, 96 insertions, 18 deletions
diff --git a/lib/compress.js b/lib/compress.js index ad47621a..33943ff0 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -3441,6 +3441,7 @@ merge(Compressor.prototype, { return true; } if (node instanceof AST_Scope) { + if (node === self) return; scopes.push(node); descend(); scopes.pop(); @@ -3451,6 +3452,7 @@ merge(Compressor.prototype, { result = false; return true; } + if (self.variables.has(node.name)) return true; var def = node.definition(); if (member(def.scope, scopes)) return true; if (scope) { @@ -6429,24 +6431,37 @@ merge(Compressor.prototype, { var ASSIGN_OPS = makePredicate("+ - / * % >> << >>> | ^ &"); var ASSIGN_OPS_COMMUTATIVE = makePredicate("* | ^ &"); OPT(AST_Assign, function(self, compressor) { - var def; - if (compressor.option("dead_code") - && self.left instanceof AST_SymbolRef - && (def = self.left.definition()).scope === compressor.find_parent(AST_Lambda)) { - if (self.left.is_immutable()) return strip_assignment(); - var level = 0, node, parent = self; - do { - node = parent; - parent = compressor.parent(level++); - if (parent instanceof AST_Exit) { - if (in_try(level, parent)) break; - if (is_reachable(def.scope, [ def ])) break; - def.fixed = false; - return strip_assignment(); - } - } while (parent instanceof AST_Binary && parent.right === node - || parent instanceof AST_Sequence && parent.tail_node() === node - || parent instanceof AST_UnaryPrefix); + if (compressor.option("dead_code")) { + if (self.left instanceof AST_PropAccess) { + var exp = self.left.expression; + if (exp instanceof AST_Lambda + || !compressor.has_directive("use strict") + && exp instanceof AST_Constant + && !exp.may_throw_on_access(compressor)) { + return self.left instanceof AST_Dot ? self.right : make_sequence(self, [ + self.left.property, + self.right + ]).optimize(compressor); + } + } else if (self.left instanceof AST_SymbolRef) { + var def = self.left.definition(); + if (def.scope === compressor.find_parent(AST_Lambda)) { + if (self.left.is_immutable()) return strip_assignment(); + var level = 0, node, parent = self; + do { + node = parent; + parent = compressor.parent(level++); + if (parent instanceof AST_Exit) { + if (in_try(level, parent)) break; + if (is_reachable(def.scope, [ def ])) break; + def.fixed = false; + return strip_assignment(); + } + } while (parent instanceof AST_Binary && parent.right === node + || parent instanceof AST_Sequence && parent.tail_node() === node + || parent instanceof AST_UnaryPrefix); + } + } } self = self.lift_sequences(compressor); if (!compressor.option("assignments")) return self; diff --git a/test/compress/dead-code.js b/test/compress/dead-code.js index 190a3243..501d55ec 100644 --- a/test/compress/dead-code.js +++ b/test/compress/dead-code.js @@ -1013,3 +1013,32 @@ issue_3406: { } expect_stdout: "true" } + +function_assign: { + options = { + dead_code: true, + } + input: { + console.log(function() { + var a = "PASS"; + function h(c) { + return c; + } + h.p = function(b) { + return b; + }.p = a; + return h; + }().p); + } + expect: { + console.log(function() { + var a = "PASS"; + function h(c) { + return c; + } + h.p = a; + return h; + }().p); + } + expect_stdout: "PASS" +} diff --git a/test/compress/drop-unused.js b/test/compress/drop-unused.js index f77072b0..7cb2e899 100644 --- a/test/compress/drop-unused.js +++ b/test/compress/drop-unused.js @@ -2187,3 +2187,37 @@ issue_3515_3: { } expect_stdout: "PASS" } + +function_assign: { + options = { + pure_getters: "strict", + reduce_vars: true, + side_effects: true, + unused: true, + } + input: { + console.log(function() { + var a = "PASS"; + function g(b) { + return b; + } + g.p = a; + function h(c) { + return c; + } + h.p = a; + return h; + }().p); + } + expect: { + console.log(function() { + var a = "PASS"; + function h(c) { + return c; + } + h.p = a; + return h; + }().p); + } + expect_stdout: "PASS" +} |