support spread syntax (#4328)
This commit is contained in:
371
test/compress/spread.js
Normal file
371
test/compress/spread.js
Normal file
@@ -0,0 +1,371 @@
|
||||
collapse_vars_1: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
input: {
|
||||
var a;
|
||||
[ ...a = "PASS", "PASS"].slice();
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
var a;
|
||||
[ ...a = "PASS", "PASS"].slice();
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
collapse_vars_2: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
input: {
|
||||
var a = "FAIL";
|
||||
try {
|
||||
a = "PASS";
|
||||
[ ...42, "PASS"].slice();
|
||||
} catch (e) {
|
||||
console.log(a);
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
var a = "FAIL";
|
||||
try {
|
||||
a = "PASS";
|
||||
[ ...42, "PASS"].slice();
|
||||
} catch (e) {
|
||||
console.log(a);
|
||||
}
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
collapse_vars_3: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
input: {
|
||||
var a = "FAIL";
|
||||
try {
|
||||
[ ...(a = "PASS", 42), "PASS"].slice();
|
||||
} catch (e) {
|
||||
console.log(a);
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
var a = "FAIL";
|
||||
try {
|
||||
[ ...(a = "PASS", 42), "PASS"].slice();
|
||||
} catch (e) {
|
||||
console.log(a);
|
||||
}
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
collapse_vars_4: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function(a) {
|
||||
return a;
|
||||
}(...[ "PASS", "FAIL" ]));
|
||||
}
|
||||
expect: {
|
||||
console.log(function(a) {
|
||||
return a;
|
||||
}(...[ "PASS", "FAIL" ]));
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
dont_inline: {
|
||||
options = {
|
||||
inline: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function(a) {
|
||||
return a;
|
||||
}(...[ "PASS", "FAIL" ]));
|
||||
}
|
||||
expect: {
|
||||
console.log(function(a) {
|
||||
return a;
|
||||
}(...[ "PASS", "FAIL" ]));
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
do_inline: {
|
||||
options = {
|
||||
properties: true,
|
||||
inline: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function(a) {
|
||||
return a;
|
||||
}(...[ "PASS", "FAIL" ]));
|
||||
}
|
||||
expect: {
|
||||
console.log(("FAIL", "PASS"));
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
drop_empty_call_1: {
|
||||
options = {
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
try {
|
||||
(function() {})(...null);
|
||||
} catch (e) {
|
||||
console.log("PASS");
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
try {
|
||||
[ ...null ];
|
||||
} catch (e) {
|
||||
console.log("PASS");
|
||||
}
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
drop_empty_call_2: {
|
||||
options = {
|
||||
properties: true,
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
(function() {})(...[ console.log("PASS") ]);
|
||||
}
|
||||
expect: {
|
||||
console.log("PASS");
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
convert_hole: {
|
||||
options = {
|
||||
properties: true,
|
||||
}
|
||||
input: {
|
||||
console.log(...[ "PASS", , 42 ]);
|
||||
}
|
||||
expect: {
|
||||
console.log("PASS", void 0, 42);
|
||||
}
|
||||
expect_stdout: "PASS undefined 42"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
keep_property_access: {
|
||||
options = {
|
||||
properties: true,
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function() {
|
||||
return [ ..."foo" ][0];
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
console.log(function() {
|
||||
return [ ..."foo" ][0];
|
||||
}());
|
||||
}
|
||||
expect_stdout: "f"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
keep_fargs: {
|
||||
options = {
|
||||
keep_fargs: "strict",
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = [ "PASS" ];
|
||||
(function(b, c) {
|
||||
console.log(c);
|
||||
})(console, ...a);
|
||||
}
|
||||
expect: {
|
||||
var a = [ "PASS" ];
|
||||
(function(b, c) {
|
||||
console.log(c);
|
||||
})(console, ...a);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
reduce_vars_1: {
|
||||
options = {
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function(b, c) {
|
||||
return c ? "PASS" : "FAIL";
|
||||
}(..."foo"));
|
||||
}
|
||||
expect: {
|
||||
console.log(function(b, c) {
|
||||
return c ? "PASS" : "FAIL";
|
||||
}(..."foo"));
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
reduce_vars_2: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function(b, c) {
|
||||
return c ? "PASS" : "FAIL";
|
||||
}(..."foo"));
|
||||
}
|
||||
expect: {
|
||||
console.log(function(b, c) {
|
||||
return c ? "PASS" : "FAIL";
|
||||
}(..."foo"));
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
drop_object: {
|
||||
options = {
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
({ ...console.log("PASS") });
|
||||
}
|
||||
expect: {
|
||||
console.log("PASS");
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
keep_getter: {
|
||||
options = {
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
({
|
||||
...{
|
||||
get p() {
|
||||
console.log("PASS");
|
||||
},
|
||||
},
|
||||
get q() {
|
||||
console.log("FAIL");
|
||||
},
|
||||
});
|
||||
}
|
||||
expect: {
|
||||
({
|
||||
...{
|
||||
get p() {
|
||||
console.log("PASS");
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
keep_accessor: {
|
||||
options = {
|
||||
properties: true,
|
||||
}
|
||||
input: {
|
||||
var o = {
|
||||
...{
|
||||
get p() {
|
||||
console.log("GET");
|
||||
return this.r;
|
||||
},
|
||||
set q(v) {
|
||||
console.log("SET", v);
|
||||
},
|
||||
r: 42,
|
||||
},
|
||||
r: null,
|
||||
};
|
||||
for (var k in o)
|
||||
console.log(k, o[k]);
|
||||
}
|
||||
expect: {
|
||||
var o = {
|
||||
...{
|
||||
get p() {
|
||||
console.log("GET");
|
||||
return this.r;
|
||||
},
|
||||
set q(v) {
|
||||
console.log("SET", v);
|
||||
},
|
||||
r: 42,
|
||||
},
|
||||
r: null,
|
||||
};
|
||||
for (var k in o)
|
||||
console.log(k, o[k]);
|
||||
}
|
||||
expect_stdout: [
|
||||
"GET",
|
||||
"p 42",
|
||||
"q undefined",
|
||||
"r null",
|
||||
]
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
unused_var_side_effects: {
|
||||
options = {
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function f(a) {
|
||||
var b = {
|
||||
...a,
|
||||
};
|
||||
})({
|
||||
get p() {
|
||||
console.log("PASS");
|
||||
},
|
||||
});
|
||||
}
|
||||
expect: {
|
||||
(function(a) {
|
||||
({
|
||||
...a,
|
||||
});
|
||||
})({
|
||||
get p() {
|
||||
console.log("PASS");
|
||||
},
|
||||
});
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=8"
|
||||
}
|
||||
@@ -135,7 +135,7 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
||||
if (expr && !(expr instanceof U.AST_Hole)) {
|
||||
node.start._permute++;
|
||||
CHANGED = true;
|
||||
return expr;
|
||||
return expr instanceof U.AST_Spread ? expr.expression : expr;
|
||||
}
|
||||
}
|
||||
else if (node instanceof U.AST_Binary) {
|
||||
@@ -164,7 +164,7 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
||||
][ ((node.start._permute += step) * steps | 0) % 3 ];
|
||||
if (expr) {
|
||||
CHANGED = true;
|
||||
return expr;
|
||||
return expr instanceof U.AST_Spread ? expr.expression : expr;
|
||||
}
|
||||
if (node.expression instanceof U.AST_Function) {
|
||||
// hoist and return expressions from the IIFE function expression
|
||||
@@ -381,9 +381,8 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
||||
}
|
||||
|
||||
if (in_list) {
|
||||
// special case to drop object properties and switch branches
|
||||
if (parent instanceof U.AST_Object
|
||||
|| parent instanceof U.AST_Switch && parent.expression != node) {
|
||||
// drop switch branches
|
||||
if (parent instanceof U.AST_Switch && parent.expression != node) {
|
||||
node.start._permute++;
|
||||
CHANGED = true;
|
||||
return List.skip;
|
||||
@@ -404,7 +403,9 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
||||
}
|
||||
|
||||
// skip element/property from (destructured) array/object
|
||||
if (parent instanceof U.AST_Array || parent instanceof U.AST_Destructured || parent instanceof AST_Object) {
|
||||
if (parent instanceof U.AST_Array
|
||||
|| parent instanceof U.AST_Destructured
|
||||
|| parent instanceof U.AST_Object) {
|
||||
node.start._permute++;
|
||||
CHANGED = true;
|
||||
return List.skip;
|
||||
|
||||
@@ -371,9 +371,24 @@ function createParams(noDuplicate) {
|
||||
}
|
||||
|
||||
function createArgs(recurmax, stmtDepth, canThrow) {
|
||||
recurmax--;
|
||||
var args = [];
|
||||
for (var n = rng(4); --n >= 0;) {
|
||||
args.push(rng(2) ? createValue() : createExpression(recurmax - 1, COMMA_OK, stmtDepth, canThrow));
|
||||
for (var n = rng(4); --n >= 0;) switch (rng(50)) {
|
||||
case 0:
|
||||
case 1:
|
||||
var name = getVarName();
|
||||
if (canThrow && rng(8) === 0) {
|
||||
args.push("..." + name);
|
||||
} else {
|
||||
args.push('...("" + ' + name + ")");
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
args.push("..." + createArrayLiteral(recurmax, stmtDepth, canThrow));
|
||||
break;
|
||||
default:
|
||||
args.push(rng(2) ? createValue() : createExpression(recurmax, COMMA_OK, stmtDepth, canThrow));
|
||||
break;
|
||||
}
|
||||
return args.join(", ");
|
||||
}
|
||||
@@ -1044,13 +1059,30 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
|
||||
|
||||
function createArrayLiteral(recurmax, stmtDepth, canThrow) {
|
||||
recurmax--;
|
||||
var arr = "[";
|
||||
for (var i = rng(6); --i >= 0;) {
|
||||
var arr = [];
|
||||
for (var i = rng(6); --i >= 0;) switch (rng(50)) {
|
||||
case 0:
|
||||
case 1:
|
||||
// in rare cases produce an array hole element
|
||||
var element = rng(20) ? createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) : "";
|
||||
arr += element + ", ";
|
||||
arr.push("");
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
var name = getVarName();
|
||||
if (canThrow && rng(8) === 0) {
|
||||
arr.push("..." + name);
|
||||
} else {
|
||||
arr.push('...("" + ' + name + ")");
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
arr.push("..." + createArrayLiteral(recurmax, stmtDepth, canThrow));
|
||||
break;
|
||||
default:
|
||||
arr.push(createExpression(recurmax, COMMA_OK, stmtDepth, canThrow));
|
||||
break;
|
||||
}
|
||||
return arr + "]";
|
||||
return "[" + arr.join(", ") + "]";
|
||||
}
|
||||
|
||||
var SAFE_KEYS = [
|
||||
@@ -1135,13 +1167,20 @@ function createObjectFunction(recurmax, stmtDepth, canThrow) {
|
||||
function createObjectLiteral(recurmax, stmtDepth, canThrow) {
|
||||
recurmax--;
|
||||
var obj = ["({"];
|
||||
for (var i = rng(6); --i >= 0;) switch (rng(30)) {
|
||||
for (var i = rng(6); --i >= 0;) switch (rng(50)) {
|
||||
case 0:
|
||||
obj.push(createObjectFunction(recurmax, stmtDepth, canThrow));
|
||||
break;
|
||||
case 1:
|
||||
obj.push(getVarName() + ",");
|
||||
break;
|
||||
case 2:
|
||||
obj.push(createObjectFunction(recurmax, stmtDepth, canThrow));
|
||||
break;
|
||||
case 3:
|
||||
obj.push("..." + getVarName() + ",");
|
||||
break;
|
||||
case 4:
|
||||
obj.push("..." + createObjectLiteral(recurmax, stmtDepth, canThrow) + ",");
|
||||
break;
|
||||
default:
|
||||
obj.push(createObjectKey(recurmax, stmtDepth, canThrow) + ":(" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + "),");
|
||||
break;
|
||||
@@ -1591,6 +1630,9 @@ function patch_try_catch(orig, toplevel) {
|
||||
} else if (result.name == "TypeError" && /'in'/.test(result.message)) {
|
||||
index = result.ufuzz_catch;
|
||||
return orig.slice(0, index) + result.ufuzz_var + ' = new Error("invalid `in`");' + orig.slice(index);
|
||||
} else if (result.name == "TypeError" && /not iterable/.test(result.message)) {
|
||||
index = result.ufuzz_catch;
|
||||
return orig.slice(0, index) + result.ufuzz_var + ' = new Error("spread not iterable");' + orig.slice(index);
|
||||
} else if (result.name == "RangeError" && result.message == "Maximum call stack size exceeded") {
|
||||
index = result.ufuzz_try;
|
||||
return orig.slice(0, index) + 'throw new Error("skipping infinite recursion");' + orig.slice(index);
|
||||
@@ -1656,6 +1698,7 @@ for (var round = 1; round <= num_iterations; round++) {
|
||||
ok = sandbox.same_stdout(orig_result[toplevel ? 3 : 2], uglify_result);
|
||||
}
|
||||
// ignore difference in error message caused by `in`
|
||||
// ignore difference in error message caused by spread syntax
|
||||
// ignore difference in depth of termination caused by infinite recursion
|
||||
if (!ok) {
|
||||
var orig_skipped = patch_try_catch(original_code, toplevel);
|
||||
|
||||
Reference in New Issue
Block a user