diff --git a/lib/compress.js b/lib/compress.js index e14d9d06c4..2a338ba16d 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -5400,25 +5400,32 @@ merge(Compressor.prototype, { return self.definitions.length ? self : make_node(AST_EmptyStatement, self); }); - AST_Call.DEFMETHOD("lift_sequences", function(compressor) { - if (!compressor.option("sequences")) return this; - var exp = this.expression; - if (!(exp instanceof AST_Sequence)) return this; - var tail = exp.tail_node(); - if (needs_unbinding(compressor, tail) && !(this instanceof AST_New)) return this; - var expressions = exp.expressions.slice(0, -1); - var node = this.clone(); - node.expression = tail; - expressions.push(node); - return make_sequence(this, expressions).optimize(compressor); - }); + function lift_sequence_in_expression(node, compressor) { + var exp = node.expression; + if (!(exp instanceof AST_Sequence)) return node; + var x = exp.expressions.slice(); + var e = node.clone(); + e.expression = x.pop(); + x.push(e); + return make_sequence(node, x); + } OPT(AST_Call, function(self, compressor) { - var seq = self.lift_sequences(compressor); - if (seq !== self) { - return seq; - } var exp = self.expression; + if (compressor.option("sequences")) { + if (exp instanceof AST_PropAccess) { + var seq = lift_sequence_in_expression(exp, compressor); + if (seq !== exp) { + var call = self.clone(); + call.expression = seq.expressions.pop(); + seq.expressions.push(call); + return seq.optimize(compressor); + } + } else if (!needs_unbinding(compressor, exp.tail_node())) { + var seq = lift_sequence_in_expression(self, compressor); + if (seq !== self) return seq.optimize(compressor); + } + } var fn = exp; if (compressor.option("reduce_vars") && fn instanceof AST_SymbolRef) { fn = fn.fixed_value(); @@ -5989,9 +5996,9 @@ merge(Compressor.prototype, { }); OPT(AST_New, function(self, compressor) { - var seq = self.lift_sequences(compressor); - if (seq !== self) { - return seq; + if (compressor.option("sequences")) { + var seq = lift_sequence_in_expression(self, compressor); + if (seq !== self) return seq.optimize(compressor); } if (compressor.option("unsafe")) { var exp = self.expression; @@ -6047,19 +6054,12 @@ merge(Compressor.prototype, { } }); - AST_Unary.DEFMETHOD("lift_sequences", function(compressor) { - if (compressor.option("sequences") && this.expression instanceof AST_Sequence) { - var x = this.expression.expressions.slice(); - var e = this.clone(); - e.expression = x.pop(); - x.push(e); - return make_sequence(this, x).optimize(compressor); - } - return this; - }); - OPT(AST_UnaryPostfix, function(self, compressor) { - return self.lift_sequences(compressor); + if (compressor.option("sequences")) { + var seq = lift_sequence_in_expression(self, compressor); + if (seq !== self) return seq.optimize(compressor); + } + return self; }); OPT(AST_UnaryPrefix, function(self, compressor) { @@ -6076,9 +6076,9 @@ merge(Compressor.prototype, { } return make_sequence(self, [ e, make_node(AST_True, self) ]).optimize(compressor); } - var seq = self.lift_sequences(compressor); - if (seq !== self) { - return seq; + if (compressor.option("sequences")) { + var seq = lift_sequence_in_expression(self, compressor); + if (seq !== self) return seq.optimize(compressor); } if (compressor.option("side_effects") && self.operator == "void") { e = e.drop_side_effect_free(compressor); @@ -6211,7 +6211,8 @@ merge(Compressor.prototype, { // result. hence, force switch. reverse(); } - self = self.lift_sequences(compressor); + var seq = self.lift_sequences(compressor); + if (seq !== self) return seq; if (compressor.option("assignments") && lazy_op[self.operator]) { var assign = self.right; // a || (a = x) => a = a || x @@ -7127,7 +7128,8 @@ merge(Compressor.prototype, { || parent instanceof AST_UnaryPrefix); } } - self = self.lift_sequences(compressor); + var seq = self.lift_sequences(compressor); + if (seq !== self) return seq; if (!compressor.option("assignments")) return self; if (self.operator == "=" && self.left instanceof AST_SymbolRef && self.right instanceof AST_Binary) { // x = expr1 OP expr2 @@ -7486,6 +7488,10 @@ merge(Compressor.prototype, { } OPT(AST_Sub, function(self, compressor) { + if (compressor.option("sequences") && compressor.parent().TYPE != "Call") { + var seq = lift_sequence_in_expression(self, compressor); + if (seq !== self) return seq.optimize(compressor); + } var expr = self.expression; var prop = self.property; if (compressor.option("properties")) { @@ -7650,6 +7656,10 @@ merge(Compressor.prototype, { }); OPT(AST_Dot, function(self, compressor) { + if (compressor.option("sequences") && compressor.parent().TYPE != "Call") { + var seq = lift_sequence_in_expression(self, compressor); + if (seq !== self) return seq.optimize(compressor); + } if (self.property == "arguments" || self.property == "caller") { AST_Node.warn("Function.prototype.{prop} not supported [{file}:{line},{col}]", { prop: self.property, diff --git a/test/compress/functions.js b/test/compress/functions.js index c8bced52d9..ef51af7255 100644 --- a/test/compress/functions.js +++ b/test/compress/functions.js @@ -2244,7 +2244,7 @@ issue_3076: { var c = "PASS"; (function(b) { var n = 2; - while (--b + (e = void 0, e && (c = "FAIL"), e = 5, 1).toString() && --n > 0); + while (--b + (e = void 0, e && (c = "FAIL"), e = 5, 1..toString()) && --n > 0); var e; })(2), console.log(c); diff --git a/test/compress/sequences.js b/test/compress/sequences.js index fbca559aa0..648f64915b 100644 --- a/test/compress/sequences.js +++ b/test/compress/sequences.js @@ -910,15 +910,23 @@ call: { console.log(this === b ? "bar" : "baz"); }; (a, b)(); + (a, b).c(); (a, b.c)(); + (a, b)["c"](); + (a, b["c"])(); (a, function() { console.log(this === a); })(); new (a, b)(); + new (a, b).c(); new (a, b.c)(); + new (a, b)["c"](); + new (a, b["c"])(); new (a, function() { console.log(this === a); })(); + console.log(typeof (a, b).c); + console.log(typeof (a, b)["c"]); } expect: { var a = function() { @@ -931,23 +939,39 @@ call: { console.log(this === b ? "bar" : "baz"); }, b(), + b.c(), (a, b.c)(), + b["c"](), + (a, b["c"])(), function() { console.log(this === a); }(), new b(), new b.c(), + new b.c(), + new b["c"](), + new b["c"](), new function() { console.log(this === a); - }(); + }(), + console.log((a, typeof b.c)), + console.log((a, typeof b["c"])); } expect_stdout: [ "foo", + "bar", + "baz", + "bar", "baz", "true", "foo", "baz", + "baz", + "baz", + "baz", "false", + "function", + "function", ] }