fix corner case in sequences (#3704)

fixes #3703
This commit is contained in:
Alex Lam S.L
2020-02-04 04:57:32 +00:00
committed by GitHub
parent 36b2d35bf3
commit df506439b1
3 changed files with 73 additions and 39 deletions

View File

@@ -6162,34 +6162,43 @@ merge(Compressor.prototype, {
}); });
AST_Binary.DEFMETHOD("lift_sequences", function(compressor) { AST_Binary.DEFMETHOD("lift_sequences", function(compressor) {
if (compressor.option("sequences")) { if (this.left instanceof AST_PropAccess) {
if (this.left instanceof AST_Sequence) { if (!(this.left.expression instanceof AST_Sequence)) return this;
var x = this.left.expressions.slice(); var x = this.left.expression.expressions.slice();
var e = this.clone(); var e = this.clone();
e.left = x.pop(); e.left = e.left.clone();
x.push(e); e.left.expression = x.pop();
return make_sequence(this, x).optimize(compressor); x.push(e);
return make_sequence(this, x);
}
if (this.left instanceof AST_Sequence) {
var x = this.left.expressions.slice();
var e = this.clone();
e.left = x.pop();
x.push(e);
return make_sequence(this, x);
}
if (this.right instanceof AST_Sequence) {
if (this.left.has_side_effects(compressor)) return this;
var assign = this.operator == "=" && this.left instanceof AST_SymbolRef;
var x = this.right.expressions;
var last = x.length - 1;
for (var i = 0; i < last; i++) {
if (!assign && x[i].has_side_effects(compressor)) break;
} }
if (this.right instanceof AST_Sequence && !this.left.has_side_effects(compressor)) { if (i == last) {
var assign = this.operator == "=" && this.left instanceof AST_SymbolRef; x = x.slice();
var x = this.right.expressions; var e = this.clone();
var last = x.length - 1; e.right = x.pop();
for (var i = 0; i < last; i++) { x.push(e);
if (!assign && x[i].has_side_effects(compressor)) break; return make_sequence(this, x);
} }
if (i == last) { if (i > 0) {
x = x.slice(); var e = this.clone();
var e = this.clone(); e.right = make_sequence(this.right, x.slice(i));
e.right = x.pop(); x = x.slice(0, i);
x.push(e); x.push(e);
return make_sequence(this, x).optimize(compressor); return make_sequence(this, x);
} else if (i > 0) {
var e = this.clone();
e.right = make_sequence(this.right, x.slice(i));
x = x.slice(0, i);
x.push(e);
return make_sequence(this, x).optimize(compressor);
}
} }
} }
return this; return this;
@@ -6240,8 +6249,10 @@ merge(Compressor.prototype, {
// result. hence, force switch. // result. hence, force switch.
reverse(); reverse();
} }
var seq = self.lift_sequences(compressor); if (compressor.option("sequences")) {
if (seq !== self) return seq; var seq = self.lift_sequences(compressor);
if (seq !== self) return seq.optimize(compressor);
}
if (compressor.option("assignments") && lazy_op[self.operator]) { if (compressor.option("assignments") && lazy_op[self.operator]) {
var assign = self.right; var assign = self.right;
// a || (a = x) => a = a || x // a || (a = x) => a = a || x
@@ -7158,8 +7169,10 @@ merge(Compressor.prototype, {
|| parent instanceof AST_UnaryPrefix); || parent instanceof AST_UnaryPrefix);
} }
} }
var seq = self.lift_sequences(compressor); if (compressor.option("sequences")) {
if (seq !== self) return seq; var seq = self.lift_sequences(compressor);
if (seq !== self) return seq.optimize(compressor);
}
if (!compressor.option("assignments")) return self; if (!compressor.option("assignments")) return self;
if (self.operator == "=" && self.left instanceof AST_SymbolRef && self.right instanceof AST_Binary) { if (self.operator == "=" && self.left instanceof AST_SymbolRef && self.right instanceof AST_Binary) {
// x = expr1 OP expr2 // x = expr1 OP expr2
@@ -7587,10 +7600,6 @@ merge(Compressor.prototype, {
} }
OPT(AST_Sub, function(self, compressor) { 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 expr = self.expression;
var prop = self.property; var prop = self.property;
if (compressor.option("properties")) { if (compressor.option("properties")) {
@@ -7661,6 +7670,10 @@ merge(Compressor.prototype, {
} }
} }
if (is_lhs(compressor.self(), parent)) return self; if (is_lhs(compressor.self(), parent)) return self;
if (compressor.option("sequences") && compressor.parent().TYPE != "Call") {
var seq = lift_sequence_in_expression(self, compressor);
if (seq !== self) return seq.optimize(compressor);
}
if (key !== prop) { if (key !== prop) {
var sub = self.flatten_object(property, compressor); var sub = self.flatten_object(property, compressor);
if (sub) { if (sub) {
@@ -7755,10 +7768,6 @@ merge(Compressor.prototype, {
}); });
OPT(AST_Dot, function(self, compressor) { 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") { if (self.property == "arguments" || self.property == "caller") {
AST_Node.warn("Function.prototype.{prop} not supported [{file}:{line},{col}]", { AST_Node.warn("Function.prototype.{prop} not supported [{file}:{line},{col}]", {
prop: self.property, prop: self.property,
@@ -7768,6 +7777,10 @@ merge(Compressor.prototype, {
}); });
} }
if (is_lhs(compressor.self(), compressor.parent())) return self; if (is_lhs(compressor.self(), compressor.parent())) return self;
if (compressor.option("sequences") && compressor.parent().TYPE != "Call") {
var seq = lift_sequence_in_expression(self, compressor);
if (seq !== self) return seq.optimize(compressor);
}
if (compressor.option("unsafe_proto") if (compressor.option("unsafe_proto")
&& self.expression instanceof AST_Dot && self.expression instanceof AST_Dot
&& self.expression.property == "prototype") { && self.expression.property == "prototype") {

View File

@@ -783,6 +783,8 @@ function OutputStream(options) {
var p = output.parent(); var p = output.parent();
if (p instanceof AST_PropAccess && p.expression === this) { if (p instanceof AST_PropAccess && p.expression === this) {
var value = this.value; var value = this.value;
// https://github.com/mishoo/UglifyJS2/issues/115
// https://github.com/mishoo/UglifyJS2/pull/1009
if (value < 0 || /^0/.test(make_num(value))) { if (value < 0 || /^0/.test(make_num(value))) {
return true; return true;
} }

View File

@@ -1093,3 +1093,22 @@ issue_3490_2: {
} }
expect_stdout: "PASS 42" expect_stdout: "PASS 42"
} }
issue_3703: {
options = {
evaluate: true,
sequences: true,
unsafe: true,
}
input: {
var a = "FAIL";
while ((a = "PASS", 0).foo = 0);
console.log(a);
}
expect: {
var a = "FAIL";
while (a = "PASS", (0).foo = 0);
console.log(a);
}
expect_stdout: "PASS"
}