diff --git a/packages/babel-plugin-proposal-async-generator-functions/src/for-await.js b/packages/babel-plugin-proposal-async-generator-functions/src/for-await.js index eff702a255b3..16f08dca1524 100644 --- a/packages/babel-plugin-proposal-async-generator-functions/src/for-await.js +++ b/packages/babel-plugin-proposal-async-generator-functions/src/for-await.js @@ -2,26 +2,22 @@ import { types as t, template } from "@babel/core"; const buildForAwait = template(` async function wrapper() { - var ITERATOR_COMPLETION = true; + var ITERATOR_ABRUPT_COMPLETION = false; var ITERATOR_HAD_ERROR_KEY = false; var ITERATOR_ERROR_KEY; try { for ( - var ITERATOR_KEY = GET_ITERATOR(OBJECT), STEP_KEY, STEP_VALUE; - ( - STEP_KEY = await ITERATOR_KEY.next(), - ITERATOR_COMPLETION = STEP_KEY.done, - STEP_VALUE = await STEP_KEY.value, - !ITERATOR_COMPLETION - ); - ITERATOR_COMPLETION = true) { + var ITERATOR_KEY = GET_ITERATOR(OBJECT), STEP_KEY; + ITERATOR_ABRUPT_COMPLETION = !(STEP_KEY = await ITERATOR_KEY.next()).done; + ITERATOR_ABRUPT_COMPLETION = false + ) { } } catch (err) { ITERATOR_HAD_ERROR_KEY = true; ITERATOR_ERROR_KEY = err; } finally { try { - if (!ITERATOR_COMPLETION && ITERATOR_KEY.return != null) { + if (ITERATOR_ABRUPT_COMPLETION && ITERATOR_KEY.return != null) { await ITERATOR_KEY.return(); } } finally { @@ -37,7 +33,7 @@ export default function (path, { getAsyncIterator }) { const { node, scope, parent } = path; const stepKey = scope.generateUidIdentifier("step"); - const stepValue = scope.generateUidIdentifier("value"); + const stepValue = t.memberExpression(stepKey, t.identifier("value")); const left = node.left; let declar; @@ -54,15 +50,14 @@ export default function (path, { getAsyncIterator }) { } let template = buildForAwait({ ITERATOR_HAD_ERROR_KEY: scope.generateUidIdentifier("didIteratorError"), - ITERATOR_COMPLETION: scope.generateUidIdentifier( - "iteratorNormalCompletion", + ITERATOR_ABRUPT_COMPLETION: scope.generateUidIdentifier( + "iteratorAbruptCompletion", ), ITERATOR_ERROR_KEY: scope.generateUidIdentifier("iteratorError"), ITERATOR_KEY: scope.generateUidIdentifier("iterator"), GET_ITERATOR: getAsyncIterator, OBJECT: node.right, - STEP_VALUE: t.cloneNode(stepValue), - STEP_KEY: stepKey, + STEP_KEY: t.cloneNode(stepKey), }); // remove async function wrapper diff --git a/packages/babel-plugin-proposal-async-generator-functions/test/fixtures/for-await/async-arrow/output.js b/packages/babel-plugin-proposal-async-generator-functions/test/fixtures/for-await/async-arrow/output.js index 1003e22ca6c3..802dd6d77316 100644 --- a/packages/babel-plugin-proposal-async-generator-functions/test/fixtures/for-await/async-arrow/output.js +++ b/packages/babel-plugin-proposal-async-generator-functions/test/fixtures/for-await/async-arrow/output.js @@ -1,13 +1,13 @@ /*#__PURE__*/ babelHelpers.asyncToGenerator(function* () { - var _iteratorNormalCompletion = true; + var _iteratorAbruptCompletion = false; var _didIteratorError = false; var _iteratorError; try { - for (var _iterator = babelHelpers.asyncIterator(y), _step, _value; _step = yield _iterator.next(), _iteratorNormalCompletion = _step.done, _value = yield _step.value, !_iteratorNormalCompletion; _iteratorNormalCompletion = true) { - let x = _value; + for (var _iterator = babelHelpers.asyncIterator(y), _step; _iteratorAbruptCompletion = !(_step = yield _iterator.next()).done; _iteratorAbruptCompletion = false) { + let x = _step.value; f(x); } } catch (err) { @@ -15,7 +15,7 @@ babelHelpers.asyncToGenerator(function* () { _iteratorError = err; } finally { try { - if (!_iteratorNormalCompletion && _iterator.return != null) { + if (_iteratorAbruptCompletion && _iterator.return != null) { yield _iterator.return(); } } finally { diff --git a/packages/babel-plugin-proposal-async-generator-functions/test/fixtures/for-await/async-function-no-transform/output.js b/packages/babel-plugin-proposal-async-generator-functions/test/fixtures/for-await/async-function-no-transform/output.js index d7801fa31936..1e1df44ed94a 100644 --- a/packages/babel-plugin-proposal-async-generator-functions/test/fixtures/for-await/async-function-no-transform/output.js +++ b/packages/babel-plugin-proposal-async-generator-functions/test/fixtures/for-await/async-function-no-transform/output.js @@ -1,19 +1,19 @@ async function foo() { - var _iteratorNormalCompletion = true; + var _iteratorAbruptCompletion = false; var _didIteratorError = false; var _iteratorError; try { - for (var _iterator = babelHelpers.asyncIterator(y), _step, _value; _step = await _iterator.next(), _iteratorNormalCompletion = _step.done, _value = await _step.value, !_iteratorNormalCompletion; _iteratorNormalCompletion = true) { - const x = _value; + for (var _iterator = babelHelpers.asyncIterator(y), _step; _iteratorAbruptCompletion = !(_step = await _iterator.next()).done; _iteratorAbruptCompletion = false) { + const x = _step.value; } } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { - if (!_iteratorNormalCompletion && _iterator.return != null) { + if (_iteratorAbruptCompletion && _iterator.return != null) { await _iterator.return(); } } finally { diff --git a/packages/babel-plugin-proposal-async-generator-functions/test/fixtures/for-await/async-function/output.js b/packages/babel-plugin-proposal-async-generator-functions/test/fixtures/for-await/async-function/output.js index 95eb83b6b2d8..fdeebc16c34f 100644 --- a/packages/babel-plugin-proposal-async-generator-functions/test/fixtures/for-await/async-function/output.js +++ b/packages/babel-plugin-proposal-async-generator-functions/test/fixtures/for-await/async-function/output.js @@ -4,14 +4,14 @@ function f() { function _f() { _f = babelHelpers.asyncToGenerator(function* () { - var _iteratorNormalCompletion = true; + var _iteratorAbruptCompletion = false; var _didIteratorError = false; var _iteratorError; try { - for (var _iterator = babelHelpers.asyncIterator(y), _step, _value; _step = yield _iterator.next(), _iteratorNormalCompletion = _step.done, _value = yield _step.value, !_iteratorNormalCompletion; _iteratorNormalCompletion = true) { - let x = _value; + for (var _iterator = babelHelpers.asyncIterator(y), _step; _iteratorAbruptCompletion = !(_step = yield _iterator.next()).done; _iteratorAbruptCompletion = false) { + let x = _step.value; g(x); } } catch (err) { @@ -19,7 +19,7 @@ function _f() { _iteratorError = err; } finally { try { - if (!_iteratorNormalCompletion && _iterator.return != null) { + if (_iteratorAbruptCompletion && _iterator.return != null) { yield _iterator.return(); } } finally { diff --git a/packages/babel-plugin-proposal-async-generator-functions/test/fixtures/for-await/async-generator/output.js b/packages/babel-plugin-proposal-async-generator-functions/test/fixtures/for-await/async-generator/output.js index 1531571a1a47..1dc0aba51463 100644 --- a/packages/babel-plugin-proposal-async-generator-functions/test/fixtures/for-await/async-generator/output.js +++ b/packages/babel-plugin-proposal-async-generator-functions/test/fixtures/for-await/async-generator/output.js @@ -4,14 +4,14 @@ function g() { function _g() { _g = babelHelpers.wrapAsyncGenerator(function* () { - var _iteratorNormalCompletion = true; + var _iteratorAbruptCompletion = false; var _didIteratorError = false; var _iteratorError; try { - for (var _iterator = babelHelpers.asyncIterator(y), _step, _value; _step = yield babelHelpers.awaitAsyncGenerator(_iterator.next()), _iteratorNormalCompletion = _step.done, _value = yield babelHelpers.awaitAsyncGenerator(_step.value), !_iteratorNormalCompletion; _iteratorNormalCompletion = true) { - let x = _value; + for (var _iterator = babelHelpers.asyncIterator(y), _step; _iteratorAbruptCompletion = !(_step = yield babelHelpers.awaitAsyncGenerator(_iterator.next())).done; _iteratorAbruptCompletion = false) { + let x = _step.value; f(x); } } catch (err) { @@ -19,7 +19,7 @@ function _g() { _iteratorError = err; } finally { try { - if (!_iteratorNormalCompletion && _iterator.return != null) { + if (_iteratorAbruptCompletion && _iterator.return != null) { yield babelHelpers.awaitAsyncGenerator(_iterator.return()); } } finally { diff --git a/packages/babel-plugin-proposal-async-generator-functions/test/fixtures/for-await/destructuring/output.js b/packages/babel-plugin-proposal-async-generator-functions/test/fixtures/for-await/destructuring/output.js index 74aeb607a425..4e599cf8bbb7 100644 --- a/packages/babel-plugin-proposal-async-generator-functions/test/fixtures/for-await/destructuring/output.js +++ b/packages/babel-plugin-proposal-async-generator-functions/test/fixtures/for-await/destructuring/output.js @@ -4,17 +4,17 @@ function f() { function _f() { _f = babelHelpers.asyncToGenerator(function* () { - var _iteratorNormalCompletion = true; + var _iteratorAbruptCompletion = false; var _didIteratorError = false; var _iteratorError; try { - for (var _iterator = babelHelpers.asyncIterator(a), _step, _value; _step = yield _iterator.next(), _iteratorNormalCompletion = _step.done, _value = yield _step.value, !_iteratorNormalCompletion; _iteratorNormalCompletion = true) { + for (var _iterator = babelHelpers.asyncIterator(a), _step; _iteratorAbruptCompletion = !(_step = yield _iterator.next()).done; _iteratorAbruptCompletion = false) { let { x, y: [z] - } = _value; + } = _step.value; g(x, z); } } catch (err) { @@ -22,7 +22,7 @@ function _f() { _iteratorError = err; } finally { try { - if (!_iteratorNormalCompletion && _iterator.return != null) { + if (_iteratorAbruptCompletion && _iterator.return != null) { yield _iterator.return(); } } finally { diff --git a/packages/babel-plugin-proposal-async-generator-functions/test/fixtures/for-await/lhs-member-expression/exec.js b/packages/babel-plugin-proposal-async-generator-functions/test/fixtures/for-await/lhs-member-expression/exec.js new file mode 100644 index 000000000000..a53e9957acaf --- /dev/null +++ b/packages/babel-plugin-proposal-async-generator-functions/test/fixtures/for-await/lhs-member-expression/exec.js @@ -0,0 +1,6 @@ +return async function () { + let obj = {}; + for await (obj.x of [1, 2]); + + expect(obj.x).toBe(2); +}(); diff --git a/packages/babel-plugin-proposal-async-generator-functions/test/fixtures/for-await/lhs-member-expression/input.js b/packages/babel-plugin-proposal-async-generator-functions/test/fixtures/for-await/lhs-member-expression/input.js new file mode 100644 index 000000000000..5e1926be130a --- /dev/null +++ b/packages/babel-plugin-proposal-async-generator-functions/test/fixtures/for-await/lhs-member-expression/input.js @@ -0,0 +1,3 @@ +(async function () { + for await (obj.x of y) {} +})(); diff --git a/packages/babel-plugin-proposal-async-generator-functions/test/fixtures/for-await/lhs-member-expression/options.json b/packages/babel-plugin-proposal-async-generator-functions/test/fixtures/for-await/lhs-member-expression/options.json new file mode 100644 index 000000000000..eeebc1a57738 --- /dev/null +++ b/packages/babel-plugin-proposal-async-generator-functions/test/fixtures/for-await/lhs-member-expression/options.json @@ -0,0 +1,5 @@ +{ + "parserOpts": { + "allowReturnOutsideFunction": true + } +} diff --git a/packages/babel-plugin-proposal-async-generator-functions/test/fixtures/for-await/lhs-member-expression/output.js b/packages/babel-plugin-proposal-async-generator-functions/test/fixtures/for-await/lhs-member-expression/output.js new file mode 100644 index 000000000000..e3db99173493 --- /dev/null +++ b/packages/babel-plugin-proposal-async-generator-functions/test/fixtures/for-await/lhs-member-expression/output.js @@ -0,0 +1,25 @@ +babelHelpers.asyncToGenerator(function* () { + var _iteratorAbruptCompletion = false; + var _didIteratorError = false; + + var _iteratorError; + + try { + for (var _iterator = babelHelpers.asyncIterator(y), _step; _iteratorAbruptCompletion = !(_step = yield _iterator.next()).done; _iteratorAbruptCompletion = false) { + obj.x = _step.value; + } + } catch (err) { + _didIteratorError = true; + _iteratorError = err; + } finally { + try { + if (_iteratorAbruptCompletion && _iterator.return != null) { + yield _iterator.return(); + } + } finally { + if (_didIteratorError) { + throw _iteratorError; + } + } + } +})(); diff --git a/packages/babel-plugin-proposal-async-generator-functions/test/fixtures/for-await/step-single-tick/exec.js b/packages/babel-plugin-proposal-async-generator-functions/test/fixtures/for-await/step-single-tick/exec.js new file mode 100644 index 000000000000..16236197b357 --- /dev/null +++ b/packages/babel-plugin-proposal-async-generator-functions/test/fixtures/for-await/step-single-tick/exec.js @@ -0,0 +1,31 @@ +let resolve; +let promise = new Promise((r) => (resolve = r)); +let iterable = { + [Symbol.asyncIterator || "@@asyncIterator"]() { + return { + next: () => promise, + }; + }, +}; + +let values = []; + +return Promise.all([ + async function () { + for await (let value of iterable) { + values.push(value); + } + }(), + async function () { + resolve({ value: 0, done: false }); + promise = new Promise((r) => (resolve = r)); + + await null; + resolve({ value: 1, done: false }); + promise = new Promise((r) => (resolve = r)); + + resolve({ value: undefined, done: true }); + }(), +]).then(() => { + expect(values).toEqual([0, 1]); +}); diff --git a/packages/babel-plugin-proposal-async-generator-functions/test/fixtures/for-await/step-single-tick/options.json b/packages/babel-plugin-proposal-async-generator-functions/test/fixtures/for-await/step-single-tick/options.json new file mode 100644 index 000000000000..eeebc1a57738 --- /dev/null +++ b/packages/babel-plugin-proposal-async-generator-functions/test/fixtures/for-await/step-single-tick/options.json @@ -0,0 +1,5 @@ +{ + "parserOpts": { + "allowReturnOutsideFunction": true + } +} diff --git a/packages/babel-plugin-proposal-async-generator-functions/test/fixtures/for-await/step-value-is-promise/exec.js b/packages/babel-plugin-proposal-async-generator-functions/test/fixtures/for-await/step-value-is-promise/exec.js new file mode 100644 index 000000000000..f79aeda27771 --- /dev/null +++ b/packages/babel-plugin-proposal-async-generator-functions/test/fixtures/for-await/step-value-is-promise/exec.js @@ -0,0 +1,22 @@ +let steps = [ + { done: false, value: Promise.resolve(1) }, + { done: true, value: undefined } +]; + +let iterable = { + [Symbol.asyncIterator || "@@asyncIterator"]() { + return { + next: () => steps.shift(), + }; + }, +}; + +let values = []; + +return async function () { + let value; + for await (value of iterable); + + expect(value).toBeInstanceOf(Promise); + await expect(value).resolves.toBe(1); +}(); diff --git a/packages/babel-plugin-proposal-async-generator-functions/test/fixtures/for-await/step-value-is-promise/options.json b/packages/babel-plugin-proposal-async-generator-functions/test/fixtures/for-await/step-value-is-promise/options.json new file mode 100644 index 000000000000..eeebc1a57738 --- /dev/null +++ b/packages/babel-plugin-proposal-async-generator-functions/test/fixtures/for-await/step-value-is-promise/options.json @@ -0,0 +1,5 @@ +{ + "parserOpts": { + "allowReturnOutsideFunction": true + } +} diff --git a/packages/babel-plugin-proposal-async-generator-functions/test/fixtures/for-await/step-value-not-accessed-when-done/exec.js b/packages/babel-plugin-proposal-async-generator-functions/test/fixtures/for-await/step-value-not-accessed-when-done/exec.js new file mode 100644 index 000000000000..8c7c36d8e9a3 --- /dev/null +++ b/packages/babel-plugin-proposal-async-generator-functions/test/fixtures/for-await/step-value-not-accessed-when-done/exec.js @@ -0,0 +1,18 @@ +let gotValue = false; + +let iterable = { + [Symbol.asyncIterator || "@@asyncIterator"]() { + return { + next: () => Promise.resolve({ + get value() { gotValue = true }, + done: true + }) + }; + }, +}; + +return async function () { + for await (let value of iterable) {} + + expect(gotValue).toBe(false); +}(); diff --git a/packages/babel-plugin-proposal-async-generator-functions/test/fixtures/for-await/step-value-not-accessed-when-done/options.json b/packages/babel-plugin-proposal-async-generator-functions/test/fixtures/for-await/step-value-not-accessed-when-done/options.json new file mode 100644 index 000000000000..eeebc1a57738 --- /dev/null +++ b/packages/babel-plugin-proposal-async-generator-functions/test/fixtures/for-await/step-value-not-accessed-when-done/options.json @@ -0,0 +1,5 @@ +{ + "parserOpts": { + "allowReturnOutsideFunction": true + } +} diff --git a/packages/babel-plugin-proposal-async-generator-functions/test/fixtures/regression/5880/output.js b/packages/babel-plugin-proposal-async-generator-functions/test/fixtures/regression/5880/output.js index 4b9e652d6cbc..dca5c85a89a8 100644 --- a/packages/babel-plugin-proposal-async-generator-functions/test/fixtures/regression/5880/output.js +++ b/packages/babel-plugin-proposal-async-generator-functions/test/fixtures/regression/5880/output.js @@ -1,21 +1,20 @@ (async () => { - var _iteratorNormalCompletion = true; + var _iteratorAbruptCompletion = false; var _didIteratorError = false; var _iteratorError; try { - for (var _iterator = babelHelpers.asyncIterator(iterable), _step, _value; _step = await _iterator.next(), _iteratorNormalCompletion = _step.done, _value = await _step.value, !_iteratorNormalCompletion; _iteratorNormalCompletion = true) { - const _value2 = _value, - _value3 = babelHelpers.slicedToArray(_value2, 1), - value = _value3[0]; + for (var _iterator = babelHelpers.asyncIterator(iterable), _step; _iteratorAbruptCompletion = !(_step = await _iterator.next()).done; _iteratorAbruptCompletion = false) { + const _step$value = babelHelpers.slicedToArray(_step.value, 1), + value = _step$value[0]; } } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { - if (!_iteratorNormalCompletion && _iterator.return != null) { + if (_iteratorAbruptCompletion && _iterator.return != null) { await _iterator.return(); } } finally {