enhance `unsafe` for `Array` (#3349)
authorAlex Lam S.L <alexlamsl@gmail.com>
Tue, 19 Mar 2019 22:37:51 +0000 (06:37 +0800)
committerGitHub <noreply@github.com>
Tue, 19 Mar 2019 22:37:51 +0000 (06:37 +0800)
lib/compress.js
test/compress/arrays.js
test/compress/reduce_vars.js

index 4e27652..72f8e63 100644 (file)
@@ -4003,17 +4003,17 @@ merge(Compressor.prototype, {
             return this;
         });
         def(AST_Binary, function(compressor, first_in_statement) {
-            var right = this.right.drop_side_effect_free(compressor);
+            var right = this.right.drop_side_effect_free(compressor, first_in_statement);
             if (!right) return this.left.drop_side_effect_free(compressor, first_in_statement);
             if (lazy_op[this.operator]) {
                 if (right === this.right) return this;
                 var node = this.clone();
-                node.right = right;
+                node.right = right.drop_side_effect_free(compressor);
                 return node;
             } else {
                 var left = this.left.drop_side_effect_free(compressor, first_in_statement);
-                if (!left) return this.right.drop_side_effect_free(compressor, first_in_statement);
-                return make_sequence(this, [ left, right ]);
+                if (!left) return right;
+                return make_sequence(this, [ left, right.drop_side_effect_free(compressor) ]);
             }
         });
         def(AST_Call, function(compressor, first_in_statement) {
@@ -4666,12 +4666,30 @@ merge(Compressor.prototype, {
         if (compressor.option("unsafe")) {
             if (is_undeclared_ref(exp)) switch (exp.name) {
               case "Array":
-                if (self.args.length != 1) {
-                    return make_node(AST_Array, self, {
-                        elements: self.args
-                    }).optimize(compressor);
+                if (self.args.length == 1) {
+                    var first = self.args[0];
+                    if (first instanceof AST_Number) try {
+                        var length = first.getValue();
+                        if (length > 6) break;
+                        var elements = Array(length);
+                        for (var i = 0; i < length; i++) elements[i] = make_node(AST_Hole, self);
+                        return make_node(AST_Array, self, {
+                            elements: elements
+                        });
+                    } catch (ex) {
+                        compressor.warn("Invalid array length: {length} [{file}:{line},{col}]", {
+                            length: length,
+                            file: self.start.file,
+                            line: self.start.line,
+                            col: self.start.col
+                        });
+                        break;
+                    }
+                    if (!first.is_boolean(compressor) && !first.is_string(compressor)) break;
                 }
-                break;
+                return make_node(AST_Array, self, {
+                    elements: self.args
+                });
               case "Object":
                 if (self.args.length == 0) {
                     return make_node(AST_Object, self, {
index 3629220..497e96c 100644 (file)
@@ -239,3 +239,113 @@ index_length: {
     }
     expect_stdout: "1 2"
 }
+
+constructor_bad: {
+    options = {
+        unsafe: true
+    }
+    input: {
+        try {
+            Array(NaN);
+            console.log("FAIL1");
+        } catch (ex) {
+            try {
+                new Array(NaN);
+                console.log("FAIL2");
+            } catch (ex) {
+                console.log("PASS");
+            }
+        }
+        try {
+            Array(3.14);
+            console.log("FAIL1");
+        } catch (ex) {
+            try {
+                new Array(3.14);
+                console.log("FAIL2");
+            } catch (ex) {
+                console.log("PASS");
+            }
+        }
+    }
+    expect: {
+        try {
+            Array(NaN);
+            console.log("FAIL1");
+        } catch (ex) {
+            try {
+                Array(NaN);
+                console.log("FAIL2");
+            } catch (ex) {
+                console.log("PASS");
+            }
+        }
+        try {
+            Array(3.14);
+            console.log("FAIL1");
+        } catch (ex) {
+            try {
+                Array(3.14);
+                console.log("FAIL2");
+            } catch (ex) {
+                console.log("PASS");
+            }
+        }
+    }
+    expect_stdout: [
+        "PASS",
+        "PASS",
+    ]
+    expect_warnings: [
+        "WARN: Invalid array length: 3.14 [test/compress/arrays.js:13,12]",
+        "WARN: Invalid array length: 3.14 [test/compress/arrays.js:17,16]",
+    ]
+}
+
+constructor_good: {
+    options = {
+        unsafe: true
+    }
+    input: {
+        console.log(Array());
+        console.log(Array(0));
+        console.log(Array(1));
+        console.log(Array(6));
+        console.log(Array(7));
+        console.log(Array(1, 2));
+        console.log(Array(false));
+        console.log(Array("foo"));
+        console.log(Array(Array));
+        console.log(new Array());
+        console.log(new Array(0));
+        console.log(new Array(1));
+        console.log(new Array(6));
+        console.log(new Array(7));
+        console.log(new Array(1, 2));
+        console.log(new Array(false));
+        console.log(new Array("foo"));
+        console.log(new Array(Array));
+    }
+    expect: {
+        console.log([]);
+        console.log([]);
+        console.log([,]);
+        console.log([,,,,,,]);
+        console.log(Array(7));
+        console.log([ 1, 2 ]);
+        console.log([ false ]);
+        console.log([ "foo" ]);
+        console.log(Array(Array));
+        console.log([]);
+        console.log([]);
+        console.log([,]);
+        console.log([,,,,,,]);
+        console.log(Array(7));
+        console.log([ 1, 2 ]);
+        console.log([ false ]);
+        console.log([ "foo" ]);
+        console.log(Array(Array));
+    }
+    expect_stdout: true
+    expect_warnings: []
+}
index 27e5345..fb5038b 100644 (file)
@@ -6716,3 +6716,24 @@ issue_3297: {
     }
     expect_stdout: "true"
 }
+
+drop_side_effect_free: {
+    options = {
+        collapse_vars: true,
+        evaluate: true,
+        reduce_vars: true,
+        side_effects: true,
+        toplevel: true,
+    }
+    input: {
+        var a = 123;
+        "" + (a && (a.b = 0) || a);
+        console.log(a);
+    }
+    expect: {
+        var a = 123;
+        a.b = 0;
+        console.log(a);
+    }
+    expect_stdout: "123"
+}