Bug 1797724 - Part 5: Use consistent error messages when iterator method returns a non-object. r=mgaudet

This ensures `Array.fromAsync` uses the same error message as `Array.from` and
normal iteration (`for-of` and `for-await-of`).

This let's us also remove the `GetIterator` self-hosted function.

Also renamed `asyncIterator` to `iterator`, because the returned iterator isn't
an async iterator.

Depends on D160478

Differential Revision: https://phabricator.services.mozilla.com/D160479
This commit is contained in:
André Bargull 2022-10-31 09:38:41 +00:00
Родитель 1c1c8e1864
Коммит bc9d9090e4
3 изменённых файлов: 55 добавлений и 59 удалений

Просмотреть файл

@ -871,17 +871,27 @@ function ArrayFromAsync(asyncItems, mapfn = undefined, thisArg = undefined) {
// Step 3.h. If usingAsyncIterator is not undefined, then
if (usingAsyncIterator !== undefined) {
// Step 3.h.i. Set iteratorRecord to ? GetIterator(asyncItems, async, usingAsyncIterator).
iteratorRecord = GetIterator(asyncItems, "async", usingAsyncIterator);
let iterator = callContentFunction(usingAsyncIterator, asyncItems);
if (!IsObject(iterator)) {
ThrowTypeError(JSMSG_GET_ASYNC_ITER_RETURNED_PRIMITIVE);
}
iteratorRecord = { iterator, nextMethod: iterator.next };
} else if (usingSyncIterator !== undefined) {
// Step 3.i. Else if usingSyncIterator is not undefined, then
// Step 3.i.i. Set iteratorRecord to ? CreateAsyncFromSyncIterator(GetIterator(asyncItems, sync, usingSyncIterator)).
let asyncIterator = GetIterator(asyncItems, "sync", usingSyncIterator);
let iterator = callContentFunction(usingSyncIterator, asyncItems);
if (!IsObject(iterator)) {
ThrowTypeError(JSMSG_GET_ITER_RETURNED_PRIMITIVE);
}
// SpiderMonkey's CreateAsyncFromSyncIterator doesn't return an iterator record
// with named slots; so we need to create our own iterator record.
let asyncFromSyncIteratorObject = CreateAsyncFromSyncIterator(
asyncIterator.iterator,
asyncIterator.nextMethod
iterator,
iterator.next
);
iteratorRecord = {

Просмотреть файл

@ -43,61 +43,6 @@ function IteratorClose(iteratorRecord, value) {
return value;
}
/**
* ES2022 draft rev c5f683e61d5dce703650f1c90d2309c46f8c157a
*
* GetIterator ( obj [ , hint [ , method ] ] )
* https://tc39.es/ecma262/#sec-getiterator
*
*/
function GetIterator(obj, hint = undefined, method = undefined) {
// Step 1. If hint is not present, set hint to sync.
if (hint === undefined) {
hint = "sync";
}
// Step 2. If method is not present, then
if (method === undefined) {
// Step 2.a. If hint is async, then
if (hint === "async") {
// Step 2.a.i. Set method to ? GetMethod(obj, @@asyncIterator).
method = GetMethod(obj, GetBuiltinSymbol("asyncIterator"));
// Step 2.a.ii. If method is undefined, then
if (method === undefined) {
// Step 2.a.ii.1. Let syncMethod be ? GetMethod(obj, @@iterator).
let syncMethod = GetMethod(obj, GetBuiltinSymbol("iterator"));
// Step 2.a.ii.2. Let syncIteratorRecord be ? GetIterator(obj, sync, syncMethod).
let syncIteratorRecord = GetIterator(obj, "sync", syncMethod);
// Step 2.a.ii.3. Return CreateAsyncFromSyncIterator(syncIteratorRecord).
// (SpiderMonkey extracts the contents of the iterator record for this call.)
return CreateAsyncFromSyncIterator(
syncIteratorRecord.iterator,
syncIteratorRecord.nextMethod
);
}
} else {
// Step 2.b. Otherwise, set method to ? GetMethod(obj, @@iterator).
method = GetMethod(obj, GetBuiltinSymbol("iterator"));
}
}
// Step 3. Let iterator be ? Call(method, obj).
let iterator = callContentFunction(method, obj);
// Step 4. If iterator is not an Object, throw a TypeError exception.
if (!IsObject(iterator)) {
ThrowTypeError(JSMSG_OBJECT_REQUIRED, iterator);
}
// Step 5. Let nextMethod be ? GetV(iterator, "next").
let nextMethod = iterator.next;
// Step 6. Let iteratorRecord be the Iterator Record { [[Iterator]]: iterator, [[NextMethod]]: nextMethod, [[Done]]: false }.
let iteratorRecord = { iterator, nextMethod, done: false };
// Step 7. Return iteratorRecord.
return iteratorRecord;
}
/**
* ES2022 draft rev c5f683e61d5dce703650f1c90d2309c46f8c157a
*

Просмотреть файл

@ -133,5 +133,46 @@ assertEq(done, true);
})();
drainJobQueue();
(async function() {
var badSyncIterator = {
[Symbol.iterator](){
return null;
}
};
var badAsyncIterator = {
[Symbol.asyncIterator](){
return null;
}
};
async function errorMessage(fn) {
try {
await fn();
} catch (e) {
return e.message;
}
throw new Error("missing error");
}
// Ensure Array.from and Array.fromAsync use consistent error reporting.
var expected = await errorMessage(() => Array.from(badSyncIterator));
var actual = await errorMessage(() => Array.fromAsync(badSyncIterator));
assertEq(actual, expected);
// Ensure for-of iteration and Array.fromAsync use consistent error reporting.
var expected = await errorMessage(() => { for (var _ of badSyncIterator); });
var actual = await errorMessage(() => Array.fromAsync(badSyncIterator));
assertEq(actual, expected);
// Ensure await for-of iteration and Array.fromAsync use consistent error reporting.
var expected = await errorMessage(async () => { for await (var _ of badAsyncIterator); });
var actual = await errorMessage(() => Array.fromAsync(badAsyncIterator));
assertEq(actual, expected);
})();
drainJobQueue();
if (typeof reportCompare === 'function')
reportCompare(true, true);