summaryrefslogtreecommitdiffstats
path: root/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype')
-rw-r--r--js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/browser.js0
-rw-r--r--js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/absent-value-not-passed.js38
-rw-r--r--js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/browser.js0
-rw-r--r--js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/for-await-iterator-next-rejected-promise-close.js66
-rw-r--r--js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/for-await-next-rejected-promise-close.js71
-rw-r--r--js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/iterator-result-poisoned-done.js53
-rw-r--r--js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/iterator-result-poisoned-value.js55
-rw-r--r--js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/iterator-result-poisoned-wrapper.js68
-rw-r--r--js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/iterator-result-prototype.js43
-rw-r--r--js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/iterator-result-rejected.js44
-rw-r--r--js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/iterator-result-unwrap-promise.js44
-rw-r--r--js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/next-result-poisoned-wrapper.js73
-rw-r--r--js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/return-promise.js28
-rw-r--r--js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/shell.js113
-rw-r--r--js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/yield-iterator-next-rejected-promise-close.js63
-rw-r--r--js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/yield-next-rejected-promise-close.js68
-rw-r--r--js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/absent-value-not-passed.js43
-rw-r--r--js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/browser.js0
-rw-r--r--js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/iterator-result-poisoned-done.js71
-rw-r--r--js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/iterator-result-poisoned-value.js71
-rw-r--r--js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/iterator-result-unwrap-promise.js65
-rw-r--r--js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/iterator-result.js56
-rw-r--r--js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/poisoned-get-return.js60
-rw-r--r--js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/poisoned-return.js66
-rw-r--r--js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/result-object-error.js65
-rw-r--r--js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/return-null.js55
-rw-r--r--js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/return-undefined.js55
-rw-r--r--js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/shell.js113
-rw-r--r--js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/shell.js0
-rw-r--r--js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/browser.js0
-rw-r--r--js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/iterator-result-poisoned-done.js70
-rw-r--r--js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/iterator-result-poisoned-value.js70
-rw-r--r--js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/iterator-result-rejected-promise-close.js84
-rw-r--r--js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/iterator-result-unwrap-promise.js66
-rw-r--r--js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/iterator-result.js60
-rw-r--r--js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/poisoned-get-throw.js59
-rw-r--r--js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/poisoned-throw.js61
-rw-r--r--js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/result-object-error.js65
-rw-r--r--js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/shell.js113
-rw-r--r--js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/throw-null.js60
-rw-r--r--js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/throw-result-poisoned-wrapper.js91
-rw-r--r--js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/throw-undefined-get-return-undefined.js74
-rw-r--r--js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/throw-undefined-poisoned-return.js78
-rw-r--r--js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/throw-undefined-return-not-object.js81
-rw-r--r--js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/throw-undefined-return-object.js75
-rw-r--r--js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/throw-undefined.js49
46 files changed, 2703 insertions, 0 deletions
diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/browser.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/browser.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/browser.js
diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/absent-value-not-passed.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/absent-value-not-passed.js
new file mode 100644
index 0000000000..ecba51e39c
--- /dev/null
+++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/absent-value-not-passed.js
@@ -0,0 +1,38 @@
+// |reftest| async
+// Copyright (C) 2020 Alexey Shvayka. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-%asyncfromsynciteratorprototype%.next
+description: >
+ `next` method does not pass absent `value`.
+info: |
+ %AsyncFromSyncIteratorPrototype%.next ( value )
+
+ [...]
+ 5. If value is present, then
+ [...]
+ 6. Else,
+ a. Let result be IteratorNext(syncIteratorRecord).
+ [...]
+flags: [async]
+features: [async-iteration]
+includes: [asyncHelpers.js]
+---*/
+
+var nextArgumentsLength;
+var syncIterator = {
+ [Symbol.iterator]() {
+ return this;
+ },
+ next() {
+ nextArgumentsLength = arguments.length;
+ return {done: true};
+ },
+};
+
+asyncTest(async function () {
+ for await (let _ of syncIterator);
+
+ assert.sameValue(nextArgumentsLength, 0);
+});
diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/browser.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/browser.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/browser.js
diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/for-await-iterator-next-rejected-promise-close.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/for-await-iterator-next-rejected-promise-close.js
new file mode 100644
index 0000000000..27a06daace
--- /dev/null
+++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/for-await-iterator-next-rejected-promise-close.js
@@ -0,0 +1,66 @@
+// |reftest| async
+// Copyright (C) 2024 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-%asyncfromsynciteratorprototype%.next
+description: next() will reject promise if resolving result promise abrupt completes.
+info: |
+ %AsyncFromSyncIteratorPrototype%.next ( value )
+ ...
+ 3. Let promiseCapability be ! NewPromiseCapability(%Promise%).
+ 4. Let syncIteratorRecord be O.[[SyncIteratorRecord]].
+ 5. If value is present, then
+ ...
+ 6. Else,
+ a. Let result be IteratorNext(syncIteratorRecord).
+ 7. IfAbruptRejectPromise(result, promiseCapability).
+ 8. Return ! AsyncFromSyncIteratorContinuation(result, promiseCapability, syncIteratorRecord, true).
+
+ AsyncFromSyncIteratorContinuation ( result, promiseCapability, syncIteratorRecord, closeOnRejection )
+ 1. Let done be IteratorComplete(result).
+ 2. IfAbruptRejectPromise(done, promiseCapability).
+ 3. Let value be IteratorValue(result).
+ 4. IfAbruptRejectPromise(value, promiseCapability).
+ 5. Let valueWrapper be PromiseResolve(%Promise%, value).
+ 6. If valueWrapper is an abrupt completion, done is false, and closeOnRejection is true, then
+ a. Set valueWrapper to IteratorClose(syncIteratorRecord, valueWrapper).
+ ...
+ 12. If done is true, or if closeOnRejection is false, then
+ ...
+ 13. Else,
+ a. Let closeIterator be a new Abstract Closure with parameters (error) that captures syncIteratorRecord and performs the following steps when called:
+ i. Return ? IteratorClose(syncIteratorRecord, ThrowCompletion(error)).
+ b. Let onRejected be CreateBuiltinFunction(closeIterator, 1, "", « »).
+ c. NOTE: onRejected is used to close the Iterator when the "value" property of an IteratorResult object it yields is a rejected promise.
+ 14. Perform PerformPromiseThen(valueWrapper, onFulfilled, onRejected, promiseCapability).
+ 15. Return promiseCapability.[[Promise]].
+
+
+flags: [async]
+features: [async-iteration]
+includes: [asyncHelpers.js]
+---*/
+
+var finallyCount = 0;
+var caught = false;
+
+function* iterator() {
+ try {
+ yield Promise.reject("reject");
+ } finally {
+ finallyCount += 1;
+ }
+}
+
+asyncTest(async () => {
+ try {
+ for await (const x of iterator());
+ } catch (e) {
+ caught = true;
+ assert.sameValue(e, "reject");
+ }
+
+ assert.sameValue(finallyCount, 1);
+ assert(caught);
+});
diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/for-await-next-rejected-promise-close.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/for-await-next-rejected-promise-close.js
new file mode 100644
index 0000000000..60d7674aa6
--- /dev/null
+++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/for-await-next-rejected-promise-close.js
@@ -0,0 +1,71 @@
+// |reftest| async
+// Copyright (C) 2024 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-%asyncfromsynciteratorprototype%.next
+description: next() will reject promise if resolving result promise abrupt completes.
+info: |
+ %AsyncFromSyncIteratorPrototype%.next ( value )
+ ...
+ 3. Let promiseCapability be ! NewPromiseCapability(%Promise%).
+ 4. Let syncIteratorRecord be O.[[SyncIteratorRecord]].
+ 5. If value is present, then
+ ...
+ 6. Else,
+ a. Let result be IteratorNext(syncIteratorRecord).
+ 7. IfAbruptRejectPromise(result, promiseCapability).
+ 8. Return ! AsyncFromSyncIteratorContinuation(result, promiseCapability, syncIteratorRecord, true).
+
+ AsyncFromSyncIteratorContinuation ( result, promiseCapability, syncIteratorRecord, closeOnRejection )
+ 1. Let done be IteratorComplete(result).
+ 2. IfAbruptRejectPromise(done, promiseCapability).
+ 3. Let value be IteratorValue(result).
+ 4. IfAbruptRejectPromise(value, promiseCapability).
+ 5. Let valueWrapper be PromiseResolve(%Promise%, value).
+ 6. If valueWrapper is an abrupt completion, done is false, and closeOnRejection is true, then
+ a. Set valueWrapper to IteratorClose(syncIteratorRecord, valueWrapper).
+ ...
+ 12. If done is true, or if closeOnRejection is false, then
+ ...
+ 13. Else,
+ a. Let closeIterator be a new Abstract Closure with parameters (error) that captures syncIteratorRecord and performs the following steps when called:
+ i. Return ? IteratorClose(syncIteratorRecord, ThrowCompletion(error)).
+ b. Let onRejected be CreateBuiltinFunction(closeIterator, 1, "", « »).
+ c. NOTE: onRejected is used to close the Iterator when the "value" property of an IteratorResult object it yields is a rejected promise.
+ 14. Perform PerformPromiseThen(valueWrapper, onFulfilled, onRejected, promiseCapability).
+ 15. Return promiseCapability.[[Promise]].
+
+
+flags: [async]
+features: [async-iteration]
+includes: [asyncHelpers.js]
+---*/
+
+var returnCount = 0;
+var caught = false;
+
+const syncIterator = {
+ [Symbol.iterator]() {
+ return {
+ next() {
+ return { value: Promise.reject("reject"), done: false };
+ },
+ return() {
+ returnCount += 1;
+ }
+ };
+ }
+}
+
+asyncTest(async () => {
+ try {
+ for await (let _ of syncIterator);
+ } catch (e) {
+ caught = true;
+ assert.sameValue(e, "reject");
+ }
+
+ assert.sameValue(returnCount, 1);
+ assert(caught);
+});
diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/iterator-result-poisoned-done.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/iterator-result-poisoned-done.js
new file mode 100644
index 0000000000..eb493bece9
--- /dev/null
+++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/iterator-result-poisoned-done.js
@@ -0,0 +1,53 @@
+// |reftest| async
+// Copyright (C) 2018 Valerie Young. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-%asyncfromsynciteratorprototype%.next
+description: next() will reject promise if getter `done` abrupt completes
+info: |
+ %AsyncFromSyncIteratorPrototype%.next ( value )
+ ...
+ 2. Let promiseCapability be ! NewPromiseCapability(%Promise%).
+ ...
+ 5. Let nextResult be IteratorNext(syncIteratorRecord, value).
+ 6. IfAbruptRejectPromise(nextResult, promiseCapability).
+ 7. Let nextDone be IteratorComplete(nextResult).
+ 8. IfAbruptRejectPromise(nextDone, promiseCapability).
+ ...
+ 18. Return promiseCapability.[[Promise]].
+
+flags: [async]
+features: [async-iteration]
+---*/
+
+var thrownError = new Error("Catch me.");
+
+var obj = {
+ [Symbol.iterator]() {
+ return {
+ next() {
+ return {
+ get done() {
+ throw thrownError;
+ },
+ value: 1
+ }
+ }
+ };
+ }
+};
+
+async function* asyncg() {
+ yield* obj;
+}
+
+asyncg().next().then(
+ function (result) {
+ throw new Test262Error("Promise should be rejected.");
+ },
+ function (err) {
+ assert.sameValue(err, thrownError, "Promise should be rejected with thrown error");
+ }
+).then($DONE, $DONE);
+
diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/iterator-result-poisoned-value.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/iterator-result-poisoned-value.js
new file mode 100644
index 0000000000..6a0e49439d
--- /dev/null
+++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/iterator-result-poisoned-value.js
@@ -0,0 +1,55 @@
+// |reftest| async
+// Copyright (C) 2018 Valerie Young. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-%asyncfromsynciteratorprototype%.next
+description: next() will reject promise if getter `value` abrupt completes
+info: |
+ %AsyncFromSyncIteratorPrototype%.next ( value )
+ ...
+ 2. Let promiseCapability be ! NewPromiseCapability(%Promise%).
+ ...
+ 5. Let nextResult be IteratorNext(syncIteratorRecord, value).
+ 6. IfAbruptRejectPromise(nextResult, promiseCapability).
+ 7. Let nextDone be IteratorComplete(nextResult).
+ 8. If AbruptRejectPromise(nextDone, promiseCapability).
+ 9. Let nextValue be IteratorValue(nextResult).
+ 10. IfAbruptRejectPromise(nextValue, promiseCapability).
+ ...
+ 18. Return promiseCapability.[[Promise]].
+
+flags: [async]
+features: [async-iteration]
+---*/
+
+var thrownError = new Error("Catch me.");
+
+var obj = {
+ [Symbol.iterator]() {
+ return {
+ next() {
+ return {
+ get value() {
+ throw thrownError;
+ },
+ done: false
+ }
+ }
+ };
+ }
+};
+
+async function* asyncg() {
+ yield* obj;
+}
+
+asyncg().next().then(
+ function (result) {
+ throw new Test262Error("Promise should be rejected.");
+ },
+ function (err) {
+ assert.sameValue(err, thrownError, "Promise should be rejected with thrown error");
+ }
+).then($DONE, $DONE);
+
diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/iterator-result-poisoned-wrapper.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/iterator-result-poisoned-wrapper.js
new file mode 100644
index 0000000000..bbcd3f3a23
--- /dev/null
+++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/iterator-result-poisoned-wrapper.js
@@ -0,0 +1,68 @@
+// |reftest| async
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-%asyncfromsynciteratorprototype%.next
+description: next() will reject promise if resolving result promise abrupt completes.
+info: |
+ %AsyncFromSyncIteratorPrototype%.next ( value )
+ ...
+ 3. Let promiseCapability be ! NewPromiseCapability(%Promise%).
+ 4. Let syncIteratorRecord be O.[[SyncIteratorRecord]].
+ 5. If value is present, then
+ ...
+ 6. Else,
+ a. Let result be IteratorNext(syncIteratorRecord).
+ 7. IfAbruptRejectPromise(result, promiseCapability).
+ 8. Return ! AsyncFromSyncIteratorContinuation(result, promiseCapability, syncIteratorRecord, true).
+
+ AsyncFromSyncIteratorContinuation ( result, promiseCapability, syncIteratorRecord, closeOnRejection )
+ 1. Let done be IteratorComplete(result).
+ 2. IfAbruptRejectPromise(done, promiseCapability).
+ 3. Let value be IteratorValue(result).
+ 4. IfAbruptRejectPromise(value, promiseCapability).
+ 5. Let valueWrapper be PromiseResolve(%Promise%, value).
+ 6. If valueWrapper is an abrupt completion, done is false, and closeOnRejection is true, then
+ a. Set valueWrapper to IteratorClose(syncIteratorRecord, valueWrapper).
+ 7. IfAbruptRejectPromise(valueWrapper, promiseCapability).
+ ...
+
+ IfAbruptRejectPromise ( value, capability )
+ 1. Assert: value is a Completion Record.
+ 2. If value is an abrupt completion, then
+ a. Perform ? Call(capability.[[Reject]], undefined, « value.[[Value]] »).
+ b. Return capability.[[Promise]].
+ ...
+
+flags: [async]
+features: [async-iteration]
+includes: [asyncHelpers.js]
+---*/
+
+var finallyCount = 0;
+function CatchError() {}
+var thrownError = new CatchError();
+
+function* gen() {
+ try {
+ const p = Promise.resolve('FAIL');
+ Object.defineProperty(p, 'constructor', {
+ get() {
+ throw thrownError;
+ }
+ });
+ yield p;
+ } finally {
+ finallyCount += 1;
+ }
+}
+
+async function* iter() {
+ yield* gen();
+}
+
+asyncTest(async function () {
+ await assert.throwsAsync(CatchError, async () => iter().next(), "Promise should be rejected");
+ assert.sameValue(finallyCount, 1, 'iterator closed properly');
+})
diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/iterator-result-prototype.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/iterator-result-prototype.js
new file mode 100644
index 0000000000..d3f638e48e
--- /dev/null
+++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/iterator-result-prototype.js
@@ -0,0 +1,43 @@
+// |reftest| async
+// Copyright (C) 2018 Valerie Young. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-%asyncfromsynciteratorprototype%.next
+description: next() returns a promise for an IteratorResult object
+info: |
+ %AsyncFromSyncIteratorPrototype%.next ( value )
+ ...
+ 2. Let promiseCapability be ! NewPromiseCapability(%Promise%).
+ ...
+ 5. Let nextResult be IteratorNext(syncIteratorRecord, value).
+ 6. IfAbruptRejectPromise(nextResult, promiseCapability).
+ 7. Let nextDone be IteratorComplete(nextResult).
+ 8. If AbruptRejectPromise(nextDone, promiseCapability).
+ 9. Let nextValue be IteratorValue(nextResult).
+ 10. IfAbruptRejectPromise(nextValue, promiseCapability).
+ ...
+ 14. Let steps be the algorithm steps defined in Async-from-Sync Iterator Value Unwrap Functions.
+
+ Async-from-Sync Iterator Value Unwrap Functions
+ 1. Return ! CreateIterResultObject(value, F.[[Done]]).
+
+flags: [async]
+features: [async-iteration]
+---*/
+
+function* g() {}
+
+async function* asyncg() {
+ yield* g();
+}
+
+asyncg().next().then(function (result) {
+ assert(
+ Object.prototype.hasOwnProperty.call(result, 'value'), 'Has "own" property `value`'
+ );
+ assert(
+ Object.prototype.hasOwnProperty.call(result, 'done'), 'Has "own" property `done`'
+ );
+ assert.sameValue(Object.getPrototypeOf(result), Object.prototype);
+}).then($DONE, $DONE);
diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/iterator-result-rejected.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/iterator-result-rejected.js
new file mode 100644
index 0000000000..8a5f9bf14a
--- /dev/null
+++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/iterator-result-rejected.js
@@ -0,0 +1,44 @@
+// |reftest| async
+// Copyright (C) 2018 Valerie Young. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-%asyncfromsynciteratorprototype%.next
+description: next() will reject promise if sync iterator next() function returns an aburpt completion
+info: |
+ %AsyncFromSyncIteratorPrototype%.next ( value )
+ ...
+ 2. Let promiseCapability be ! NewPromiseCapability(%Promise%).
+ ...
+ 5. Let nextResult be IteratorNext(syncIteratorRecord, value).
+ 6. IfAbruptRejectPromise(nextResult, promiseCapability).
+ 7. Let nextDone be IteratorComplete(nextResult).
+ 8. If AbruptRejectPromise(nextDone, promiseCapability).
+ 9. Let nextValue be IteratorValue(nextResult).
+ 10. IfAbruptRejectPromise(nextValue, promiseCapability).
+ ...
+ 18. Return promiseCapability.[[Promise]].
+
+flags: [async]
+features: [async-iteration]
+---*/
+
+var thrownError = new Error("Catch me.");
+
+function* g() {
+ throw thrownError;
+}
+
+async function* asyncg() {
+ yield* g();
+}
+
+asyncg().next().then(
+ function (result) {
+ throw new Test262Error("Promise should be rejected.");
+ },
+ function (err) {
+ assert.sameValue(err, thrownError, "Promise should be rejected with thrown error");
+ }
+).then($DONE, $DONE);
+
diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/iterator-result-unwrap-promise.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/iterator-result-unwrap-promise.js
new file mode 100644
index 0000000000..f77f3c2d96
--- /dev/null
+++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/iterator-result-unwrap-promise.js
@@ -0,0 +1,44 @@
+// |reftest| async
+// Copyright (C) 2018 Valerie Young. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-%asyncfromsynciteratorprototype%.next
+description: next() will unwrap a Promise value return by the sync iterator
+info: |
+ %AsyncFromSyncIteratorPrototype%.next ( value )
+ ...
+ 2. Let promiseCapability be ! NewPromiseCapability(%Promise%).
+ ...
+ 5. Let nextResult be IteratorNext(syncIteratorRecord, value).
+ 6. IfAbruptRejectPromise(nextResult, promiseCapability).
+ 7. Let nextDone be IteratorComplete(nextResult).
+ 8. If AbruptRejectPromise(nextDone, promiseCapability).
+ 9. Let nextValue be IteratorValue(nextResult).
+ 10. IfAbruptRejectPromise(nextValue, promiseCapability).
+ ...
+ 14. Let steps be the algorithm steps defined in Async-from-Sync Iterator Value Unwrap Functions.
+
+ Async-from-Sync Iterator Value Unwrap Functions
+ An async-from-sync iterator value unwrap function is an anonymous built-in
+ function that is used by methods of %AsyncFromSyncIteratorPrototype% when
+ processing the value field of an IteratorResult object, in order to wait for
+ its value if it is a promise and re-package the result in a new "unwrapped"
+ IteratorResult object. Each async iterator value unwrap function has a
+ [[Done]] internal slot.
+
+flags: [async]
+features: [async-iteration]
+---*/
+
+function* g() {
+ yield Promise.resolve(1);
+}
+
+async function* asyncg() {
+ yield* g();
+}
+
+asyncg().next().then(function (result) {
+ assert.sameValue(result.value, 1, "result.value should be unwrapped promise, got: " + result.value)
+}).then($DONE, $DONE);
diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/next-result-poisoned-wrapper.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/next-result-poisoned-wrapper.js
new file mode 100644
index 0000000000..f7b9c57549
--- /dev/null
+++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/next-result-poisoned-wrapper.js
@@ -0,0 +1,73 @@
+// |reftest| async
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-%asyncfromsynciteratorprototype%.next
+description: next() will reject promise if resolving result promise abrupt completes.
+info: |
+ %AsyncFromSyncIteratorPrototype%.next ( value )
+ ...
+ 3. Let promiseCapability be ! NewPromiseCapability(%Promise%).
+ 4. Let syncIteratorRecord be O.[[SyncIteratorRecord]].
+ 5. If value is present, then
+ ...
+ 6. Else,
+ a. Let result be IteratorNext(syncIteratorRecord).
+ 7. IfAbruptRejectPromise(result, promiseCapability).
+ 8. Return ! AsyncFromSyncIteratorContinuation(result, promiseCapability, syncIteratorRecord, true).
+
+ AsyncFromSyncIteratorContinuation ( result, promiseCapability, syncIteratorRecord, closeOnRejection )
+ 1. Let done be IteratorComplete(result).
+ 2. IfAbruptRejectPromise(done, promiseCapability).
+ 3. Let value be IteratorValue(result).
+ 4. IfAbruptRejectPromise(value, promiseCapability).
+ 5. Let valueWrapper be PromiseResolve(%Promise%, value).
+ 6. If valueWrapper is an abrupt completion, done is false, and closeOnRejection is true, then
+ a. Set valueWrapper to IteratorClose(syncIteratorRecord, valueWrapper).
+ 7. IfAbruptRejectPromise(valueWrapper, promiseCapability).
+ ...
+
+ IfAbruptRejectPromise ( value, capability )
+ 1. Assert: value is a Completion Record.
+ 2. If value is an abrupt completion, then
+ a. Perform ? Call(capability.[[Reject]], undefined, « value.[[Value]] »).
+ b. Return capability.[[Promise]].
+ ...
+
+flags: [async]
+features: [async-iteration]
+includes: [asyncHelpers.js]
+---*/
+
+var returnCount = 0;
+function CatchError() {}
+var thrownError = new CatchError();
+
+const obj = {
+ [Symbol.iterator]() {
+ return {
+ next() {
+ const p = Promise.resolve('FAIL');
+ Object.defineProperty(p, 'constructor', {
+ get() {
+ throw thrownError;
+ }
+ });
+ return { value: p, done: false };
+ },
+ return() {
+ returnCount += 1;
+ }
+ };
+ }
+};
+
+async function* iter() {
+ yield* obj;
+}
+
+asyncTest(async function () {
+ await assert.throwsAsync(CatchError, async () => iter().next(), "Promise should be rejected");
+ assert.sameValue(returnCount, 1, 'iterator closed properly');
+})
diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/return-promise.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/return-promise.js
new file mode 100644
index 0000000000..4f6a112c45
--- /dev/null
+++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/return-promise.js
@@ -0,0 +1,28 @@
+// Copyright (C) 2018 Valerie Young. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-%asyncfromsynciteratorprototype%.next
+description: >
+ "next" returns a promise for an IteratorResult object
+info: |
+ %AsyncFromSyncIteratorPrototype%.next ( value )
+ ...
+ 2. Let promiseCapability be ! NewPromiseCapability(%Promise%).
+ ...
+ 18. Return promiseCapability.[[Promise]].
+
+features: [async-iteration]
+---*/
+
+function* g() {
+}
+
+async function* asyncg() {
+ yield* g();
+}
+
+var result = asyncg().next();
+assert(result instanceof Promise)
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/shell.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/shell.js
new file mode 100644
index 0000000000..ae18ad584d
--- /dev/null
+++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/shell.js
@@ -0,0 +1,113 @@
+// GENERATED, DO NOT EDIT
+// file: asyncHelpers.js
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: |
+ A collection of assertion and wrapper functions for testing asynchronous built-ins.
+defines: [asyncTest]
+---*/
+
+function asyncTest(testFunc) {
+ if (!Object.hasOwn(globalThis, "$DONE")) {
+ throw new Test262Error("asyncTest called without async flag");
+ }
+ if (typeof testFunc !== "function") {
+ $DONE(new Test262Error("asyncTest called with non-function argument"));
+ return;
+ }
+ try {
+ testFunc().then(
+ function () {
+ $DONE();
+ },
+ function (error) {
+ $DONE(error);
+ }
+ );
+ } catch (syncError) {
+ $DONE(syncError);
+ }
+}
+
+assert.throwsAsync = async function (expectedErrorConstructor, func, message) {
+ var innerThenable;
+ if (message === undefined) {
+ message = "";
+ } else {
+ message += " ";
+ }
+ if (typeof func === "function") {
+ try {
+ innerThenable = func();
+ if (
+ innerThenable === null ||
+ typeof innerThenable !== "object" ||
+ typeof innerThenable.then !== "function"
+ ) {
+ message +=
+ "Expected to obtain an inner promise that would reject with a" +
+ expectedErrorConstructor.name +
+ " but result was not a thenable";
+ throw new Test262Error(message);
+ }
+ } catch (thrown) {
+ message +=
+ "Expected a " +
+ expectedErrorConstructor.name +
+ " to be thrown asynchronously but an exception was thrown synchronously while obtaining the inner promise";
+ throw new Test262Error(message);
+ }
+ } else {
+ message +=
+ "assert.throwsAsync called with an argument that is not a function";
+ throw new Test262Error(message);
+ }
+
+ try {
+ return innerThenable.then(
+ function () {
+ message +=
+ "Expected a " +
+ expectedErrorConstructor.name +
+ " to be thrown asynchronously but no exception was thrown at all";
+ throw new Test262Error(message);
+ },
+ function (thrown) {
+ var expectedName, actualName;
+ if (typeof thrown !== "object" || thrown === null) {
+ message += "Thrown value was not an object!";
+ throw new Test262Error(message);
+ } else if (thrown.constructor !== expectedErrorConstructor) {
+ expectedName = expectedErrorConstructor.name;
+ actualName = thrown.constructor.name;
+ if (expectedName === actualName) {
+ message +=
+ "Expected a " +
+ expectedName +
+ " but got a different error constructor with the same name";
+ } else {
+ message +=
+ "Expected a " + expectedName + " but got a " + actualName;
+ }
+ throw new Test262Error(message);
+ }
+ }
+ );
+ } catch (thrown) {
+ if (typeof thrown !== "object" || thrown === null) {
+ message +=
+ "Expected a " +
+ expectedErrorConstructor.name +
+ " to be thrown asynchronously but innerThenable synchronously threw a value that was not an object ";
+ } else {
+ message +=
+ "Expected a " +
+ expectedErrorConstructor.name +
+ " to be thrown asynchronously but a " +
+ thrown.constructor.name +
+ " was thrown synchronously";
+ }
+ throw new Test262Error(message);
+ }
+};
diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/yield-iterator-next-rejected-promise-close.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/yield-iterator-next-rejected-promise-close.js
new file mode 100644
index 0000000000..26c35b6312
--- /dev/null
+++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/yield-iterator-next-rejected-promise-close.js
@@ -0,0 +1,63 @@
+// |reftest| async
+// Copyright (C) 2024 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-%asyncfromsynciteratorprototype%.next
+description: next() will reject promise if resolving result promise abrupt completes.
+info: |
+ %AsyncFromSyncIteratorPrototype%.next ( value )
+ ...
+ 3. Let promiseCapability be ! NewPromiseCapability(%Promise%).
+ 4. Let syncIteratorRecord be O.[[SyncIteratorRecord]].
+ 5. If value is present, then
+ ...
+ 6. Else,
+ a. Let result be IteratorNext(syncIteratorRecord).
+ 7. IfAbruptRejectPromise(result, promiseCapability).
+ 8. Return ! AsyncFromSyncIteratorContinuation(result, promiseCapability, syncIteratorRecord, true).
+
+ AsyncFromSyncIteratorContinuation ( result, promiseCapability, syncIteratorRecord, closeOnRejection )
+ 1. Let done be IteratorComplete(result).
+ 2. IfAbruptRejectPromise(done, promiseCapability).
+ 3. Let value be IteratorValue(result).
+ 4. IfAbruptRejectPromise(value, promiseCapability).
+ 5. Let valueWrapper be PromiseResolve(%Promise%, value).
+ 6. If valueWrapper is an abrupt completion, done is false, and closeOnRejection is true, then
+ a. Set valueWrapper to IteratorClose(syncIteratorRecord, valueWrapper).
+ ...
+ 12. If done is true, or if closeOnRejection is false, then
+ ...
+ 13. Else,
+ a. Let closeIterator be a new Abstract Closure with parameters (error) that captures syncIteratorRecord and performs the following steps when called:
+ i. Return ? IteratorClose(syncIteratorRecord, ThrowCompletion(error)).
+ b. Let onRejected be CreateBuiltinFunction(closeIterator, 1, "", « »).
+ c. NOTE: onRejected is used to close the Iterator when the "value" property of an IteratorResult object it yields is a rejected promise.
+ 14. Perform PerformPromiseThen(valueWrapper, onFulfilled, onRejected, promiseCapability).
+ 15. Return promiseCapability.[[Promise]].
+
+
+flags: [async]
+features: [async-iteration]
+includes: [asyncHelpers.js]
+---*/
+
+var finallyCount = 0;
+function Reject() {}
+
+function* iterator() {
+ try {
+ yield Promise.reject(new Reject());
+ } finally {
+ finallyCount += 1;
+ }
+}
+
+async function* asyncIterator() {
+ yield* iterator()
+}
+
+asyncTest(async () => {
+ await assert.throwsAsync(Reject, async () => asyncIterator().next(), "Promise should be rejected");
+ assert.sameValue(finallyCount, 1);
+});
diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/yield-next-rejected-promise-close.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/yield-next-rejected-promise-close.js
new file mode 100644
index 0000000000..d747bce581
--- /dev/null
+++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/next/yield-next-rejected-promise-close.js
@@ -0,0 +1,68 @@
+// |reftest| async
+// Copyright (C) 2024 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-%asyncfromsynciteratorprototype%.next
+description: next() will reject promise if resolving result promise abrupt completes.
+info: |
+ %AsyncFromSyncIteratorPrototype%.next ( value )
+ ...
+ 3. Let promiseCapability be ! NewPromiseCapability(%Promise%).
+ 4. Let syncIteratorRecord be O.[[SyncIteratorRecord]].
+ 5. If value is present, then
+ ...
+ 6. Else,
+ a. Let result be IteratorNext(syncIteratorRecord).
+ 7. IfAbruptRejectPromise(result, promiseCapability).
+ 8. Return ! AsyncFromSyncIteratorContinuation(result, promiseCapability, syncIteratorRecord, true).
+
+ AsyncFromSyncIteratorContinuation ( result, promiseCapability, syncIteratorRecord, closeOnRejection )
+ 1. Let done be IteratorComplete(result).
+ 2. IfAbruptRejectPromise(done, promiseCapability).
+ 3. Let value be IteratorValue(result).
+ 4. IfAbruptRejectPromise(value, promiseCapability).
+ 5. Let valueWrapper be PromiseResolve(%Promise%, value).
+ 6. If valueWrapper is an abrupt completion, done is false, and closeOnRejection is true, then
+ a. Set valueWrapper to IteratorClose(syncIteratorRecord, valueWrapper).
+ ...
+ 12. If done is true, or if closeOnRejection is false, then
+ ...
+ 13. Else,
+ a. Let closeIterator be a new Abstract Closure with parameters (error) that captures syncIteratorRecord and performs the following steps when called:
+ i. Return ? IteratorClose(syncIteratorRecord, ThrowCompletion(error)).
+ b. Let onRejected be CreateBuiltinFunction(closeIterator, 1, "", « »).
+ c. NOTE: onRejected is used to close the Iterator when the "value" property of an IteratorResult object it yields is a rejected promise.
+ 14. Perform PerformPromiseThen(valueWrapper, onFulfilled, onRejected, promiseCapability).
+ 15. Return promiseCapability.[[Promise]].
+
+
+flags: [async]
+features: [async-iteration]
+includes: [asyncHelpers.js]
+---*/
+
+var returnCount = 0;
+function Reject() {}
+
+const syncIterator = {
+ [Symbol.iterator]() {
+ return {
+ next() {
+ return { value: Promise.reject(new Reject()), done: false };
+ },
+ return() {
+ returnCount += 1;
+ }
+ };
+ }
+}
+
+async function* asyncIterator() {
+ yield* syncIterator;
+}
+
+asyncTest(async () => {
+ await assert.throwsAsync(Reject, async () => asyncIterator().next(), "Promise should be rejected");
+ assert.sameValue(returnCount, 1);
+});
diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/absent-value-not-passed.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/absent-value-not-passed.js
new file mode 100644
index 0000000000..21686a8896
--- /dev/null
+++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/absent-value-not-passed.js
@@ -0,0 +1,43 @@
+// |reftest| async
+// Copyright (C) 2020 Alexey Shvayka. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-%asyncfromsynciteratorprototype%.return
+description: >
+ `return` method does not pass absent `value`.
+info: |
+ %AsyncFromSyncIteratorPrototype%.return ( value )
+
+ [...]
+ 8. If value is present, then
+ [...]
+ 9. Else,
+ a. Let result be Call(return, syncIterator).
+ [...]
+flags: [async]
+features: [async-iteration]
+includes: [asyncHelpers.js]
+---*/
+
+var returnArgumentsLength;
+var syncIterator = {
+ [Symbol.iterator]() {
+ return this;
+ },
+ next() {
+ return {done: false};
+ },
+ return() {
+ returnArgumentsLength = arguments.length;
+ return {done: true};
+ },
+};
+
+asyncTest(async function () {
+ for await (let _ of syncIterator) {
+ break;
+ }
+
+ assert.sameValue(returnArgumentsLength, 0);
+});
diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/browser.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/browser.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/browser.js
diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/iterator-result-poisoned-done.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/iterator-result-poisoned-done.js
new file mode 100644
index 0000000000..de5639aa9d
--- /dev/null
+++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/iterator-result-poisoned-done.js
@@ -0,0 +1,71 @@
+// |reftest| async
+// Copyright (C) 2018 Valerie Young. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-%asyncfromsynciteratorprototype%.return
+description: return() will reject promise if getter `done` abrupt completes
+info: |
+ %AsyncFromSyncIteratorPrototype%.return ( value )
+ ...
+ 2. Let promiseCapability be ! NewPromiseCapability(%Promise%).
+ ...
+ 5. Let return be GetMethod(syncIterator, "return").
+ ...
+ 8. Let returnResult be Call(return, syncIterator, « value »).
+ 9. IfAbruptRejectPromise(returnResult, promiseCapability).
+ ...
+ 11. Let returnDone be IteratorComplete(returnResult).
+ 12. IfAbruptRejectPromise(returnDone, promiseCapability).
+ 13. Let returnValue be IteratorValue(returnResult).
+ 14. IfAbruptRejectPromise(returnValue, promiseCapability).
+ ...
+ 22. Return promiseCapability.[[Promise]].
+
+flags: [async]
+features: [async-iteration]
+---*/
+
+var thrownError = new Error("Catch me.");
+
+var obj = {
+ [Symbol.iterator]() {
+ return {
+ next() {
+ return { value: 1, done: false };
+ },
+ return() {
+ return {
+ get done() {
+ throw thrownError;
+ },
+ value: 1
+ }
+ }
+ };
+ }
+};
+
+async function* asyncg() {
+ yield* obj;
+}
+
+var iter = asyncg();
+
+iter.next().then(function(result) {
+
+ iter.return().then(
+ function (result) {
+ throw new Test262Error("Promise should be rejected, got: " + result.value);
+ },
+ function (err) {
+ assert.sameValue(err, thrownError, "Promise should be rejected with thrown error");
+
+ iter.next().then(({ done, value }) => {
+ assert.sameValue(done, true, 'the iterator is completed');
+ assert.sameValue(value, undefined, 'value is undefined');
+ }).then($DONE, $DONE);
+ }
+ ).catch($DONE);
+
+}).catch($DONE);
diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/iterator-result-poisoned-value.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/iterator-result-poisoned-value.js
new file mode 100644
index 0000000000..369319f098
--- /dev/null
+++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/iterator-result-poisoned-value.js
@@ -0,0 +1,71 @@
+// |reftest| async
+// Copyright (C) 2018 Valerie Young. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-%asyncfromsynciteratorprototype%.return
+description: return() will reject promise if getter `value` abrupt completes
+info: |
+ %AsyncFromSyncIteratorPrototype%.return ( value )
+ ...
+ 2. Let promiseCapability be ! NewPromiseCapability(%Promise%).
+ ...
+ 5. Let return be GetMethod(syncIterator, "return").
+ ...
+ 8. Let returnResult be Call(return, syncIterator, « value »).
+ 9. IfAbruptRejectPromise(returnResult, promiseCapability).
+ ...
+ 11. Let returnDone be IteratorComplete(returnResult).
+ 12. IfAbruptRejectPromise(returnDone, promiseCapability).
+ 13. Let returnValue be IteratorValue(returnResult).
+ 14. IfAbruptRejectPromise(returnValue, promiseCapability).
+ ...
+ 22. Return promiseCapability.[[Promise]].
+
+flags: [async]
+features: [async-iteration]
+---*/
+
+
+var thrownError = new Error("Catch me.");
+var obj = {
+ [Symbol.iterator]() {
+ return {
+ next() {
+ return { value: 1, done: false };
+ },
+ return() {
+ return {
+ get value() {
+ throw thrownError;
+ },
+ done: false
+ }
+ }
+ };
+ }
+};
+
+async function* asyncg() {
+ yield* obj;
+}
+
+var iter = asyncg();
+
+iter.next().then(function(result) {
+
+ iter.return().then(
+ function (result) {
+ throw new Test262Error("Promise should be rejected, got: " + result.value);
+ },
+ function (err) {
+ assert.sameValue(err, thrownError, "Promise should be rejected with thrown error");
+
+ iter.next().then(({ done, value }) => {
+ assert.sameValue(done, true, 'the iterator is completed');
+ assert.sameValue(value, undefined, 'value is undefined');
+ }).then($DONE, $DONE);
+ }
+ ).catch($DONE);
+
+}).catch($DONE);
diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/iterator-result-unwrap-promise.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/iterator-result-unwrap-promise.js
new file mode 100644
index 0000000000..5d69a98f7f
--- /dev/null
+++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/iterator-result-unwrap-promise.js
@@ -0,0 +1,65 @@
+// |reftest| async
+// Copyright (C) 2018 Valerie Young. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-%asyncfromsynciteratorprototype%.return
+description: return() will unwrap a Promise value return by the sync iterator
+info: |
+ %AsyncFromSyncIteratorPrototype%.return ( value )
+ ...
+ 2. Let promiseCapability be ! NewPromiseCapability(%Promise%).
+ ...
+ 5. Let return be GetMethod(syncIterator, "return").
+ ...
+ 17. Let steps be the algorithm steps defined in Async-from-Sync Iterator Value Unwrap Functions.
+ ...
+ 22. Return promiseCapability.[[Promise]].
+
+ Async-from-Sync Iterator Value Unwrap Functions
+ An async-from-sync iterator value unwrap function is an anonymous built-in
+ function that is used by methods of %AsyncFromSyncIteratorPrototype% when
+ processing the value field of an IteratorResult object, in order to wait for
+ its value if it is a promise and re-package the result in a new "unwrapped"
+ IteratorResult object. Each async iterator value unwrap function has a
+ [[Done]] internal slot.
+
+flags: [async]
+features: [async-iteration]
+---*/
+
+var obj = {
+ [Symbol.iterator]() {
+ return {
+ next() {
+ return { value: 1, done: false };
+ },
+ return() {
+ return {
+ value: Promise.resolve(42),
+ done: true
+ };
+ }
+ };
+ }
+};
+
+async function* asyncg() {
+ yield* obj;
+}
+
+let iter = asyncg();
+
+iter.next().then(function (result) {
+ iter.return().then(
+ function (result) {
+ assert.sameValue(result.value, 42, "Result.value should be unwrapped, got: " + result.value);
+
+ iter.next().then(({ done, value }) => {
+ assert.sameValue(done, true, 'the iterator is completed');
+ assert.sameValue(value, undefined, 'value is undefined');
+ }).then($DONE, $DONE);
+ }
+ ).catch($DONE);
+
+}).catch($DONE);
diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/iterator-result.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/iterator-result.js
new file mode 100644
index 0000000000..38ac3eeaa5
--- /dev/null
+++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/iterator-result.js
@@ -0,0 +1,56 @@
+// |reftest| async
+// Copyright (C) 2018 Valerie Young. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-%asyncfromsynciteratorprototype%.return
+description: return() will return a iterator result object when built-in sync throw is called
+info: |
+ %AsyncFromSyncIteratorPrototype%.return ( value )
+ ...
+ 2. Let promiseCapability be ! NewPromiseCapability(%Promise%).
+ ...
+ 5. Let return be GetMethod(syncIterator, "return").
+ ...
+ 8. Let returnResult be Call(return, syncIterator, « value »).
+ ...
+ 22. Return promiseCapability.[[Promise]].
+
+ Generator.prototype.return ( value )
+ 1. Let g be the this value.
+ 2. Let C be Completion{[[Type]]: return, [[Value]]: value, [[Target]]: empty}.
+ 3. Return ? GeneratorResumeAbrupt(g, C).
+
+flags: [async]
+features: [async-iteration]
+---*/
+
+function* g() {
+ yield 42;
+ throw new Test262Error('return closes iter');
+ yield 43;
+}
+
+async function* asyncg() {
+ yield* g();
+}
+
+var iter = asyncg();
+var val = 'some specific return value'
+
+iter.next().then(function(result) {
+
+ // return will call sync generator prototype built-in function return
+ iter.return(val).then(function(result) {
+
+ assert.sameValue(result.done, true, 'the iterator is completed');
+ assert.sameValue(result.value, val, 'expect agrument to `return`');
+
+ iter.next().then(({ done, value }) => {
+ assert.sameValue(done, true, 'the iterator is completed');
+ assert.sameValue(value, undefined, 'value is undefined');
+ }).then($DONE, $DONE);
+
+ }).catch($DONE);
+
+}).catch($DONE);
diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/poisoned-get-return.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/poisoned-get-return.js
new file mode 100644
index 0000000000..c91a1954d5
--- /dev/null
+++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/poisoned-get-return.js
@@ -0,0 +1,60 @@
+// |reftest| async
+// Copyright (C) 2018 Valerie Young. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-%asyncfromsynciteratorprototype%.return
+description: return() will return rejected promise if getter of `return` abrupt completes
+info: |
+ %AsyncFromSyncIteratorPrototype%.return ( value )
+ ...
+ 2. Let promiseCapability be ! NewPromiseCapability(%Promise%).
+ ...
+ 5. Let return be GetMethod(syncIterator, "return").
+ 6. IfAbruptRejectPromise(return, promiseCapability).
+ ...
+ 22. Return promiseCapability.[[Promise]].
+
+flags: [async]
+features: [async-iteration]
+---*/
+
+var thrownError = new Error("Catch me.");
+
+var obj = {
+ [Symbol.iterator]() {
+ return {
+ next() {
+ return { value: 1, done: false };
+ },
+ get return() {
+ throw thrownError;
+ }
+ }
+ }
+};
+
+async function* asyncg() {
+ yield* obj;
+}
+
+var iter = asyncg();
+
+iter.next().then(function(result) {
+
+ iter.return().then(
+ function (result) {
+ throw new Test262Error("Promise should be rejected, got: " + result.value);
+ },
+ function (err) {
+ assert.sameValue(err, thrownError, "Promise should be rejected with thrown error");
+
+ iter.next().then(({ done, value }) => {
+ assert.sameValue(done, true, 'the iterator is completed');
+ assert.sameValue(value, undefined, 'value is undefined');
+ }).then($DONE, $DONE);
+ }
+ ).catch($DONE);
+
+}).catch($DONE);
+
diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/poisoned-return.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/poisoned-return.js
new file mode 100644
index 0000000000..19d2be92d8
--- /dev/null
+++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/poisoned-return.js
@@ -0,0 +1,66 @@
+// |reftest| async
+// Copyright (C) 2018 Valerie Young. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-%asyncfromsynciteratorprototype%.return
+description: return() will return rejected promise if getter of `return` abrupt completes
+info: |
+ %AsyncFromSyncIteratorPrototype%.return ( value )
+ ...
+ 2. Let promiseCapability be ! NewPromiseCapability(%Promise%).
+ ...
+ 5. Let return be GetMethod(syncIterator, "return").
+ 6. IfAbruptRejectPromise(return, promiseCapability).
+ ...
+ 8. Let returnResult be Call(return, syncIterator, « value »).
+ ...
+ 10. If Type(returnResult) is not Object,
+ a. Perform ! Call(promiseCapability.[[Reject]], undefined, « a TypeError exception »).
+ b. Return promiseCapability.[[Promise]].
+ ...
+ 22. Return promiseCapability.[[Promise]].
+
+flags: [async]
+features: [async-iteration]
+---*/
+
+var thrownError = new Error("Catch me.");
+
+var obj = {
+ [Symbol.iterator]() {
+ return {
+ next() {
+ return { value: 1, done: false };
+ },
+ return() {
+ throw thrownError;
+ }
+ };
+ }
+};
+
+async function* asyncg() {
+ yield* obj;
+}
+
+var iter = asyncg();
+
+iter.next().then(function(result) {
+
+ iter.return().then(
+ function (result) {
+ throw new Test262Error("Promise should be rejected, got: " + result.value);
+ },
+ function (err) {
+ assert.sameValue(err, thrownError, "Promise should be rejected with thrown error");
+
+ iter.next().then(({ done, value }) => {
+ assert.sameValue(done, true, 'the iterator is completed');
+ assert.sameValue(value, undefined, 'value is undefined');
+ }).then($DONE, $DONE);
+ }
+ ).catch($DONE);
+
+}).catch($DONE);
+
diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/result-object-error.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/result-object-error.js
new file mode 100644
index 0000000000..153ff47f41
--- /dev/null
+++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/result-object-error.js
@@ -0,0 +1,65 @@
+// |reftest| async
+// Copyright (C) 2018 Valerie Young. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-%asyncfromsynciteratorprototype%.return
+description: return() will return rejected promise if getter of `return` abrupt completes
+info: |
+ %AsyncFromSyncIteratorPrototype%.return ( value )
+ ...
+ 2. Let promiseCapability be ! NewPromiseCapability(%Promise%).
+ ...
+ 5. Let return be GetMethod(syncIterator, "return").
+ 6. IfAbruptRejectPromise(return, promiseCapability).
+ ...
+ 8. Let returnResult be Call(return, syncIterator, « value »).
+ ...
+ 10. If Type(returnResult) is not Object,
+ a. Perform ! Call(promiseCapability.[[Reject]], undefined, « a TypeError exception »).
+ b. Return promiseCapability.[[Promise]].
+ ...
+ 22. Return promiseCapability.[[Promise]].
+
+flags: [async]
+features: [async-iteration]
+---*/
+
+var obj = {
+ [Symbol.iterator]() {
+ return {
+ next() {
+ return { value: 1, done: false };
+ },
+ return() {
+ return 1;
+ }
+ };
+ }
+};
+
+async function* asyncg() {
+ yield* obj;
+}
+
+var iter = asyncg();
+
+iter.next().then(function(result) {
+
+ iter.return().then(
+ function (result) {
+ throw new Test262Error("Promise should be rejected, got: " + result.value);
+ },
+ function (err) {
+ let typeerror = err instanceof TypeError;
+ assert(typeerror, "Expect TypeError, got: " + err);
+
+ iter.next().then(({ done, value }) => {
+ assert.sameValue(done, true, 'the iterator is completed');
+ assert.sameValue(value, undefined, 'value is undefined');
+ }).then($DONE, $DONE);
+ }
+ ).catch($DONE);
+
+}).catch($DONE);
+
diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/return-null.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/return-null.js
new file mode 100644
index 0000000000..50f94bba85
--- /dev/null
+++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/return-null.js
@@ -0,0 +1,55 @@
+// |reftest| async
+// Copyright (C) 2020 Alexey Shvayka. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-%asyncfromsynciteratorprototype%.return
+description: >
+ If syncIterator's "return" method is `null`,
+ a Promise resolved with `undefined` value is returned.
+info: |
+ %AsyncFromSyncIteratorPrototype%.return ( value )
+
+ [...]
+ 5. Let return be GetMethod(syncIterator, "return").
+ [...]
+ 7. If return is undefined, then
+ a. Let iterResult be ! CreateIterResultObject(value, true).
+ b. Perform ! Call(promiseCapability.[[Resolve]], undefined, « iterResult »).
+ c. Return promiseCapability.[[Promise]].
+
+ GetMethod ( V, P )
+
+ [...]
+ 2. Let func be ? GetV(V, P).
+ 3. If func is either undefined or null, return undefined.
+flags: [async]
+features: [async-iteration]
+includes: [asyncHelpers.js]
+---*/
+
+var iterationCount = 0;
+var returnGets = 0;
+
+var syncIterator = {
+ [Symbol.iterator]() {
+ return this;
+ },
+ next() {
+ return {value: 1, done: false};
+ },
+ get return() {
+ returnGets += 1;
+ return null;
+ },
+};
+
+asyncTest(async function() {
+ for await (let _ of syncIterator) {
+ iterationCount += 1;
+ break;
+ }
+
+ assert.sameValue(iterationCount, 1);
+ assert.sameValue(returnGets, 1);
+});
diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/return-undefined.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/return-undefined.js
new file mode 100644
index 0000000000..5e5e766288
--- /dev/null
+++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/return-undefined.js
@@ -0,0 +1,55 @@
+// |reftest| async
+// Copyright (C) 2018 Valerie Young. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-%asyncfromsynciteratorprototype%.throw
+description: return() will return value undefined if sync `return` is undefined
+info: |
+ %AsyncFromSyncIteratorPrototype%.return ( value )
+ ...
+ 2. Let promiseCapability be ! NewPromiseCapability(%Promise%).
+ ...
+ 5. Let return be GetMethod(syncIterator, "return").
+ 6. IfAbruptRejectPromise(return, promiseCapability).
+ 7. If return is undefined, then
+ a. Let iterResult be ! CreateIterResultObject(value, true).
+ b. Perform ! Call(promiseCapability.[[Resolve]], undefined, « iterResult »).
+ c. Return promiseCapability.[[Promise]].
+
+flags: [async]
+features: [async-iteration]
+---*/
+
+
+var obj = {
+ [Symbol.iterator]() {
+ return {
+ next() {
+ return { value: 1, done: false };
+ }
+ };
+ }
+};
+
+async function* asyncg() {
+ yield* obj;
+}
+
+var iter = asyncg();
+
+iter.next().then(function(result) {
+
+ iter.return().then(function(result) {
+
+ assert.sameValue(result.done, true, 'the iterator is completed');
+ assert.sameValue(result.value, undefined, 'expect value to be undefined');
+
+ iter.next().then(({ done, value }) => {
+ assert.sameValue(done, true, 'the iterator is completed');
+ assert.sameValue(value, undefined, 'value is undefined');
+ }).then($DONE, $DONE);
+
+ }).catch($DONE);
+
+}).catch($DONE);
diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/shell.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/shell.js
new file mode 100644
index 0000000000..ae18ad584d
--- /dev/null
+++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/return/shell.js
@@ -0,0 +1,113 @@
+// GENERATED, DO NOT EDIT
+// file: asyncHelpers.js
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: |
+ A collection of assertion and wrapper functions for testing asynchronous built-ins.
+defines: [asyncTest]
+---*/
+
+function asyncTest(testFunc) {
+ if (!Object.hasOwn(globalThis, "$DONE")) {
+ throw new Test262Error("asyncTest called without async flag");
+ }
+ if (typeof testFunc !== "function") {
+ $DONE(new Test262Error("asyncTest called with non-function argument"));
+ return;
+ }
+ try {
+ testFunc().then(
+ function () {
+ $DONE();
+ },
+ function (error) {
+ $DONE(error);
+ }
+ );
+ } catch (syncError) {
+ $DONE(syncError);
+ }
+}
+
+assert.throwsAsync = async function (expectedErrorConstructor, func, message) {
+ var innerThenable;
+ if (message === undefined) {
+ message = "";
+ } else {
+ message += " ";
+ }
+ if (typeof func === "function") {
+ try {
+ innerThenable = func();
+ if (
+ innerThenable === null ||
+ typeof innerThenable !== "object" ||
+ typeof innerThenable.then !== "function"
+ ) {
+ message +=
+ "Expected to obtain an inner promise that would reject with a" +
+ expectedErrorConstructor.name +
+ " but result was not a thenable";
+ throw new Test262Error(message);
+ }
+ } catch (thrown) {
+ message +=
+ "Expected a " +
+ expectedErrorConstructor.name +
+ " to be thrown asynchronously but an exception was thrown synchronously while obtaining the inner promise";
+ throw new Test262Error(message);
+ }
+ } else {
+ message +=
+ "assert.throwsAsync called with an argument that is not a function";
+ throw new Test262Error(message);
+ }
+
+ try {
+ return innerThenable.then(
+ function () {
+ message +=
+ "Expected a " +
+ expectedErrorConstructor.name +
+ " to be thrown asynchronously but no exception was thrown at all";
+ throw new Test262Error(message);
+ },
+ function (thrown) {
+ var expectedName, actualName;
+ if (typeof thrown !== "object" || thrown === null) {
+ message += "Thrown value was not an object!";
+ throw new Test262Error(message);
+ } else if (thrown.constructor !== expectedErrorConstructor) {
+ expectedName = expectedErrorConstructor.name;
+ actualName = thrown.constructor.name;
+ if (expectedName === actualName) {
+ message +=
+ "Expected a " +
+ expectedName +
+ " but got a different error constructor with the same name";
+ } else {
+ message +=
+ "Expected a " + expectedName + " but got a " + actualName;
+ }
+ throw new Test262Error(message);
+ }
+ }
+ );
+ } catch (thrown) {
+ if (typeof thrown !== "object" || thrown === null) {
+ message +=
+ "Expected a " +
+ expectedErrorConstructor.name +
+ " to be thrown asynchronously but innerThenable synchronously threw a value that was not an object ";
+ } else {
+ message +=
+ "Expected a " +
+ expectedErrorConstructor.name +
+ " to be thrown asynchronously but a " +
+ thrown.constructor.name +
+ " was thrown synchronously";
+ }
+ throw new Test262Error(message);
+ }
+};
diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/shell.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/shell.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/shell.js
diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/browser.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/browser.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/browser.js
diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/iterator-result-poisoned-done.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/iterator-result-poisoned-done.js
new file mode 100644
index 0000000000..bab1bf956d
--- /dev/null
+++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/iterator-result-poisoned-done.js
@@ -0,0 +1,70 @@
+// |reftest| async
+// Copyright (C) 2018 Valerie Young. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-%asyncfromsynciteratorprototype%.throw
+description: throw() will reject promise if getter `done` abrupt completes
+info: |
+ %AsyncFromSyncIteratorPrototype%.throw ( value )
+ ...
+ 2. Let promiseCapability be ! NewPromiseCapability(%Promise%).
+ ...
+ 5. Let throw be GetMethod(syncIterator, "throw").
+ ...
+ 8. Let throwResult be Call(throw, syncIterator, « value »).
+ ...
+ 11. Let throwDone be IteratorComplete(throwResult).
+ 12. IfAbruptRejectPromise(throwDone, promiseCapability).
+ 13. Let throwValue be IteratorValue(throwResult).
+ 14. IfAbruptRejectPromise(throwValue, promiseCapability).
+ ...
+ 20. Return promiseCapability.[[Promise]].
+
+flags: [async]
+features: [async-iteration]
+---*/
+
+var thrownError = new Error("Catch me.");
+
+var obj = {
+ [Symbol.iterator]() {
+ return {
+ next() {
+ return { value: 1, done: false };
+ },
+ throw() {
+ return {
+ get done() {
+ throw thrownError;
+ },
+ value: 1
+ };
+ }
+ };
+ }
+};
+
+async function* asyncg() {
+ yield* obj;
+}
+
+var iter = asyncg();
+
+iter.next().then(function(result) {
+
+ iter.throw().then(
+ function (result) {
+ throw new Test262Error("Promise should be rejected, got: " + result.value);
+ },
+ function (err) {
+ assert.sameValue(err, thrownError, "Promise should be rejected with thrown error");
+
+ iter.next().then(({ done, value }) => {
+ assert.sameValue(done, true, 'the iterator is completed');
+ assert.sameValue(value, undefined, 'value is undefined');
+ }).then($DONE, $DONE);
+ }
+ ).catch($DONE);
+
+}).catch($DONE);
diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/iterator-result-poisoned-value.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/iterator-result-poisoned-value.js
new file mode 100644
index 0000000000..9745df52c1
--- /dev/null
+++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/iterator-result-poisoned-value.js
@@ -0,0 +1,70 @@
+// |reftest| async
+// Copyright (C) 2018 Valerie Young. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-%asyncfromsynciteratorprototype%.throw
+description: throw() will reject promise if getter `value` abrupt completes
+info: |
+ %AsyncFromSyncIteratorPrototype%.throw ( value )
+ ...
+ 2. Let promiseCapability be ! NewPromiseCapability(%Promise%).
+ ...
+ 5. Let throw be GetMethod(syncIterator, "throw").
+ ...
+ 8. Let throwResult be Call(throw, syncIterator, « value »).
+ ...
+ 11. Let throwDone be IteratorComplete(throwResult).
+ 12. IfAbruptRejectPromise(throwDone, promiseCapability).
+ 13. Let throwValue be IteratorValue(throwResult).
+ 14. IfAbruptRejectPromise(throwValue, promiseCapability).
+ ...
+ 20. Return promiseCapability.[[Promise]].
+
+flags: [async]
+features: [async-iteration]
+---*/
+
+var thrownError = new Error("Catch me.");
+
+var obj = {
+ [Symbol.iterator]() {
+ return {
+ next() {
+ return { value: 1, done: false };
+ },
+ throw() {
+ return {
+ get value() {
+ throw thrownError;
+ },
+ done: false
+ };
+ }
+ }
+ }
+};
+
+async function* asyncg() {
+ yield* obj;
+}
+
+var iter = asyncg();
+
+iter.next().then(function(result) {
+
+ iter.throw().then(
+ function (result) {
+ throw new Test262Error("Promise should be rejected, got: " + result.value);
+ },
+ function (err) {
+ assert.sameValue(err, thrownError, "Promise should be rejected with thrown error");
+
+ iter.next().then(({ done, value }) => {
+ assert.sameValue(done, true, 'the iterator is completed');
+ assert.sameValue(value, undefined, 'value is undefined');
+ }).then($DONE, $DONE);
+ }
+ ).catch($DONE);
+
+}).catch($DONE);
diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/iterator-result-rejected-promise-close.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/iterator-result-rejected-promise-close.js
new file mode 100644
index 0000000000..4d27039be8
--- /dev/null
+++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/iterator-result-rejected-promise-close.js
@@ -0,0 +1,84 @@
+// |reftest| async
+// Copyright (C) 2024 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-%asyncfromsynciteratorprototype%.throw
+description: throw() will reject promise if resolving result promise abrupt completes.
+info: |
+ %AsyncFromSyncIteratorPrototype%.throw ( value )
+ ...
+ 3. Let promiseCapability be ! NewPromiseCapability(%Promise%).
+ 4. Let syncIteratorRecord be O.[[SyncIteratorRecord]].
+ 5. Let syncIterator be syncIteratorRecord.[[Iterator]].
+ 6. Let throw be GetMethod(syncIterator, "throw").
+ ...
+ 9. If value is present, then
+ ...
+ 10. Else,
+ a. Let result be Call(throw,syncIterator).
+ ...
+ 13. Return ! AsyncFromSyncIteratorContinuation(result, promiseCapability, syncIteratorRecord, true).
+
+ AsyncFromSyncIteratorContinuation ( result, promiseCapability, syncIteratorRecord, closeOnRejection )
+ 1. Let done be IteratorComplete(result).
+ 2. IfAbruptRejectPromise(done, promiseCapability).
+ 3. Let value be IteratorValue(result).
+ 4. IfAbruptRejectPromise(value, promiseCapability).
+ 5. Let valueWrapper be PromiseResolve(%Promise%, value).
+ 6. If valueWrapper is an abrupt completion, done is false, and closeOnRejection is true, then
+ a. Set valueWrapper to IteratorClose(syncIteratorRecord, valueWrapper).
+ ...
+ 12. If done is true, or if closeOnRejection is false, then
+ ...
+ 13. Else,
+ a. Let closeIterator be a new Abstract Closure with parameters (error) that captures syncIteratorRecord and performs the following steps when called:
+ i. Return ? IteratorClose(syncIteratorRecord, ThrowCompletion(error)).
+ b. Let onRejected be CreateBuiltinFunction(closeIterator, 1, "", « »).
+ c. NOTE: onRejected is used to close the Iterator when the "value" property of an IteratorResult object it yields is a rejected promise.
+ 14. Perform PerformPromiseThen(valueWrapper, onFulfilled, onRejected, promiseCapability).
+ 15. Return promiseCapability.[[Promise]].
+
+flags: [async]
+features: [async-iteration]
+includes: [asyncHelpers.js]
+---*/
+
+var returnCount = 0;
+function Reject() {}
+
+var obj = {
+ [Symbol.iterator]() {
+ return {
+ next() {
+ return { value: 1, done: false };
+ },
+ throw() {
+ return {
+ value: Promise.reject(new Reject()),
+ done: false
+ };
+ },
+ return() {
+ returnCount += 1;
+ }
+ };
+ }
+};
+
+async function* asyncg() {
+ return yield* obj;
+}
+
+let iter = asyncg();
+
+asyncTest(async function () {
+ await assert.throwsAsync(Reject, async () => {
+ await iter.next();
+ return iter.throw();
+ }, "Promise should be rejected");
+ assert.sameValue(returnCount, 1);
+ const result = await iter.next();
+ assert(result.done, "the iterator is completed");
+ assert.sameValue(result.value, undefined, "value is undefined");
+})
diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/iterator-result-unwrap-promise.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/iterator-result-unwrap-promise.js
new file mode 100644
index 0000000000..9542254c75
--- /dev/null
+++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/iterator-result-unwrap-promise.js
@@ -0,0 +1,66 @@
+// |reftest| async
+// Copyright (C) 2018 Valerie Young. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-%asyncfromsynciteratorprototype%.throw
+description: throw() will unwrap a Promise value return by the sync iterator
+info: |
+ %AsyncFromSyncIteratorPrototype%.throw ( value )
+ ...
+ 2. Let promiseCapability be ! NewPromiseCapability(%Promise%).
+ ...
+ 5. Let throw be GetMethod(syncIterator, "throw").
+ ...
+ 17. Let steps be the algorithm steps defined in Async-from-Sync Iterator Value Unwrap Functions.
+ ...
+ 20. Return promiseCapability.[[Promise]].
+
+ Async-from-Sync Iterator Value Unwrap Functions
+ An async-from-sync iterator value unwrap function is an anonymous built-in
+ function that is used by methods of %AsyncFromSyncIteratorPrototype% when
+ processing the value field of an IteratorResult object, in order to wait for
+ its value if it is a promise and re-package the result in a new "unwrapped"
+ IteratorResult object. Each async iterator value unwrap function has a
+ [[Done]] internal slot.
+
+flags: [async]
+features: [async-iteration]
+---*/
+
+var thrownError = new Error("Don't catch me.")
+
+var obj = {
+ [Symbol.iterator]() {
+ return {
+ next() {
+ return { value: 1, done: false };
+ },
+ throw() {
+ return {
+ value: Promise.resolve(42),
+ done: true
+ };
+ }
+ };
+ }
+};
+
+async function* asyncg() {
+ return yield* obj;
+}
+
+let iter = asyncg();
+
+iter.next().then(function (result) {
+ iter.throw(thrownError).then(
+ function (result) {
+ assert.sameValue(result.value, 42, "Result.value should be unwrapped, got: " + result.value);
+
+ iter.next().then(({ done, value }) => {
+ assert.sameValue(done, true, 'the iterator is completed');
+ assert.sameValue(value, undefined, 'value is undefined');
+ }).then($DONE, $DONE);
+ }
+ ).catch($DONE);
+}).catch($DONE);
diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/iterator-result.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/iterator-result.js
new file mode 100644
index 0000000000..90b02da8c2
--- /dev/null
+++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/iterator-result.js
@@ -0,0 +1,60 @@
+// |reftest| async
+// Copyright (C) 2018 Valerie Young. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-%asyncfromsynciteratorprototype%.throw
+description: throw() will call default sync throw
+info: |
+ %AsyncFromSyncIteratorPrototype%.throw ( value )
+ ...
+ 2. Let promiseCapability be ! NewPromiseCapability(%Promise%).
+ ...
+ 5. Let throw be GetMethod(syncIterator, "throw").
+ ...
+ 8. Let throwResult be Call(throw, syncIterator, « value »)
+ 9. IfAbruptRejectPromise(throwResult, promiseCapability).
+ ...
+ 22. Return promiseCapability.[[Promise]].
+
+ Generator.prototype.throw ( exception )
+ 1. Let g be the this value.
+ 2. Let C be Completion{[[Type]]: throw, [[Value]]: exception, [[Target]]: empty}.
+ 3. Return ? GeneratorResumeAbrupt(g, C).
+
+flags: [async]
+features: [async-iteration]
+---*/
+
+var thrownError = new Error("Catch me.")
+
+function* g() {
+ yield 42;
+ throw new Test262Error('throw closes iter');
+ yield 43;
+}
+
+async function* asyncg() {
+ yield* g();
+}
+
+var iter = asyncg();
+
+iter.next().then(function(result) {
+
+ // throw will call sync generator prototype built-in function throw
+ iter.throw(thrownError).then(
+ function(result) {
+ throw new Test262Error('throw should cause rejection of promise');
+ },
+ function(err) {
+ assert.sameValue(err, thrownError, "promise should be reject with custom error, got: " + err)
+
+ iter.next().then(({ done, value }) => {
+ assert.sameValue(done, true, 'the iterator is completed');
+ assert.sameValue(value, undefined, 'value is undefined');
+ }).then($DONE, $DONE);
+ }
+ ).catch($DONE);
+
+}).catch($DONE);
diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/poisoned-get-throw.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/poisoned-get-throw.js
new file mode 100644
index 0000000000..5a87c2e2ba
--- /dev/null
+++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/poisoned-get-throw.js
@@ -0,0 +1,59 @@
+// |reftest| async
+// Copyright (C) 2018 Valerie Young. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-%asyncfromsynciteratorprototype%.throw
+description: throw() will return rejected promise if getter of `throw` abrupt completes
+info: |
+ %AsyncFromSyncIteratorPrototype%.return ( value )
+ ...
+ 2. Let promiseCapability be ! NewPromiseCapability(%Promise%).
+ ...
+ 5. Let return be GetMethod(syncIterator, "throw").
+ 6. IfAbruptRejectPromise(throw, promiseCapability).
+ ...
+ 22. Return promiseCapability.[[Promise]].
+
+flags: [async]
+features: [async-iteration]
+---*/
+
+var thrownError = new Error("Catch me.");
+
+var obj = {
+ [Symbol.iterator]() {
+ return {
+ next() {
+ return { value: 1, done: false };
+ },
+ get throw() {
+ throw thrownError;
+ }
+ };
+ }
+};
+
+async function* asyncg() {
+ yield* obj;
+}
+
+var iter = asyncg();
+
+iter.next().then(function(result) {
+
+ iter.throw().then(
+ function (result) {
+ throw new Test262Error("Promise should be rejected, got: " + result.value);
+ },
+ function (err) {
+ assert.sameValue(err, thrownError, "Promise should be rejected with thrown error");
+
+ iter.next().then(({ done, value }) => {
+ assert.sameValue(done, true, 'the iterator is completed');
+ assert.sameValue(value, undefined, 'value is undefined');
+ }).then($DONE, $DONE);
+ }
+ ).catch($DONE);
+
+}).catch($DONE);
diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/poisoned-throw.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/poisoned-throw.js
new file mode 100644
index 0000000000..15656dbff8
--- /dev/null
+++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/poisoned-throw.js
@@ -0,0 +1,61 @@
+// |reftest| async
+// Copyright (C) 2018 Valerie Young. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-%asyncfromsynciteratorprototype%.throw
+description: throw() will return rejected promise if getter of `throw` abrupt completes
+info: |
+ %AsyncFromSyncIteratorPrototype%.throw ( value )
+ ...
+ 2. Let promiseCapability be ! NewPromiseCapability(%Promise%).
+ ...
+ 5. Let throw be GetMethod(syncIterator, "throw").
+ 6. IfAbruptRejectPromise(throw, promiseCapability).
+ ...
+ 8. Let throwResult be Call(throw, syncIterator, « value »).
+ 9. IfAbruptRejectPromise(throwResult, promiseCapability).
+ ...
+ 22. Return promiseCapability.[[Promise]].
+
+flags: [async]
+features: [async-iteration]
+---*/
+
+var thrownError = new Error("Catch me.");
+
+var obj = {
+ [Symbol.iterator]() {
+ return {
+ next() {
+ return { value: 1, done: false };
+ },
+ throw() {
+ throw thrownError;
+ }
+ };
+ }
+};
+
+async function* asyncg() {
+ yield* obj;
+}
+
+var iter = asyncg();
+
+iter.next().then(function(result) {
+
+ iter.throw().then(
+ function (result) {
+ throw new Test262Error("Promise should be rejected, got: " + result.value);
+ },
+ function (err) {
+ assert.sameValue(err, thrownError, "Promise should be rejected with thrown error");
+
+ iter.next().then(({ done, value }) => {
+ assert.sameValue(done, true, 'the iterator is completed');
+ assert.sameValue(value, undefined, 'value is undefined');
+ }).then($DONE, $DONE);
+ }
+ ).catch($DONE);
+}).catch($DONE);
diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/result-object-error.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/result-object-error.js
new file mode 100644
index 0000000000..f59d06cc8a
--- /dev/null
+++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/result-object-error.js
@@ -0,0 +1,65 @@
+// |reftest| async
+// Copyright (C) 2018 Valerie Young. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-%asyncfromsynciteratorprototype%.throw
+description: throw() will return rejected promise if getter of `throw` abrupt completes
+info: |
+ %AsyncFromSyncIteratorPrototype%.throw ( value )
+ ...
+ 2. Let promiseCapability be ! NewPromiseCapability(%Promise%).
+ ...
+ 5. Let throw be GetMethod(syncIterator, "throw").
+ 6. IfAbruptRejectPromise(thow, promiseCapability).
+ ...
+ 8. Let throwResult be Call(throw, syncIterator, « value »).
+ ...
+ 10. If Type(throwResult) is not Object,
+ a. Perform ! Call(promiseCapability.[[Reject]], undefined, « a TypeError exception »).
+ b. Return promiseCapability.[[Promise]].
+
+flags: [async]
+features: [async-iteration]
+---*/
+
+var thrownError = new Error("Don't catch me.")
+
+var obj = {
+ [Symbol.iterator]() {
+ return {
+ next() {
+ return { value: 1, done: false };
+ },
+ throw() {
+ return 1;
+ }
+ };
+ }
+};
+
+async function* asyncg() {
+ yield* obj;
+}
+
+var iter = asyncg();
+
+iter.next().then(function(result) {
+
+ iter.throw(thrownError).then(
+ function (result) {
+ throw new Test262Error("Promise should be rejected, got: " + result.value);
+ },
+ function (err) {
+ let typeerror = err instanceof TypeError;
+ assert(typeerror, "Expect TypeError, got: " + err);
+
+ iter.next().then(({ done, value }) => {
+ assert.sameValue(done, true, 'the iterator is completed');
+ assert.sameValue(value, undefined, 'value is undefined');
+ }).then($DONE, $DONE);
+ }
+ ).catch($DONE);
+
+}).catch($DONE);
+
diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/shell.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/shell.js
new file mode 100644
index 0000000000..ae18ad584d
--- /dev/null
+++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/shell.js
@@ -0,0 +1,113 @@
+// GENERATED, DO NOT EDIT
+// file: asyncHelpers.js
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: |
+ A collection of assertion and wrapper functions for testing asynchronous built-ins.
+defines: [asyncTest]
+---*/
+
+function asyncTest(testFunc) {
+ if (!Object.hasOwn(globalThis, "$DONE")) {
+ throw new Test262Error("asyncTest called without async flag");
+ }
+ if (typeof testFunc !== "function") {
+ $DONE(new Test262Error("asyncTest called with non-function argument"));
+ return;
+ }
+ try {
+ testFunc().then(
+ function () {
+ $DONE();
+ },
+ function (error) {
+ $DONE(error);
+ }
+ );
+ } catch (syncError) {
+ $DONE(syncError);
+ }
+}
+
+assert.throwsAsync = async function (expectedErrorConstructor, func, message) {
+ var innerThenable;
+ if (message === undefined) {
+ message = "";
+ } else {
+ message += " ";
+ }
+ if (typeof func === "function") {
+ try {
+ innerThenable = func();
+ if (
+ innerThenable === null ||
+ typeof innerThenable !== "object" ||
+ typeof innerThenable.then !== "function"
+ ) {
+ message +=
+ "Expected to obtain an inner promise that would reject with a" +
+ expectedErrorConstructor.name +
+ " but result was not a thenable";
+ throw new Test262Error(message);
+ }
+ } catch (thrown) {
+ message +=
+ "Expected a " +
+ expectedErrorConstructor.name +
+ " to be thrown asynchronously but an exception was thrown synchronously while obtaining the inner promise";
+ throw new Test262Error(message);
+ }
+ } else {
+ message +=
+ "assert.throwsAsync called with an argument that is not a function";
+ throw new Test262Error(message);
+ }
+
+ try {
+ return innerThenable.then(
+ function () {
+ message +=
+ "Expected a " +
+ expectedErrorConstructor.name +
+ " to be thrown asynchronously but no exception was thrown at all";
+ throw new Test262Error(message);
+ },
+ function (thrown) {
+ var expectedName, actualName;
+ if (typeof thrown !== "object" || thrown === null) {
+ message += "Thrown value was not an object!";
+ throw new Test262Error(message);
+ } else if (thrown.constructor !== expectedErrorConstructor) {
+ expectedName = expectedErrorConstructor.name;
+ actualName = thrown.constructor.name;
+ if (expectedName === actualName) {
+ message +=
+ "Expected a " +
+ expectedName +
+ " but got a different error constructor with the same name";
+ } else {
+ message +=
+ "Expected a " + expectedName + " but got a " + actualName;
+ }
+ throw new Test262Error(message);
+ }
+ }
+ );
+ } catch (thrown) {
+ if (typeof thrown !== "object" || thrown === null) {
+ message +=
+ "Expected a " +
+ expectedErrorConstructor.name +
+ " to be thrown asynchronously but innerThenable synchronously threw a value that was not an object ";
+ } else {
+ message +=
+ "Expected a " +
+ expectedErrorConstructor.name +
+ " to be thrown asynchronously but a " +
+ thrown.constructor.name +
+ " was thrown synchronously";
+ }
+ throw new Test262Error(message);
+ }
+};
diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/throw-null.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/throw-null.js
new file mode 100644
index 0000000000..afe9c0d2a3
--- /dev/null
+++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/throw-null.js
@@ -0,0 +1,60 @@
+// |reftest| async
+// Copyright (C) 2020 Alexey Shvayka. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-%asyncfromsynciteratorprototype%.throw
+description: >
+ If syncIterator's "throw" method is `null`,
+ a Promise rejected with provided value is returned.
+info: |
+ %AsyncFromSyncIteratorPrototype%.throw ( value )
+
+ [...]
+ 6. Let throw be GetMethod(syncIterator, "throw").
+ [...]
+ 8. If throw is undefined, then
+ ...
+ g. Perform ! Call(promiseCapability.[[Reject]], undefined, « a newly created TypeError object »).
+ h. Return promiseCapability.[[Promise]].
+
+ GetMethod ( V, P )
+
+ [...]
+ 2. Let func be ? GetV(V, P).
+ 3. If func is either undefined or null, return undefined.
+flags: [async]
+features: [async-iteration]
+includes: [asyncHelpers.js]
+---*/
+
+var throwGets = 0;
+var syncIterator = {
+ [Symbol.iterator]() {
+ return this;
+ },
+ next() {
+ return {value: 1, done: false};
+ },
+ get throw() {
+ throwGets += 1;
+ return null;
+ },
+};
+
+async function* asyncGenerator() {
+ yield* syncIterator;
+}
+
+var asyncIterator = asyncGenerator();
+var thrownError = { name: "err" };
+
+asyncTest(async function () {
+ await assert.throwsAsync(TypeError, async () => {
+ await asyncIterator.next();
+ return asyncIterator.throw(thrownError);
+ }, "Promise should be rejected");
+ const result = await asyncIterator.next();
+ assert(result.done, "the iterator is completed");
+ assert.sameValue(result.value, undefined, "value is undefined");
+})
diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/throw-result-poisoned-wrapper.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/throw-result-poisoned-wrapper.js
new file mode 100644
index 0000000000..4edbcfe390
--- /dev/null
+++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/throw-result-poisoned-wrapper.js
@@ -0,0 +1,91 @@
+// |reftest| async
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-%asyncfromsynciteratorprototype%.throw
+description: throw() will reject promise if resolving result promise abrupt completes.
+info: |
+ %AsyncFromSyncIteratorPrototype%.throw ( value )
+ ...
+ 3. Let promiseCapability be ! NewPromiseCapability(%Promise%).
+ 4. Let syncIteratorRecord be O.[[SyncIteratorRecord]].
+ 5. Let syncIterator be syncIteratorRecord.[[Iterator]].
+ 6. Let throw be GetMethod(syncIterator, "throw").
+ 7. IfAbruptRejectPromise(throw, promiseCapability).
+ 8. If throw is undefined, then
+ ...
+ 9. If value is present, then
+ ...
+ 10. Else,
+ a. Let result be Call(throw, syncIterator).
+ ...
+ 13. Return ! AsyncFromSyncIteratorContinuation(result, promiseCapability, syncIteratorRecord, true).
+
+ AsyncFromSyncIteratorContinuation ( result, promiseCapability, syncIteratorRecord, closeOnRejection )
+ 1. Let done be IteratorComplete(result).
+ 2. IfAbruptRejectPromise(done, promiseCapability).
+ 3. Let value be IteratorValue(result).
+ 4. IfAbruptRejectPromise(value, promiseCapability).
+ 5. Let valueWrapper be PromiseResolve(%Promise%, value).
+ 6. If valueWrapper is an abrupt completion, done is false, and closeOnRejection is true, then
+ a. Set valueWrapper to IteratorClose(syncIteratorRecord, valueWrapper).
+ 7. IfAbruptRejectPromise(valueWrapper, promiseCapability).
+ ...
+
+ IfAbruptRejectPromise ( value, capability )
+ 1. Assert: value is a Completion Record.
+ 2. If value is an abrupt completion, then
+ a. Perform ? Call(capability.[[Reject]], undefined, « value.[[Value]] »).
+ b. Return capability.[[Promise]].
+ ...
+
+flags: [async]
+features: [async-iteration]
+includes: [asyncHelpers.js]
+---*/
+
+var returnCount = 0;
+function CatchError() {}
+var thrownError = new CatchError();
+var uncaughtError = new Error("Don't catch me");
+
+const obj = {
+ [Symbol.iterator]() {
+ return {
+ next() {
+ return { value: 1, done: false };
+ },
+ throw() {
+ const p = Promise.resolve('FAIL');
+ Object.defineProperty(p, 'constructor', {
+ get() {
+ throw thrownError;
+ }
+ });
+ return { value: p, done: false };
+ },
+ return() {
+ returnCount += 1;
+ return { value: undefined, done: true };
+ }
+ };
+ }
+};
+
+async function* asyncg() {
+ return yield* obj;
+}
+
+let iter = asyncg();
+
+asyncTest(async function () {
+ await assert.throwsAsync(CatchError, async () => {
+ await iter.next();
+ return iter.throw(uncaughtError);
+ }, "Promise should be rejected");
+ assert.sameValue(returnCount, 1, 'iterator closed properly');
+ const result = await iter.next();
+ assert(result.done, "the iterator is completed");
+ assert.sameValue(result.value, undefined, "value is undefined");
+})
diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/throw-undefined-get-return-undefined.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/throw-undefined-get-return-undefined.js
new file mode 100644
index 0000000000..c3ef881b7b
--- /dev/null
+++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/throw-undefined-get-return-undefined.js
@@ -0,0 +1,74 @@
+// |reftest| async
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-%asyncfromsynciteratorprototype%.throw
+description: >
+ If syncIterator's "throw" method is `undefined`,
+ and its "return" method returns `undefined`,
+ the iterator will close returning the `undefined` value,
+ which will be ignored and instead a rejected Promise with a new TypeError is returned.
+info: |
+ %AsyncFromSyncIteratorPrototype%.throw ( value )
+ ...
+ 2. Let promiseCapability be ! NewPromiseCapability(%Promise%).
+ ...
+ 5. Let return be GetMethod(syncIterator, "throw").
+ 6. IfAbruptRejectPromise(throw, promiseCapability).
+ 7. If throw is undefined, then
+ a. NOTE: If syncIterator does not have a throw method, close it to give it a chance to clean up before we reject the capability.
+ b. Let closeCompletion be Completion { [[Type]]: normal, [[Value]]: empty, [[Target]]: empty }.
+ c. Set result to IteratorClose(syncIteratorRecord, closeCompletion).
+ ...
+ g. Perform ! Call(promiseCapability.[[Reject]], undefined, « a newly created TypeError object »).
+ h. Return promiseCapability.[[Promise]].
+ ...
+
+ IteratorClose ( iterator, completion )
+ ...
+ 2. Let iterator be iteratorRecord.[[Iterator]].
+ 3. Let innerResult be Completion(GetMethod(iterator, "return")).
+ 4. If innerResult.[[Type]] is normal, then
+ a. Let return be innerResult.[[Value]].
+ b. If return is undefined, return ? completion.
+ ...
+
+flags: [async]
+features: [async-iteration]
+includes: [asyncHelpers.js]
+---*/
+
+var returnCount = 0;
+
+const obj = {
+ [Symbol.iterator]() {
+ return {
+ next() {
+ return {value: 1, done: false};
+ },
+ get return() {
+ returnCount += 1;
+ return undefined;
+ }
+ };
+ }
+};
+
+async function* wrapper() {
+ yield* obj;
+}
+
+var iter = wrapper();
+
+asyncTest(async function () {
+ await assert.throwsAsync(TypeError, async () => {
+ await iter.next();
+ return iter.throw();
+ }, "Promise should be rejected");
+ assert.sameValue(returnCount, 1, 'iterator closed properly');
+ const result = await iter.next();
+ assert(result.done, "the iterator is completed");
+ assert.sameValue(result.value, undefined, "value is undefined");
+})
+
diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/throw-undefined-poisoned-return.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/throw-undefined-poisoned-return.js
new file mode 100644
index 0000000000..5b0b5ae56a
--- /dev/null
+++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/throw-undefined-poisoned-return.js
@@ -0,0 +1,78 @@
+// |reftest| async
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-%asyncfromsynciteratorprototype%.throw
+description: throw() will close the iterator and return rejected promise if sync `throw` undefined
+info: |
+ %AsyncFromSyncIteratorPrototype%.throw ( value )
+ ...
+ 2. Let promiseCapability be ! NewPromiseCapability(%Promise%).
+ ...
+ 5. Let return be GetMethod(syncIterator, "throw").
+ 6. IfAbruptRejectPromise(throw, promiseCapability).
+ 7. If throw is undefined, then
+ a. NOTE: If syncIterator does not have a throw method, close it to give it a chance to clean up before we reject the capability.
+ b. Let closeCompletion be Completion { [[Type]]: normal, [[Value]]: empty, [[Target]]: empty }.
+ c. Set result to IteratorClose(syncIteratorRecord, closeCompletion).
+ d. IfAbruptRejectPromise(result, promiseCapability).
+ e. NOTE: The next step throws a TypeError to indicate that there was a protocol violation: syncIterator does not have a throw method.
+ f. NOTE: If closing syncIterator does not throw then the result of that operation is ignored, even if it yields a rejected promise.
+ g. Perform ! Call(promiseCapability.[[Reject]], undefined, « a newly created TypeError object »).
+ h. Return promiseCapability.[[Promise]].
+
+ IteratorClose ( iterator, completion )
+ ...
+ 2. Let iterator be iteratorRecord.[[Iterator]].
+ 3. Let innerResult be Completion(GetMethod(iterator, "return")).
+ ...
+ 6. If innerResult.[[Type]] is throw, return ? innerResult.
+ ...
+
+ IfAbruptRejectPromise ( value, capability )
+ 1. Assert: value is a Completion Record.
+ 2. If value is an abrupt completion, then
+ a. Perform ? Call(capability.[[Reject]], undefined, « value.[[Value]] »).
+ b. Return capability.[[Promise]].
+ ...
+
+flags: [async]
+features: [async-iteration]
+includes: [asyncHelpers.js]
+---*/
+
+var returnCount = 0;
+function CatchError() {}
+var thrownError = new CatchError();
+
+const obj = {
+ [Symbol.iterator]() {
+ return {
+ next() {
+ return {value: 1, done: false};
+ },
+ get return() {
+ returnCount += 1;
+ throw thrownError;
+ }
+ };
+ }
+};
+
+async function* wrapper() {
+ yield* obj;
+}
+
+var iter = wrapper();
+
+asyncTest(async function () {
+ await assert.throwsAsync(CatchError, async () => {
+ await iter.next();
+ return iter.throw();
+ }, "Promise should be rejected");
+ assert.sameValue(returnCount, 1, 'iterator closed properly');
+ const result = await iter.next();
+ assert(result.done, "the iterator is completed");
+ assert.sameValue(result.value, undefined, "value is undefined");
+})
diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/throw-undefined-return-not-object.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/throw-undefined-return-not-object.js
new file mode 100644
index 0000000000..28de5558e0
--- /dev/null
+++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/throw-undefined-return-not-object.js
@@ -0,0 +1,81 @@
+// |reftest| async
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-%asyncfromsynciteratorprototype%.throw
+description: >
+ If syncIterator's "throw" method is `undefined`,
+ and its "return" method returns `undefined`,
+ the iterator will close returning the `undefined` value,
+ which will be ignored and instead a rejected Promise with a new TypeError is returned.
+info: |
+ %AsyncFromSyncIteratorPrototype%.throw ( value )
+ ...
+ 2. Let promiseCapability be ! NewPromiseCapability(%Promise%).
+ ...
+ 5. Let return be GetMethod(syncIterator, "throw").
+ 6. IfAbruptRejectPromise(throw, promiseCapability).
+ 7. If throw is undefined, then
+ a. NOTE: If syncIterator does not have a throw method, close it to give it a chance to clean up before we reject the capability.
+ b. Let closeCompletion be Completion { [[Type]]: normal, [[Value]]: empty, [[Target]]: empty }.
+ c. Set result to IteratorClose(syncIteratorRecord, closeCompletion).
+ d. IfAbruptRejectPromise(result, promiseCapability).
+ ...
+
+ IteratorClose ( iterator, completion )
+ ...
+ 2. Let iterator be iteratorRecord.[[Iterator]].
+ 3. Let innerResult be Completion(GetMethod(iterator, "return")).
+ 4. If innerResult.[[Type]] is normal, then
+ a. Let return be innerResult.[[Value]].
+ ...
+ c. Set innerResult to Completion(Call(return, iterator)).
+ ...
+ 7. If innerResult.[[Value]] is not an Object, throw a TypeError exception.
+ ...
+
+ IfAbruptRejectPromise ( value, capability )
+ 1. Assert: value is a Completion Record.
+ 2. If value is an abrupt completion, then
+ a. Perform ? Call(capability.[[Reject]], undefined, « value.[[Value]] »).
+ b. Return capability.[[Promise]].
+ ...
+
+flags: [async]
+features: [async-iteration]
+includes: [asyncHelpers.js]
+---*/
+
+var returnCount = 0;
+
+const obj = {
+ [Symbol.iterator]() {
+ return {
+ next() {
+ return {value: 1, done: false};
+ },
+ return() {
+ returnCount += 1;
+ return 2;
+ }
+ };
+ }
+};
+
+async function* wrapper() {
+ yield* obj;
+}
+
+var iter = wrapper();
+
+asyncTest(async function () {
+ await assert.throwsAsync(TypeError, async () => {
+ await iter.next();
+ return iter.throw();
+ }, "Promise should be rejected");
+ assert.sameValue(returnCount, 1, 'iterator closed properly');
+ const result = await iter.next();
+ assert(result.done, "the iterator is completed");
+ assert.sameValue(result.value, undefined, "value is undefined");
+})
diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/throw-undefined-return-object.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/throw-undefined-return-object.js
new file mode 100644
index 0000000000..30e660a0e8
--- /dev/null
+++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/throw-undefined-return-object.js
@@ -0,0 +1,75 @@
+// |reftest| async
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-%asyncfromsynciteratorprototype%.throw
+description: >
+ If syncIterator's "throw" method is `undefined`,
+ and its "return" method returns `undefined`,
+ the iterator will close returning the `undefined` value,
+ which will be ignored and instead a rejected Promise with a new TypeError is returned.
+info: |
+ %AsyncFromSyncIteratorPrototype%.throw ( value )
+ ...
+ 2. Let promiseCapability be ! NewPromiseCapability(%Promise%).
+ ...
+ 5. Let return be GetMethod(syncIterator, "throw").
+ ...
+ 7. If throw is undefined, then
+ a. NOTE: If syncIterator does not have a throw method, close it to give it a chance to clean up before we reject the capability.
+ b. Let closeCompletion be Completion { [[Type]]: normal, [[Value]]: empty, [[Target]]: empty }.
+ c. Set result to IteratorClose(syncIteratorRecord, closeCompletion).
+ ...
+ g. Perform ! Call(promiseCapability.[[Reject]], undefined, « a newly created TypeError object »).
+ h. Return promiseCapability.[[Promise]].
+ ...
+
+ IteratorClose ( iterator, completion )
+ ...
+ 2. Let iterator be iteratorRecord.[[Iterator]].
+ 3. Let innerResult be Completion(GetMethod(iterator, "return")).
+ 4. If innerResult.[[Type]] is normal, then
+ a. Let return be innerResult.[[Value]].
+ ...
+ c. Set innerResult to Completion(Call(return, iterator)).
+ ...
+ 8. Return ? completion.
+
+flags: [async]
+features: [async-iteration]
+includes: [asyncHelpers.js]
+---*/
+
+var returnCount = 0;
+
+const obj = {
+ [Symbol.iterator]() {
+ return {
+ next() {
+ return {value: 1, done: false};
+ },
+ return() {
+ returnCount += 1;
+ return {value: 2, done: true};
+ }
+ };
+ }
+};
+
+async function* wrapper() {
+ yield* obj;
+}
+
+var iter = wrapper();
+
+asyncTest(async function () {
+ await assert.throwsAsync(TypeError, async () => {
+ await iter.next();
+ return iter.throw();
+ }, "Promise should be rejected");
+ assert.sameValue(returnCount, 1, 'iterator closed properly');
+ const result = await iter.next();
+ assert(result.done, "the iterator is completed");
+ assert.sameValue(result.value, undefined, "value is undefined");
+})
diff --git a/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/throw-undefined.js b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/throw-undefined.js
new file mode 100644
index 0000000000..4c478c270b
--- /dev/null
+++ b/js/src/tests/test262/built-ins/AsyncFromSyncIteratorPrototype/throw/throw-undefined.js
@@ -0,0 +1,49 @@
+// |reftest| async
+// Copyright (C) 2018 Valerie Young. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-%asyncfromsynciteratorprototype%.throw
+description: throw() will return rejected promise if sync `throw` undefined
+info: |
+ %AsyncFromSyncIteratorPrototype%.throw ( value )
+ ...
+ 2. Let promiseCapability be ! NewPromiseCapability(%Promise%).
+ ...
+ 6. Let throw be GetMethod(syncIterator, "throw").
+ [...]
+ 8. If throw is undefined, then
+ ...
+ g. Perform ! Call(promiseCapability.[[Reject]], undefined, « a newly created TypeError object »).
+ h. Return promiseCapability.[[Promise]].
+
+flags: [async]
+features: [async-iteration]
+includes: [asyncHelpers.js]
+---*/
+
+var obj = {
+ [Symbol.iterator]() {
+ return {
+ next() {
+ return { value: 1, done: false };
+ }
+ };
+ }
+};
+
+async function* asyncg() {
+ yield* obj;
+}
+
+var iter = asyncg();
+
+asyncTest(async function () {
+ await assert.throwsAsync(TypeError, async () => {
+ await iter.next();
+ return iter.throw();
+ }, "Promise should be rejected");
+ const result = await iter.next();
+ assert(result.done, "the iterator is completed");
+ assert.sameValue(result.value, undefined, "value is undefined");
+})