blob: 3d3232fe059cbdd415df1ecbda8ad05c2cf9cd50 [file] [log] [blame]
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax
function testSpreadCallsStrict() {
"use strict"
function countArgs() { return arguments.length; }
// Test this argument
function returnThis() { return this; }
assertEquals(void 0, returnThis(..."test"));
// Test argument counting with different iterables
assertEquals(0, countArgs(...""));
assertEquals(4, countArgs(..."test"));
assertEquals(4, countArgs(..."tes", ..."t"));
assertEquals(4, countArgs("t", ..."es", "t"));
assertEquals(4, countArgs("tes", ..."t!!"));
assertEquals(1, countArgs(...[1]));
assertEquals(2, countArgs(...[1, 2]));
assertEquals(3, countArgs(...[1, 2, 3]));
assertEquals(4, countArgs(...[1, 2, 3, 4]));
assertEquals(5, countArgs(...[1, 2, 3, 4, 5]));
assertEquals(6, countArgs(...[1, 2, 3, 4, 5, 6]));
assertEquals(1, countArgs(...[1.1]));
assertEquals(2, countArgs(...[1.1, 2.2]));
assertEquals(3, countArgs(...[1.1, 2.2, 3.3]));
assertEquals(4, countArgs(...[1.1, 2.2, 3.3, 4.4]));
assertEquals(5, countArgs(...[1.1, 2.2, 3.3, 4.4, 5.5]));
assertEquals(6, countArgs(...[1.1, 2.2, 3.3, 4.4, 5.5, 6.6]));
assertEquals(1, countArgs(...new Set([1])));
assertEquals(2, countArgs(...new Set([1, 2])));
assertEquals(3, countArgs(...new Set([1, 2, 3])));
assertEquals(4, countArgs(...new Set([1, 2, 3, 4])));
assertEquals(5, countArgs(...new Set([1, 2, 3, 4, 5])));
assertEquals(6, countArgs(...new Set([1, 2, 3, 4, 5, 6])));
assertEquals(3, countArgs(...(function*(){ yield 1; yield 2; yield 3; })()));
// Test values
function sum() {
var sum = arguments[0];
for (var i = 1; i < arguments.length; ++i) {
sum += arguments[i];
}
return sum;
}
assertThrows(function() {
sum(...0);
}, TypeError);
assertEquals(void 0, sum(...""));
assertEquals(void 0, sum(...[]));
assertEquals(void 0, sum(...new Set));
assertEquals(void 0, sum(...(function*() { })()));
assertEquals("test", sum(..."test"));
assertEquals(10, sum(...[1, 2, 3, 4]));
assertEquals(10, sum(...[1, 2, 3], 4));
assertEquals(10, sum(1, ...[2, 3], 4));
assertEquals(10, sum(1, ...[2, 3], ...[4]));
assertEquals(10, sum(1, 2, ...[3, 4]));
assertEquals(10, sum(...new Set([1, 2, 3, 4])));
assertEquals(10, sum(...(function*() {
yield 1;
yield 2;
yield 3;
yield 4;
})()));
// nested spreads
function makeArray() {
var result = [];
for (var i = 0; i < arguments.length; ++i) {
result.push(arguments[i]);
}
return result;
}
assertEquals(10, sum(...makeArray(...[1, 2, 3, 4])));
assertEquals("test!!!", sum(...makeArray(..."test!!!")));
// Interleaved spread/unspread args
assertEquals(36, sum(0, ...[1], 2, 3, ...[4, 5], 6, 7, 8));
assertEquals(45, sum(0, ...[1], 2, 3, ...[4, 5], 6, 7, 8, ...[9]));
// Methods
var O = {
returnThis: returnThis,
countArgs: countArgs,
sum: sum,
makeArray: makeArray,
nested: {
returnThis: returnThis,
countArgs: countArgs,
sum: sum,
makeArray: makeArray
}
};
// Test this argument
assertEquals(O, O.returnThis(..."test"));
assertEquals(O, O["returnThis"](..."test"));
assertEquals(O.nested, O.nested.returnThis(..."test"));
assertEquals(O.nested, O.nested["returnThis"](..."test"));
// Test argument counting with different iterables
assertEquals(0, O.countArgs(...""));
assertEquals(4, O.countArgs(..."test"));
assertEquals(4, O.countArgs(..."tes", ..."t"));
assertEquals(4, O.countArgs("t", ..."es", "t"));
assertEquals(4, O.countArgs("tes", ..."t!!"));
assertEquals(1, O.countArgs(...[1]));
assertEquals(2, O.countArgs(...[1, 2]));
assertEquals(3, O.countArgs(...[1, 2, 3]));
assertEquals(4, O.countArgs(...[1, 2, 3, 4]));
assertEquals(5, O.countArgs(...[1, 2, 3, 4, 5]));
assertEquals(6, O.countArgs(...[1, 2, 3, 4, 5, 6]));
assertEquals(1, O.countArgs(...new Set([1])));
assertEquals(2, O.countArgs(...new Set([1, 2])));
assertEquals(3, O.countArgs(...new Set([1, 2, 3])));
assertEquals(4, O.countArgs(...new Set([1, 2, 3, 4])));
assertEquals(5, O.countArgs(...new Set([1, 2, 3, 4, 5])));
assertEquals(6, O.countArgs(...new Set([1, 2, 3, 4, 5, 6])));
assertEquals(3, O.countArgs(
...(function*(){ yield 1; yield 2; yield 3; })()));
// Test values
assertEquals(void 0, O.sum(...""));
assertEquals(void 0, O.sum(...[]));
assertEquals(void 0, O.sum(...new Set));
assertEquals(void 0, O.sum(...(function*() { })()));
assertEquals("test", O.sum(..."test"));
assertEquals(10, O.sum(...[1, 2, 3, 4]));
assertEquals(10, O.sum(...[1, 2, 3], 4));
assertEquals(10, O.sum(1, ...[2, 3], 4));
assertEquals(10, O.sum(1, ...[2, 3], ...[4]));
assertEquals(10, O.sum(1, 2, ...[3, 4]));
assertEquals(10, O.sum(...new Set([1, 2, 3, 4])));
assertEquals(10, O.sum(...(function*() {
yield 1;
yield 2;
yield 3;
yield 4;
})()));
// nested spreads
assertEquals(10, O.sum(...O.makeArray(...[1, 2, 3, 4])));
assertEquals("test!!!", O.sum(...O.makeArray(..."test!!!")));
// Interleaved spread/unspread args
assertEquals(36, O.sum(0, ...[1], 2, 3, ...[4, 5], 6, 7, 8));
assertEquals(45, O.sum(0, ...[1], 2, 3, ...[4, 5], 6, 7, 8, ...[9]));
};
%PrepareFunctionForOptimization(testSpreadCallsStrict);
testSpreadCallsStrict();
%OptimizeFunctionOnNextCall(testSpreadCallsStrict);
testSpreadCallsStrict();
(function testSpreadCallsSloppy() {
// Test this argument
function returnThis() { return this; }
assertEquals(this, returnThis(..."test"));
function countArgs() { return arguments.length; }
// Test argument counting with different iterables
assertEquals(0, countArgs(...""));
assertEquals(4, countArgs(..."test"));
assertEquals(4, countArgs(..."tes", ..."t"));
assertEquals(4, countArgs("t", ..."es", "t"));
assertEquals(4, countArgs("tes", ..."t!!"));
assertEquals(1, countArgs(...[1]));
assertEquals(2, countArgs(...[1, 2]));
assertEquals(3, countArgs(...[1, 2, 3]));
assertEquals(4, countArgs(...[1, 2, 3, 4]));
assertEquals(5, countArgs(...[1, 2, 3, 4, 5]));
assertEquals(6, countArgs(...[1, 2, 3, 4, 5, 6]));
assertEquals(1, countArgs(...new Set([1])));
assertEquals(2, countArgs(...new Set([1, 2])));
assertEquals(3, countArgs(...new Set([1, 2, 3])));
assertEquals(4, countArgs(...new Set([1, 2, 3, 4])));
assertEquals(5, countArgs(...new Set([1, 2, 3, 4, 5])));
assertEquals(6, countArgs(...new Set([1, 2, 3, 4, 5, 6])));
assertEquals(3, countArgs(...(function*(){
yield 1;
yield 2;
yield 3;
})()));
// Test values
function sum() {
var sum = arguments[0];
for (var i = 1; i < arguments.length; ++i) {
sum += arguments[i];
}
return sum;
}
assertThrows(function() {
sum(...0);
}, TypeError);
assertEquals(void 0, sum(...""));
assertEquals(void 0, sum(...[]));
assertEquals(void 0, sum(...new Set));
assertEquals(void 0, sum(...(function*() { })()));
assertEquals("test", sum(..."test"));
assertEquals(10, sum(...[1, 2, 3, 4]));
assertEquals(10, sum(...[1, 2, 3], 4));
assertEquals(10, sum(1, ...[2, 3], 4));
assertEquals(10, sum(1, ...[2, 3], ...[4]));
assertEquals(10, sum(1, 2, ...[3, 4]));
assertEquals(10, sum(...new Set([1, 2, 3, 4])));
assertEquals(10, sum(...(function*() {
yield 1;
yield 2;
yield 3;
yield 4;
})()));
// nested spreads
function makeArray() {
var result = [];
for (var i = 0; i < arguments.length; ++i) {
result.push(arguments[i]);
}
return result;
}
assertEquals(10, sum(...makeArray(...[1, 2, 3, 4])));
assertEquals("test!!!", sum(...makeArray(..."test!!!")));
// Interleaved spread/unspread args
assertEquals(36, sum(0, ...[1], 2, 3, ...[4, 5], 6, 7, 8));
assertEquals(45, sum(0, ...[1], 2, 3, ...[4, 5], 6, 7, 8, ...[9]));
// Methods
var O = {
returnThis: returnThis,
countArgs: countArgs,
sum: sum,
makeArray: makeArray,
nested: {
returnThis: returnThis,
countArgs: countArgs,
sum: sum,
makeArray: makeArray
}
};
// Test this argument
assertEquals(O, O.returnThis(..."test"));
assertEquals(O, O["returnThis"](..."test"));
assertEquals(O.nested, O.nested.returnThis(..."test"));
assertEquals(O.nested, O.nested["returnThis"](..."test"));
// Test argument counting with different iterables
assertEquals(0, O.countArgs(...""));
assertEquals(4, O.countArgs(..."test"));
assertEquals(4, O.countArgs(..."tes", ..."t"));
assertEquals(4, O.countArgs("t", ..."es", "t"));
assertEquals(4, O.countArgs("tes", ..."t!!"));
assertEquals(1, O.countArgs(...[1]));
assertEquals(2, O.countArgs(...[1, 2]));
assertEquals(3, O.countArgs(...[1, 2, 3]));
assertEquals(4, O.countArgs(...[1, 2, 3, 4]));
assertEquals(5, O.countArgs(...[1, 2, 3, 4, 5]));
assertEquals(6, O.countArgs(...[1, 2, 3, 4, 5, 6]));
assertEquals(1, O.countArgs(...new Set([1])));
assertEquals(2, O.countArgs(...new Set([1, 2])));
assertEquals(3, O.countArgs(...new Set([1, 2, 3])));
assertEquals(4, O.countArgs(...new Set([1, 2, 3, 4])));
assertEquals(5, O.countArgs(...new Set([1, 2, 3, 4, 5])));
assertEquals(6, O.countArgs(...new Set([1, 2, 3, 4, 5, 6])));
assertEquals(3, O.countArgs(...(function*(){
yield 1;
yield 2;
yield 3;
})()));
// Test values
assertEquals(void 0, O.sum(...""));
assertEquals(void 0, O.sum(...[]));
assertEquals(void 0, O.sum(...new Set));
assertEquals(void 0, O.sum(...(function*() { })()));
assertEquals("test", O.sum(..."test"));
assertEquals(10, O.sum(...[1, 2, 3, 4]));
assertEquals(10, O.sum(...[1, 2, 3], 4));
assertEquals(10, O.sum(1, ...[2, 3], 4));
assertEquals(10, O.sum(1, ...[2, 3], ...[4]));
assertEquals(10, O.sum(1, 2, ...[3, 4]));
assertEquals(10, O.sum(...new Set([1, 2, 3, 4])));
assertEquals(10, O.sum(...(function*() {
yield 1;
yield 2;
yield 3;
yield 4;
})()));
// nested spreads
assertEquals(10, O.sum(...O.makeArray(...[1, 2, 3, 4])));
assertEquals("test!!!", O.sum(...O.makeArray(..."test!!!")));
// Interleaved spread/unspread args
assertEquals(36, O.sum(0, ...[1], 2, 3, ...[4, 5], 6, 7, 8));
assertEquals(45, O.sum(0, ...[1], 2, 3, ...[4, 5], 6, 7, 8, ...[9]));
})();
(function testSpreadEvaluationOrder() {
"use strict";
var log = "";
function* gen() { log += "X"; yield 0; log += "Y"; }
function a() { log += "A"; }
function b() { log += "B"; return gen(); }
function* c() { log += 'C1'; yield 1; log += 'C2'; }
function d() { log += "D"; }
function e() { log += "E"; }
function fn() {
var args = [];
for (var i = 0; i < arguments.length; ++i) args.push(arguments[i]);
return args;
}
var result = fn(a(), ...b(), d());
assertEquals([undefined, 0, undefined], result);
assertEquals("ABXYD", log);
log = "";
result = fn(...b(), d());
assertEquals([0, undefined], result);
assertEquals("BXYD", log);
log = "";
result = fn(a(), ...b());
assertEquals([undefined, 0], result);
assertEquals("ABXY", log);
log = "";
result = fn(a(), ...b(), ...c(), d(), e());
assertEquals([undefined, 0, 1, undefined, undefined], result);
assertEquals("ABXYC1C2DE", log);
log = "";
result = fn(a(), ...b(), ...c(), d(), e(), ...b(), ...c());
assertEquals([undefined, 0, 1, undefined, undefined, 0, 1], result);
assertEquals("ABXYC1C2DEBXYC1C2", log);
})();
(function testArrayPrototypeHoleGetterModifiesIteratorPrototypeNext() {
function sum() {
var sum = arguments[0];
for (var i = 1; i < arguments.length; ++i) {
sum += arguments[i];
}
return sum;
}
var a = [1, 2];
a[3] = 4;
var called = 0;
// .next method is only accessed during iteration prologue (see
// https://github.com/tc39/ecma262/pull/988)
let ArrayIteratorPrototype = Array.prototype[Symbol.iterator]().__proto__;
let ArrayIteratorPrototypeNextDescriptor =
Object.getOwnPropertyDescriptor(ArrayIteratorPrototype, 'next');
Object.defineProperty(Array.prototype, 2, {
get: function() {
var ai = a[Symbol.iterator]();
var original_next = ai.__proto__["next"];
Object.defineProperty(ai.__proto__, "next", {
get: function() {
called++;
return original_next;
},
configurable: true
});
return 3;
},
configurable: true
});
assertEquals(10, sum(...a));
assertEquals(0, called);
Object.defineProperty(ArrayIteratorPrototype, 'next',
ArrayIteratorPrototypeNextDescriptor);
Object.defineProperty(Array.prototype, 2, {});
})();
(function testArrayHasOtherPrototype() {
function countArgs() { return arguments.length; }
var a = [1, 2, 3];
var b = {};
Object.defineProperty(b, Symbol.iterator, {
value: function*() {
yield 4;
},
configurable: true
});
Object.setPrototypeOf(a, b);
assertEquals(1, countArgs(...a));
})();
(function testArrayIteratorPrototypeGetter() {
function countArgs() { return arguments.length; }
var a = [1, 2, 3];
var ai = a[Symbol.iterator]();
var called = 0;
var original_next = ai.__proto__["next"];
Object.defineProperty(ai.__proto__, "next", {
get: function() {
called++;
return original_next;
}
});
countArgs(...a);
// .next method is only accessed during iteration prologue (see
// https://github.com/tc39/ecma262/pull/988)
assertEquals(1, called);
})();
(function testArrayIteratorPrototypeModified() {
function countArgs() { return arguments.length; }
var a = [1,2,3];
var ai = a[Symbol.iterator]();
Object.defineProperty(ai.__proto__, "next", {
value: function() {
return {value: undefined, done: true};
},
configurable: true
});
assertEquals(0, countArgs(...a));
})();
(function testCustomArrayPrototypeIterator() {
var origIterator =
Object.getOwnPropertyDescriptor(Array.prototype, Symbol.iterator);
Object.defineProperty(Array.prototype, Symbol.iterator, {
value: function*() {
yield 1;
yield 2;
yield 3;
},
configurable: true
});
function returnCountStrict() { 'use strict'; return arguments.length; }
function returnCountSloppy() { return arguments.length; }
assertEquals(3, returnCountStrict(...[1]));
assertEquals(4, returnCountStrict(1, ...[2]));
assertEquals(5, returnCountStrict(1, ...[2], 3));
assertEquals(3, returnCountSloppy(...[1]));
assertEquals(4, returnCountSloppy(1, ...[2]));
assertEquals(5, returnCountSloppy(1, ...[2], 3));
Object.defineProperty(Array.prototype, Symbol.iterator, origIterator);
})();
(function testGetPropertyIteratorCalledExactlyOnce() {
function countArgs() { return arguments.length; }
var a = [1, 2, 3];
var called = 0;
Object.defineProperty(Array.prototype, Symbol.iterator, {
value: function*() {
yield 1;
yield 2;
},
configurable: true
});
var it = a[Symbol.iterator];
Object.defineProperty(a, Symbol.iterator, {
get: function() {
called++;
return it;
}
});
countArgs(...a);
assertEquals(1, called);
})();