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) {
if (compressor.option("sequences")) {
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).optimize(compressor);
if (this.left instanceof AST_PropAccess) {
if (!(this.left.expression instanceof AST_Sequence)) return this;
var x = this.left.expression.expressions.slice();
var e = this.clone();
e.left = e.left.clone();
e.left.expression = x.pop();
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)) {
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 (i == last) {
x = x.slice();
var e = this.clone();
e.right = x.pop();
x.push(e);
return make_sequence(this, x).optimize(compressor);
} 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);
}
if (i == last) {
x = x.slice();
var e = this.clone();
e.right = x.pop();
x.push(e);
return make_sequence(this, x);
}
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);
}
}
return this;
@@ -6240,8 +6249,10 @@ merge(Compressor.prototype, {
// result. hence, force switch.
reverse();
}
var seq = self.lift_sequences(compressor);
if (seq !== self) return seq;
if (compressor.option("sequences")) {
var seq = self.lift_sequences(compressor);
if (seq !== self) return seq.optimize(compressor);
}
if (compressor.option("assignments") && lazy_op[self.operator]) {
var assign = self.right;
// a || (a = x) => a = a || x
@@ -7158,8 +7169,10 @@ merge(Compressor.prototype, {
|| parent instanceof AST_UnaryPrefix);
}
}
var seq = self.lift_sequences(compressor);
if (seq !== self) return seq;
if (compressor.option("sequences")) {
var seq = self.lift_sequences(compressor);
if (seq !== self) return seq.optimize(compressor);
}
if (!compressor.option("assignments")) return self;
if (self.operator == "=" && self.left instanceof AST_SymbolRef && self.right instanceof AST_Binary) {
// x = expr1 OP expr2
@@ -7587,10 +7600,6 @@ 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")) {
@@ -7661,6 +7670,10 @@ merge(Compressor.prototype, {
}
}
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) {
var sub = self.flatten_object(property, compressor);
if (sub) {
@@ -7755,10 +7768,6 @@ 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,
@@ -7768,6 +7777,10 @@ merge(Compressor.prototype, {
});
}
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")
&& self.expression instanceof AST_Dot
&& self.expression.property == "prototype") {

View File

@@ -783,6 +783,8 @@ function OutputStream(options) {
var p = output.parent();
if (p instanceof AST_PropAccess && p.expression === this) {
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))) {
return true;
}

View File

@@ -1093,3 +1093,22 @@ issue_3490_2: {
}
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"
}