Diff
Modified: trunk/LayoutTests/ChangeLog (196733 => 196734)
--- trunk/LayoutTests/ChangeLog 2016-02-18 01:05:56 UTC (rev 196733)
+++ trunk/LayoutTests/ChangeLog 2016-02-18 01:17:36 UTC (rev 196734)
@@ -1,3 +1,22 @@
+2016-02-17 Keith Miller <[email protected]>
+
+ Spread operator should be allowed when not the first argument of parameter list
+ https://bugs.webkit.org/show_bug.cgi?id=152721
+
+ Reviewed by Saam Barati.
+
+ Update tests with new semantics of spread calling. Additionally,
+ adjust benchmarks to run in a more reasonable time now that
+ spread is implemented correctly.
+
+ * js/basic-spread-expected.txt:
+ * js/parser-syntax-check-expected.txt:
+ * js/regress/script-tests/deltablue-varargs.js:
+ (deltaBlue):
+ * js/regress/script-tests/varargs-construct.js:
+ * js/script-tests/basic-spread.js:
+ * js/script-tests/parser-syntax-check.js:
+
2016-02-17 Ryan Haddad <[email protected]>
Add ios-simulator baseline for new W3C HTML tests added with r196710
Modified: trunk/LayoutTests/js/basic-spread-expected.txt (196733 => 196734)
--- trunk/LayoutTests/js/basic-spread-expected.txt 2016-02-18 01:05:56 UTC (rev 196733)
+++ trunk/LayoutTests/js/basic-spread-expected.txt 2016-02-18 01:17:36 UTC (rev 196734)
@@ -43,46 +43,6 @@
PASS args[1] is undefined
PASS args[2] is null
PASS args[3] is 4
-PASS passedThis is o
-PASS args[0] is 1
-PASS args[1] is undefined
-PASS args[2] is null
-PASS args[3] is 4
-PASS passedThis is o
-PASS args[0] is 1
-PASS args[1] is undefined
-PASS args[2] is null
-PASS args[3] is 4
-PASS passedThis is o
-PASS args[0] is 1
-PASS args[1] is undefined
-PASS args[2] is null
-PASS args[3] is 4
-PASS passedThis is o
-PASS args[0] is 1
-PASS args[1] is undefined
-PASS args[2] is null
-PASS args[3] is 4
-PASS passedThis is o
-PASS args[0] is 1
-PASS args[1] is undefined
-PASS args[2] is null
-PASS args[3] is 4
-PASS passedThis is o
-PASS args[0] is 1
-PASS args[1] is undefined
-PASS args[2] is null
-PASS args[3] is 4
-PASS passedThis is o
-PASS args[0] is 1
-PASS args[1] is undefined
-PASS args[2] is null
-PASS args[3] is 4
-PASS passedThis is o
-PASS args[0] is 1
-PASS args[1] is undefined
-PASS args[2] is null
-PASS args[3] is 4
PASS a is [1,2,3]
PASS [...a] is [1,2,3]
PASS [...a] is [1,2,3]
Modified: trunk/LayoutTests/js/parser-syntax-check-expected.txt (196733 => 196734)
--- trunk/LayoutTests/js/parser-syntax-check-expected.txt 2016-02-18 01:05:56 UTC (rev 196733)
+++ trunk/LayoutTests/js/parser-syntax-check-expected.txt 2016-02-18 01:17:36 UTC (rev 196734)
@@ -757,18 +757,18 @@
PASS Invalid: "function f() { o.foo(bar...) }"
PASS Invalid: "o[foo](bar...)"
PASS Invalid: "function f() { o[foo](bar...) }"
-PASS Invalid: "foo(a,...bar)"
-PASS Invalid: "function f() { foo(a,...bar) }"
-PASS Invalid: "o.foo(a,...bar)"
-PASS Invalid: "function f() { o.foo(a,...bar) }"
-PASS Invalid: "o[foo](a,...bar)"
-PASS Invalid: "function f() { o[foo](a,...bar) }"
-PASS Invalid: "foo(...bar, a)"
-PASS Invalid: "function f() { foo(...bar, a) }"
-PASS Invalid: "o.foo(...bar, a)"
-PASS Invalid: "function f() { o.foo(...bar, a) }"
-PASS Invalid: "o[foo](...bar, a)"
-PASS Invalid: "function f() { o[foo](...bar, a) }"
+PASS Valid: "foo(a,...bar)" with ReferenceError
+PASS Valid: "function f() { foo(a,...bar) }"
+PASS Valid: "o.foo(a,...bar)" with ReferenceError
+PASS Valid: "function f() { o.foo(a,...bar) }"
+PASS Valid: "o[foo](a,...bar)" with ReferenceError
+PASS Valid: "function f() { o[foo](a,...bar) }"
+PASS Valid: "foo(...bar, a)" with ReferenceError
+PASS Valid: "function f() { foo(...bar, a) }"
+PASS Valid: "o.foo(...bar, a)" with ReferenceError
+PASS Valid: "function f() { o.foo(...bar, a) }"
+PASS Valid: "o[foo](...bar, a)" with ReferenceError
+PASS Valid: "function f() { o[foo](...bar, a) }"
PASS Valid: "[...bar]" with ReferenceError
PASS Valid: "function f() { [...bar] }"
PASS Valid: "[a, ...bar]" with ReferenceError
Modified: trunk/LayoutTests/js/regress/script-tests/deltablue-varargs.js (196733 => 196734)
--- trunk/LayoutTests/js/regress/script-tests/deltablue-varargs.js 2016-02-18 01:05:56 UTC (rev 196733)
+++ trunk/LayoutTests/js/regress/script-tests/deltablue-varargs.js 2016-02-18 01:17:36 UTC (rev 196734)
@@ -880,9 +880,9 @@
var planner = null;
function deltaBlue() {
- chainTest(...args(100));
- projectionTest(...args(100));
+ chainTest(...args(25));
+ projectionTest(...args(25));
}
-for (var i = 0; i < 30; ++i)
+for (var i = 0; i < 5; ++i)
deltaBlue(...args());
Modified: trunk/LayoutTests/js/regress/script-tests/varargs-construct.js (196733 => 196734)
--- trunk/LayoutTests/js/regress/script-tests/varargs-construct.js 2016-02-18 01:05:56 UTC (rev 196733)
+++ trunk/LayoutTests/js/regress/script-tests/varargs-construct.js 2016-02-18 01:17:36 UTC (rev 196734)
@@ -14,7 +14,7 @@
noInline(bar);
-for (var i = 0; i < 1000000; ++i) {
+for (var i = 0; i < 100000; ++i) {
var result = bar(1, 2);
if (result.f != 1)
throw "Error: bad result.f: " + result.f;
Modified: trunk/LayoutTests/js/script-tests/basic-spread.js (196733 => 196734)
--- trunk/LayoutTests/js/script-tests/basic-spread.js 2016-02-18 01:05:56 UTC (rev 196733)
+++ trunk/LayoutTests/js/script-tests/basic-spread.js 2016-02-18 01:17:36 UTC (rev 196734)
@@ -17,18 +17,12 @@
o.f = f;
var test1 = [1, undefined, null, 4]
var test2 = [1, , null, 4]
-var test3 = {length: 4, 0: 1, 2: null, 3: 4}
-var test4 = {length: 4, 0: 1, 1: undefined, 2: null, 3: 4}
o.f(...test1)
o.f(...test2)
-o.f(...test3)
-o.f(...test4)
var h=eval('"f"')
o[h](...test1)
o[h](...test2)
-o[h](...test3)
-o[h](...test4)
function g()
{
@@ -37,13 +31,9 @@
g.apply(null, test1)
g.apply(null, test2)
-g.apply(null, test3)
-g.apply(null, test4)
g(...test1)
g(...test2)
-g(...test3)
-g(...test4)
var a=[1,2,3]
Modified: trunk/LayoutTests/js/script-tests/parser-syntax-check.js (196733 => 196734)
--- trunk/LayoutTests/js/script-tests/parser-syntax-check.js 2016-02-18 01:05:56 UTC (rev 196733)
+++ trunk/LayoutTests/js/script-tests/parser-syntax-check.js 2016-02-18 01:17:36 UTC (rev 196734)
@@ -471,12 +471,12 @@
invalid("foo(bar...)")
invalid("o.foo(bar...)")
invalid("o[foo](bar...)")
-invalid("foo(a,...bar)")
-invalid("o.foo(a,...bar)")
-invalid("o[foo](a,...bar)")
-invalid("foo(...bar, a)")
-invalid("o.foo(...bar, a)")
-invalid("o[foo](...bar, a)")
+valid("foo(a,...bar)")
+valid("o.foo(a,...bar)")
+valid("o[foo](a,...bar)")
+valid("foo(...bar, a)")
+valid("o.foo(...bar, a)")
+valid("o[foo](...bar, a)")
valid("[...bar]")
valid("[a, ...bar]")
valid("[...bar, a]")
Modified: trunk/Source/_javascript_Core/ChangeLog (196733 => 196734)
--- trunk/Source/_javascript_Core/ChangeLog 2016-02-18 01:05:56 UTC (rev 196733)
+++ trunk/Source/_javascript_Core/ChangeLog 2016-02-18 01:17:36 UTC (rev 196734)
@@ -1,3 +1,44 @@
+2016-02-17 Keith Miller <[email protected]>
+
+ Spread operator should be allowed when not the first argument of parameter list
+ https://bugs.webkit.org/show_bug.cgi?id=152721
+
+ Reviewed by Saam Barati.
+
+ Spread arguments to functions should now be ES6 compliant. Before we
+ would only take a spread operator if it was the sole argument to a
+ function. Additionally, we would not use the Symbol.iterator on the
+ object to generate the arguments. Instead we would do a loop up to the
+ length mapping indexed properties to the corresponding argument. We fix
+ both these issues by doing an AST transformation from foo(...a, b, ...c, d)
+ to foo(...[...a, b, ...c, d]) (where the spread on the rhs uses the
+ old spread semantics). This solution has the downside of requiring the
+ allocation of another object and copying each element twice but avoids a
+ large change to the vm calling convention.
+
+ * interpreter/Interpreter.cpp:
+ (JSC::loadVarargs):
+ * parser/ASTBuilder.h:
+ (JSC::ASTBuilder::createElementList):
+ * parser/Parser.cpp:
+ (JSC::Parser<LexerType>::parseArguments):
+ (JSC::Parser<LexerType>::parseArgument):
+ (JSC::Parser<LexerType>::parseMemberExpression):
+ * parser/Parser.h:
+ * parser/SyntaxChecker.h:
+ (JSC::SyntaxChecker::createElementList):
+ * tests/es6.yaml:
+ * tests/stress/spread-calling.js: Added.
+ (testFunction):
+ (testEmpty):
+ (makeObject):
+ (otherIterator.return.next):
+ (otherIterator):
+ (totalIter):
+ (throwingIter.return.next):
+ (throwingIter):
+ (i.catch):
+
2016-02-17 Brian Burg <[email protected]>
Remove a wrong cast in RemoteInspector::receivedSetupMessage
Modified: trunk/Source/_javascript_Core/interpreter/Interpreter.cpp (196733 => 196734)
--- trunk/Source/_javascript_Core/interpreter/Interpreter.cpp 2016-02-18 01:05:56 UTC (rev 196733)
+++ trunk/Source/_javascript_Core/interpreter/Interpreter.cpp 2016-02-18 01:17:36 UTC (rev 196734)
@@ -247,7 +247,7 @@
void loadVarargs(CallFrame* callFrame, VirtualRegister firstElementDest, JSValue arguments, uint32_t offset, uint32_t length)
{
- if (UNLIKELY(!arguments.isCell()))
+ if (UNLIKELY(!arguments.isCell()) || !length)
return;
JSCell* cell = arguments.asCell();
Modified: trunk/Source/_javascript_Core/parser/ASTBuilder.h (196733 => 196734)
--- trunk/Source/_javascript_Core/parser/ASTBuilder.h 2016-02-18 01:05:56 UTC (rev 196733)
+++ trunk/Source/_javascript_Core/parser/ASTBuilder.h 2016-02-18 01:17:36 UTC (rev 196734)
@@ -441,6 +441,17 @@
ElementNode* createElementList(int elisions, ExpressionNode* expr) { return new (m_parserArena) ElementNode(elisions, expr); }
ElementNode* createElementList(ElementNode* elems, int elisions, ExpressionNode* expr) { return new (m_parserArena) ElementNode(elems, elisions, expr); }
+ ElementNode* createElementList(ArgumentListNode* elems)
+ {
+ ElementNode* head = new (m_parserArena) ElementNode(0, elems->m_expr);
+ ElementNode* tail = head;
+ elems = elems->m_next;
+ while (elems) {
+ tail = new (m_parserArena) ElementNode(tail, 0, elems->m_expr);
+ elems = elems->m_next;
+ }
+ return head;
+ }
FormalParameterList createFormalParameterList() { return new (m_parserArena) FunctionParameters(); }
void appendParameter(FormalParameterList list, DestructuringPattern pattern, ExpressionNode* defaultValue)
Modified: trunk/Source/_javascript_Core/parser/Parser.cpp (196733 => 196734)
--- trunk/Source/_javascript_Core/parser/Parser.cpp 2016-02-18 01:05:56 UTC (rev 196733)
+++ trunk/Source/_javascript_Core/parser/Parser.cpp 2016-02-18 01:17:36 UTC (rev 196734)
@@ -3703,7 +3703,7 @@
}
template <typename LexerType>
-template <class TreeBuilder> TreeArguments Parser<LexerType>::parseArguments(TreeBuilder& context, SpreadMode mode)
+template <class TreeBuilder> TreeArguments Parser<LexerType>::parseArguments(TreeBuilder& context)
{
consumeOrFailWithFlags(OPENPAREN, TreeBuilder::DontBuildStrings, "Expected opening '(' at start of argument list");
JSTokenLocation location(tokenLocation());
@@ -3711,42 +3711,63 @@
next(TreeBuilder::DontBuildStrings);
return context.createArguments();
}
- if (match(DOTDOTDOT) && mode == AllowSpread) {
- JSTokenLocation spreadLocation(tokenLocation());
- auto start = m_token.m_startPosition;
- auto divot = m_token.m_endPosition;
- next();
- auto spreadExpr = parseAssignmentExpression(context);
- auto end = m_lastTokenEndPosition;
- if (!spreadExpr)
- failWithMessage("Cannot parse spread _expression_");
- if (!consume(CLOSEPAREN)) {
- if (match(COMMA))
- semanticFail("Spread operator may only be applied to the last argument passed to a function");
- handleProductionOrFail(CLOSEPAREN, ")", "end", "argument list");
- }
- auto spread = context.createSpreadExpression(spreadLocation, spreadExpr, start, divot, end);
- TreeArgumentsList argList = context.createArgumentsList(location, spread);
- return context.createArguments(argList);
- }
- TreeExpression firstArg = parseAssignmentExpression(context);
+ auto argumentsStart = m_token.m_startPosition;
+ auto argumentsDivot = m_token.m_endPosition;
+
+ ArgumentType argType = ArgumentType::Normal;
+ TreeExpression firstArg = parseArgument(context, argType);
failIfFalse(firstArg, "Cannot parse function argument");
-
+ semanticFailIfTrue(match(DOTDOTDOT), "The '...' operator should come before the target _expression_");
+
+ bool hasSpread = false;
+ if (argType == ArgumentType::Spread)
+ hasSpread = true;
TreeArgumentsList argList = context.createArgumentsList(location, firstArg);
TreeArgumentsList tail = argList;
+
while (match(COMMA)) {
JSTokenLocation argumentLocation(tokenLocation());
next(TreeBuilder::DontBuildStrings);
- TreeExpression arg = parseAssignmentExpression(context);
- failIfFalse(arg, "Cannot parse function argument");
+
+ TreeExpression arg = parseArgument(context, argType);
+ propagateError();
+ semanticFailIfTrue(match(DOTDOTDOT), "The '...' operator should come before the target _expression_");
+
+ if (argType == ArgumentType::Spread)
+ hasSpread = true;
+
tail = context.createArgumentsList(argumentLocation, tail, arg);
}
- semanticFailIfTrue(match(DOTDOTDOT), "The '...' operator should come before the target _expression_");
+
handleProductionOrFail(CLOSEPAREN, ")", "end", "argument list");
+ if (hasSpread) {
+ TreeExpression spreadArray = context.createSpreadExpression(location, context.createArray(location, context.createElementList(argList)), argumentsStart, argumentsDivot, m_lastTokenEndPosition);
+ return context.createArguments(context.createArgumentsList(location, spreadArray));
+ }
+
return context.createArguments(argList);
}
template <typename LexerType>
+template <class TreeBuilder> TreeExpression Parser<LexerType>::parseArgument(TreeBuilder& context, ArgumentType& type)
+{
+ if (UNLIKELY(match(DOTDOTDOT))) {
+ JSTokenLocation spreadLocation(tokenLocation());
+ auto start = m_token.m_startPosition;
+ auto divot = m_token.m_endPosition;
+ next();
+ TreeExpression spreadExpr = parseAssignmentExpression(context);
+ propagateError();
+ auto end = m_lastTokenEndPosition;
+ type = ArgumentType::Spread;
+ return context.createSpreadExpression(spreadLocation, spreadExpr, start, divot, end);
+ }
+
+ type = ArgumentType::Normal;
+ return parseAssignmentExpression(context);
+}
+
+template <typename LexerType>
template <class TreeBuilder> TreeExpression Parser<LexerType>::parseMemberExpression(TreeBuilder& context)
{
TreeExpression base = 0;
@@ -3814,12 +3835,12 @@
if (newCount) {
newCount--;
JSTextPosition expressionEnd = lastTokenEndPosition();
- TreeArguments arguments = parseArguments(context, AllowSpread);
+ TreeArguments arguments = parseArguments(context);
failIfFalse(arguments, "Cannot parse call arguments");
base = context.createNewExpr(location, base, arguments, expressionStart, expressionEnd, lastTokenEndPosition());
} else {
JSTextPosition expressionEnd = lastTokenEndPosition();
- TreeArguments arguments = parseArguments(context, AllowSpread);
+ TreeArguments arguments = parseArguments(context);
failIfFalse(arguments, "Cannot parse call arguments");
if (baseIsSuper)
currentFunctionScope()->setHasDirectSuper();
Modified: trunk/Source/_javascript_Core/parser/Parser.h (196733 => 196734)
--- trunk/Source/_javascript_Core/parser/Parser.h 2016-02-18 01:05:56 UTC (rev 196733)
+++ trunk/Source/_javascript_Core/parser/Parser.h 2016-02-18 01:17:36 UTC (rev 196734)
@@ -677,6 +677,11 @@
unsigned m_index;
};
+enum class ArgumentType {
+ Normal,
+ Spread
+};
+
template <typename LexerType>
class Parser {
WTF_MAKE_NONCOPYABLE(Parser);
@@ -1239,8 +1244,8 @@
template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseObjectLiteral(TreeBuilder&);
template <class TreeBuilder> NEVER_INLINE TreeExpression parseStrictObjectLiteral(TreeBuilder&);
template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseFunctionExpression(TreeBuilder&);
- enum SpreadMode { AllowSpread, DontAllowSpread };
- template <class TreeBuilder> ALWAYS_INLINE TreeArguments parseArguments(TreeBuilder&, SpreadMode);
+ template <class TreeBuilder> ALWAYS_INLINE TreeArguments parseArguments(TreeBuilder&);
+ template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseArgument(TreeBuilder&, ArgumentType&);
template <class TreeBuilder> TreeProperty parseProperty(TreeBuilder&, bool strict);
template <class TreeBuilder> TreeExpression parsePropertyMethod(TreeBuilder& context, const Identifier* methodName, bool isGenerator);
template <class TreeBuilder> TreeProperty parseGetterSetter(TreeBuilder&, bool strict, PropertyNode::Type, unsigned getterOrSetterStartOffset, ConstructorKind = ConstructorKind::None, SuperBinding = SuperBinding::NotNeeded);
Modified: trunk/Source/_javascript_Core/parser/SyntaxChecker.h (196733 => 196734)
--- trunk/Source/_javascript_Core/parser/SyntaxChecker.h 2016-02-18 01:05:56 UTC (rev 196733)
+++ trunk/Source/_javascript_Core/parser/SyntaxChecker.h 2016-02-18 01:17:36 UTC (rev 196734)
@@ -221,6 +221,7 @@
int createPropertyList(const JSTokenLocation&, Property, int) { return PropertyListResult; }
int createElementList(int, int) { return ElementsListResult; }
int createElementList(int, int, int) { return ElementsListResult; }
+ int createElementList(int) { return ElementsListResult; }
int createFormalParameterList() { return FormalParameterListResult; }
void appendParameter(int, DestructuringPattern, int) { }
int createClause(int, int) { return ClauseResult; }
Modified: trunk/Source/_javascript_Core/tests/es6.yaml (196733 => 196734)
--- trunk/Source/_javascript_Core/tests/es6.yaml 2016-02-18 01:05:56 UTC (rev 196733)
+++ trunk/Source/_javascript_Core/tests/es6.yaml 2016-02-18 01:17:36 UTC (rev 196734)
@@ -1113,11 +1113,11 @@
- path: es6/Set_Set[Symbol.species].js
cmd: runES6 :normal
- path: es6/spread_..._operator_with_astral_plane_strings_in_function_calls.js
- cmd: runES6 :fail
+ cmd: runES6 :normal
- path: es6/spread_..._operator_with_generator_instances_in_arrays.js
cmd: runES6 :normal
- path: es6/spread_..._operator_with_generator_instances_in_calls.js
- cmd: runES6 :fail
+ cmd: runES6 :normal
- path: es6/spread_..._operator_with_generic_iterables_in_arrays.js
cmd: runES6 :fail
- path: es6/spread_..._operator_with_generic_iterables_in_calls.js
@@ -1127,7 +1127,7 @@
- path: es6/spread_..._operator_with_instances_of_iterables_in_calls.js
cmd: runES6 :fail
- path: es6/spread_..._operator_with_strings_in_function_calls.js
- cmd: runES6 :fail
+ cmd: runES6 :normal
- path: es6/typed_arrays_%TypedArray%.from.js
cmd: runES6 :normal
- path: es6/typed_arrays_%TypedArray%.of.js
Added: trunk/Source/_javascript_Core/tests/stress/spread-calling.js (0 => 196734)
--- trunk/Source/_javascript_Core/tests/stress/spread-calling.js (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/spread-calling.js 2016-02-18 01:17:36 UTC (rev 196734)
@@ -0,0 +1,81 @@
+function testFunction() {
+ if (arguments.length !== 10)
+ throw "wrong number of arguments expected 10 was " + arguments.length;
+ for (let i in arguments) {
+ if ((arguments[i] | 0) !== (i | 0))
+ throw "argument " + i + " expected " + i + " was " + arguments[i];
+ }
+}
+
+function testEmpty() {
+ if (arguments.length !== 0)
+ throw "wrong length expected 0 was " + arguments.length;
+}
+
+iter = Array.prototype.values;
+
+function makeObject(array, iterator) {
+ let obj = { [Symbol.iterator]: iterator, length: array.length };
+ for (let i in array)
+ obj[i] = array[i];
+ return obj;
+}
+
+function otherIterator() {
+ return {
+ count: 6,
+ next: function() {
+ if (this.count < 10)
+ return { value: this.count++, done: false };
+ return { done: true };
+ }
+ };
+}
+
+count = 0;
+function* totalIter() {
+ for (let i = count; i < count+5; i++) {
+ yield i;
+ }
+ count += 5;
+}
+
+function throwingIter() {
+ return {
+ count: 0,
+ next: function() {
+ if (this.count < 10)
+ return { value: this.count++, done: false };
+ throw new Error("this should have been caught");
+ }
+ };
+}
+
+object1 = makeObject([1, 2, 3], iter);
+object2 = makeObject([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], iter);
+object3 = makeObject([], otherIterator);
+object4 = makeObject([], totalIter);
+objectThrow = makeObject([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], throwingIter);
+
+for (let i = 0; i < 10000; i++) {
+ count = 0;
+ testFunction(0, ...[1, 2, 3], ...[4], 5, 6, ...[7, 8, 9]);
+ testFunction(...[0, 1], 2, 3, ...[4, 5, 6, 7, 8], 9);
+ testFunction(...[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
+ testFunction(0, ...object1, 4, 5, ...[6, 7, 8, 9]);
+ testFunction(...object2);
+ testFunction(0, ...object1, 4, 5, ...object3);
+ testFunction(0, ..."12345", ...object3);
+ testEmpty(...[]);
+ testFunction(...object4, ...object4);
+ let failed = false;
+ try {
+ testFunction(...objectThrow);
+ failed = true;
+ } catch (e) {
+ if (!e instanceof Error)
+ failed = true;
+ }
+ if (failed)
+ throw "did not throw an exeption even though it should have";
+}