fix corner cases in `properties` (#3189)
authorAlex Lam S.L <alexlamsl@gmail.com>
Tue, 19 Jun 2018 10:20:11 +0000 (18:20 +0800)
committerGitHub <noreply@github.com>
Tue, 19 Jun 2018 10:20:11 +0000 (18:20 +0800)
fixes #3188

lib/compress.js
test/compress/properties.js

index ad01e48..56c8fc4 100644 (file)
@@ -6171,6 +6171,16 @@ merge(Compressor.prototype, {
         });
     });
 
+    function safe_to_flatten(value, compressor) {
+        if (value instanceof AST_SymbolRef) {
+            value = value.fixed_value();
+        }
+        if (!value) return false;
+        return !(value instanceof AST_Lambda)
+            || compressor.parent() instanceof AST_New
+            || !value.contains_this();
+    }
+
     OPT(AST_Sub, function(self, compressor) {
         var expr = self.expression;
         var prop = self.property;
@@ -6210,7 +6220,8 @@ merge(Compressor.prototype, {
             && prop instanceof AST_Number && expr instanceof AST_Array) {
             var index = prop.getValue();
             var elements = expr.elements;
-            if (index in elements) {
+            var retValue = elements[index];
+            if (safe_to_flatten(retValue, compressor)) {
                 var flatten = true;
                 var values = [];
                 for (var i = elements.length; --i > index;) {
@@ -6220,7 +6231,6 @@ merge(Compressor.prototype, {
                         if (flatten && value.has_side_effects(compressor)) flatten = false;
                     }
                 }
-                var retValue = elements[index];
                 retValue = retValue instanceof AST_Hole ? make_node(AST_Undefined, retValue) : retValue;
                 if (!flatten) values.unshift(retValue);
                 while (--i >= 0) {
@@ -6296,10 +6306,7 @@ merge(Compressor.prototype, {
                     if (!all(props, function(prop) {
                         return prop instanceof AST_ObjectKeyVal;
                     })) break;
-                    var value = prop.value;
-                    if (value instanceof AST_Function
-                        && !(compressor.parent() instanceof AST_New)
-                        && value.contains_this()) break;
+                    if (!safe_to_flatten(prop.value, compressor)) break;
                     return make_node(AST_Sub, this, {
                         expression: make_node(AST_Array, expr, {
                             elements: props.map(function(prop) {
index efe0d49..d36ae07 100644 (file)
@@ -1729,3 +1729,106 @@ issue_869_2: {
     }
     expect_stdout: "PASS"
 }
+
+issue_3188_1: {
+    options = {
+        collapse_vars: true,
+        inline: true,
+        properties: true,
+        reduce_vars: true,
+        side_effects: true,
+    }
+    input: {
+        (function() {
+            function f() {
+                console.log(this.p);
+            }
+            (function() {
+                var o = {
+                    p: "PASS",
+                    f: f
+                };
+                o.f();
+            })();
+        })();
+    }
+    expect: {
+        (function() {
+            function f() {
+                console.log(this.p);
+            }
+            ({
+                p: "PASS",
+                f: f
+            }).f();
+            var o;
+        })();
+    }
+    expect_stdout: "PASS"
+}
+
+issue_3188_2: {
+    options = {
+        collapse_vars: true,
+        inline: true,
+        properties: true,
+        reduce_vars: true,
+        side_effects: true,
+        unused: true,
+    }
+    input: {
+        (function() {
+            var f = function() {
+                console.log(this.p);
+            };
+            function g() {
+                var o = {
+                    p: "PASS",
+                    f: f
+                };
+                o.f();
+            }
+            g();
+        })();
+    }
+    expect: {
+        ({
+            p: "PASS",
+            f: function() {
+                console.log(this.p);
+            }
+        }).f();
+    }
+    expect_stdout: "PASS"
+}
+
+issue_3188_3: {
+    options = {
+        collapse_vars: true,
+        inline: true,
+        properties: true,
+        reduce_vars: true,
+        side_effects: true,
+    }
+    input: {
+        (function() {
+            function f() {
+                console.log(this[0]);
+            }
+            (function() {
+                var o = ["PASS", f];
+                o[1]();
+            })();
+        })();
+    }
+    expect: {
+        (function() {
+            function f() {
+                console.log(this[0]);
+            }
+            ["PASS", f][1]();
+            var o;
+        })();
+    }
+    expect_stdout: "PASS"
+}