aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/compress.js39
-rw-r--r--test/compress/dead-code.js130
2 files changed, 152 insertions, 17 deletions
diff --git a/lib/compress.js b/lib/compress.js
index 8d8dffa2..2a1399d5 100644
--- a/lib/compress.js
+++ b/lib/compress.js
@@ -571,7 +571,14 @@ merge(Compressor.prototype, {
});
def(AST_Assign, function(tw, descend, compressor) {
var node = this;
+ var eq = node.operator == "=";
var sym = node.left;
+ if (eq && sym.equivalent_to(node.right) && !sym.has_side_effects(compressor)) {
+ node.right.walk(tw);
+ walk_prop(sym);
+ node.__drop = true;
+ return true;
+ }
if (!(sym instanceof AST_SymbolRef)) {
mark_assignment_to_arguments(sym);
return;
@@ -579,7 +586,6 @@ merge(Compressor.prototype, {
var d = sym.definition();
d.assignments++;
var fixed = d.fixed;
- var eq = node.operator == "=";
var value = eq ? node.right : node;
if (is_modified(compressor, tw, node, value, 0)) return;
var safe = eq || safe_to_read(tw, d);
@@ -609,6 +615,21 @@ merge(Compressor.prototype, {
d.fixed = false;
}
return true;
+
+ function walk_prop(node) {
+ if (node instanceof AST_Dot) {
+ walk_prop(node.expression);
+ } else if (node instanceof AST_Sub) {
+ walk_prop(node.expression);
+ node.property.walk(tw);
+ } else if (node instanceof AST_SymbolRef) {
+ var d = node.definition();
+ push_ref(d, node);
+ node.fixed = d.fixed;
+ } else {
+ node.walk(tw);
+ }
+ }
});
def(AST_Binary, function(tw) {
if (!lazy_op[this.operator]) return;
@@ -7843,8 +7864,15 @@ merge(Compressor.prototype, {
if (compressor.option("dead_code")) {
if (self.left instanceof AST_PropAccess) {
if (self.operator == "=") {
- if (self.left.equivalent_to(self.right)
- && (self.left instanceof AST_Dot || !self.left.property.has_side_effects(compressor))) {
+ if (self.__drop) {
+ var props = [];
+ flatten(self.left, props);
+ flatten(self.right, props);
+ return props.length == 0 ? make_node(AST_Number, self, {
+ value: 0
+ }) : make_sequence(self, props).optimize(compressor);
+ }
+ if (self.left.equivalent_to(self.right) && !self.left.has_side_effects(compressor)) {
return self.right;
}
var exp = self.left.expression;
@@ -7934,6 +7962,11 @@ merge(Compressor.prototype, {
}
return try_evaluate(compressor, self);
+ function flatten(node, props) {
+ if (!(node.expression instanceof AST_SymbolRef)) props.push(node.expression);
+ if (node instanceof AST_Sub) props.push(node.property);
+ }
+
function in_try(level, node) {
var right = self.right;
self.right = make_node(AST_Null, right);
diff --git a/test/compress/dead-code.js b/test/compress/dead-code.js
index 5506b95a..a2ebf37a 100644
--- a/test/compress/dead-code.js
+++ b/test/compress/dead-code.js
@@ -1169,29 +1169,131 @@ redundant_assignments: {
expect_stdout: "PASS PASS"
}
-self_assignments: {
+self_assignments_1: {
options = {
dead_code: true,
}
input: {
- var a = "PASS", b = 0, l = [ "FAIL", "PASS" ], o = { p: "PASS" };
+ var a = "PASS";
a = a;
- l[0] = l[0];
- l[b] = l[b];
- l[b++] = l[b++];
- o.p = o.p;
- console.log(a, b, l[0], o.p);
+ console.log(a);
}
expect: {
- var a = "PASS", b = 0, l = [ "FAIL", "PASS" ], o = { p: "PASS" };
+ var a = "PASS";
a;
- l[0];
- l[b];
- l[b++] = l[b++];
- o.p;
- console.log(a, b, l[0], o.p);
+ console.log(a);
+ }
+ expect_stdout: "PASS"
+}
+
+self_assignments_2: {
+ options = {
+ dead_code: true,
+ pure_getters: "strict",
+ reduce_vars: true,
+ side_effects: true,
+ toplevel: true,
+ }
+ input: {
+ var a = "q", o = {
+ p: "PASS",
+ };
+ o.p = o.p;
+ o[a] = o[a];
+ console.log(o.p, o[a]);
+ }
+ expect: {
+ var a = "q", o = {
+ p: "PASS",
+ };
+ console.log(o.p, o[a]);
+ }
+ expect_stdout: "PASS undefined"
+}
+
+self_assignments_3: {
+ options = {
+ dead_code: true,
+ pure_getters: "strict",
+ reduce_vars: true,
+ side_effects: true,
+ toplevel: true,
+ }
+ input: {
+ var a = "q", o = {
+ p: "FAIL",
+ get q() {
+ return "PASS";
+ },
+ set q(v) {
+ this.p = v;
+ },
+ };
+ o.p = o.p;
+ o[a] = o[a];
+ console.log(o.p, o[a]);
+ }
+ expect: {
+ var a = "q", o = {
+ p: "FAIL",
+ get q() {
+ return "PASS";
+ },
+ set q(v) {
+ this.p = v;
+ },
+ };
+ o.p = o.p;
+ o[a] = o[a];
+ console.log(o.p, o[a]);
+ }
+ expect_stdout: "PASS PASS"
+}
+
+self_assignments_4: {
+ options = {
+ dead_code: true,
+ pure_getters: "strict",
+ reduce_vars: true,
+ side_effects: true,
+ toplevel: true,
+ }
+ input: {
+ var i = 0, l = [ "PASS" ];
+ l[0] = l[0];
+ l[i] = l[i];
+ console.log(l[0], i);
+ }
+ expect: {
+ var i = 0, l = [ "PASS" ];
+ console.log(l[0], i);
+ }
+ expect_stdout: "PASS 0"
+}
+
+self_assignments_5: {
+ options = {
+ dead_code: true,
+ evaluate: true,
+ passes: 3,
+ pure_getters: "strict",
+ reduce_vars: true,
+ side_effects: true,
+ toplevel: true,
+ }
+ input: {
+ var i = 0, l = [ "FAIL", "PASS" ];
+ l[0] = l[0];
+ l[i] = l[i];
+ l[i++] = l[i++];
+ console.log(l[0], i);
+ }
+ expect: {
+ var i = 0, l = [ "FAIL", "PASS" ];
+ l[0] = l[1];
+ console.log(l[0], 2);
}
- expect_stdout: "PASS 2 PASS PASS"
+ expect_stdout: "PASS 2"
}
issue_3967: {