fix corner case in `sequences` (#3704)
authorAlex Lam S.L <alexlamsl@gmail.com>
Tue, 4 Feb 2020 04:57:32 +0000 (04:57 +0000)
committerGitHub <noreply@github.com>
Tue, 4 Feb 2020 04:57:32 +0000 (04:57 +0000)
fixes #3703

lib/compress.js
lib/output.js
test/compress/sequences.js

index 5d14963..32d0b67 100644 (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();
+        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 (i == last) {
+                x = x.slice();
                 var e = this.clone();
-                e.left = x.pop();
+                e.right = x.pop();
                 x.push(e);
-                return make_sequence(this, x).optimize(compressor);
-            }
-            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);
-                }
+                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") {
index a63671c..86c0931 100644 (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;
             }
index 648f649..c0b7712 100644 (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"
+}