Skip to content

Commit 1c0a08d

Browse files
authored
[7.x backport] fix: Properly handle await in finally (#17805)
* fix * update test * update test
1 parent 061bf95 commit 1c0a08d

6 files changed

Lines changed: 68 additions & 48 deletions

File tree

packages/babel-helpers/src/helpers-generated.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1576,10 +1576,10 @@ const helpers: Record<string, Helper> = {
15761576
internal: false,
15771577
},
15781578
),
1579-
// size: 1166, gzip size: 524
1579+
// size: 1063, gzip size: 498
15801580
wrapAsyncGenerator: helper(
15811581
"7.0.0-beta.0",
1582-
'function _wrapAsyncGenerator(e){return function(){return new AsyncGenerator(e.apply(this,arguments))}}function AsyncGenerator(e){var r,t;function resume(r,t){try{var n=e[r](t),o=n.value,u=o instanceof OverloadYield;Promise.resolve(u?o.v:o).then(function(t){if(u){var i="return"===r?"return":"next";if(!o.k||t.done)return resume(i,t);t=e[i](t).value}settle(n.done?"return":"normal",t)},function(e){resume("throw",e)})}catch(e){settle("throw",e)}}function settle(e,n){switch(e){case"return":r.resolve({value:n,done:!0});break;case"throw":r.reject(n);break;default:r.resolve({value:n,done:!1})}(r=r.next)?resume(r.key,r.arg):t=null}this._invoke=function(e,n){return new Promise(function(o,u){var i={key:e,arg:n,resolve:o,reject:u,next:null};t?t=t.next=i:(r=t=i,resume(e,n))})},"function"!=typeof e.return&&(this.return=void 0)}AsyncGenerator.prototype["function"==typeof Symbol&&Symbol.asyncIterator||"@@asyncIterator"]=function(){return this},AsyncGenerator.prototype.next=function(e){return this._invoke("next",e)},AsyncGenerator.prototype.throw=function(e){return this._invoke("throw",e)},AsyncGenerator.prototype.return=function(e){return this._invoke("return",e)};',
1582+
'function _wrapAsyncGenerator(e){return function(){return new AsyncGenerator(e.apply(this,arguments))}}function AsyncGenerator(e){var t,n;function resume(t,n){try{var r=e[t](n),o=r.value,u=o instanceof OverloadYield;Promise.resolve(u?o.v:o).then(function(n){if(u){var i="return"===t&&o.k?t:"next";if(!o.k||n.done)return resume(i,n);n=e[i](n).value}settle(!!r.done,n)},function(e){resume("throw",e)})}catch(e){settle(2,e)}}function settle(e,r){2===e?t.reject(r):t.resolve({value:r,done:e}),(t=t.next)?resume(t.key,t.arg):n=null}this._invoke=function(e,r){return new Promise(function(o,u){var i={key:e,arg:r,resolve:o,reject:u,next:null};n?n=n.next=i:(t=n=i,resume(e,r))})},"function"!=typeof e.return&&(this.return=void 0)}AsyncGenerator.prototype["function"==typeof Symbol&&Symbol.asyncIterator||"@@asyncIterator"]=function(){return this},AsyncGenerator.prototype.next=function(e){return this._invoke("next",e)},AsyncGenerator.prototype.throw=function(e){return this._invoke("throw",e)},AsyncGenerator.prototype.return=function(e){return this._invoke("return",e)};',
15831583
{
15841584
globals: ["Promise", "Symbol"],
15851585
locals: {

packages/babel-helpers/src/helpers/wrapAsyncGenerator.ts

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,10 @@ function AsyncGenerator<T = unknown, TReturn = any, TNext = unknown>(
9090
// not visible to the (sync) yield*.
9191
// The other part of this implementation is in asyncGeneratorDelegate.
9292
var nextKey: "return" | "next" =
93-
key === "return" ? "return" : "next";
93+
key === "return" &&
94+
(value as OverloadYield<IteratorReturnResult<T>>).k
95+
? key
96+
: "next";
9497
if (
9598
!(value as OverloadYield<IteratorReturnResult<T>>).k ||
9699
arg.done
@@ -104,28 +107,27 @@ function AsyncGenerator<T = unknown, TReturn = any, TNext = unknown>(
104107
}
105108
}
106109

107-
settle(result.done ? "return" : "normal", arg);
110+
settle(!!result.done, arg);
108111
},
109112
function (err) {
110113
resume("throw", err);
111114
},
112115
);
113116
} catch (err) {
114-
settle("throw", err);
117+
settle(2, err);
115118
}
116119
}
117120

118-
function settle(type: AsyncIteratorMethod | "normal", value: any) {
119-
switch (type) {
120-
case "return":
121-
front!.resolve({ value: value, done: true });
122-
break;
123-
case "throw":
124-
front!.reject(value);
125-
break;
126-
default:
127-
front!.resolve({ value: value, done: false });
128-
break;
121+
/**
122+
* type == true -> return
123+
* type == false -> normal
124+
* type == 2 -> throw
125+
*/
126+
function settle(type: true | false | 2, value: any) {
127+
if (type === 2) {
128+
front!.reject(value);
129+
} else {
130+
front!.resolve({ value: value, done: type });
129131
}
130132

131133
front = front!.next;
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
2+
3+
async function* createAsyncGenerator() {
4+
try {
5+
yield 1;
6+
} finally {
7+
await Promise.resolve(2);
8+
await Promise.resolve(3);
9+
yield 4;
10+
}
11+
return 5;
12+
}
13+
14+
async function test() {
15+
const withReturnCall = createAsyncGenerator();
16+
17+
expect(await withReturnCall.next()).toEqual({ value: 1, done: false });
18+
expect(await withReturnCall.return(10)).toEqual({ value: 4, done: false });
19+
expect(await withReturnCall.next()).toEqual({ value: 10, done: true });
20+
}
21+
22+
return test();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"plugins": [
3+
"transform-async-generator-functions"
4+
],
5+
"parserOpts": {
6+
"allowReturnOutsideFunction": true
7+
},
8+
"minNodeVersion": "8.0.0"
9+
}

packages/babel-preset-env/test/fixtures/corejs2-babel-7/usage-shippedProposals/output.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/babel-runtime-corejs3/helpers/esm/wrapAsyncGenerator.js

Lines changed: 18 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -8,55 +8,42 @@ function _wrapAsyncGenerator(e) {
88
};
99
}
1010
function AsyncGenerator(e) {
11-
var r, t;
12-
function resume(r, t) {
11+
var t, n;
12+
function resume(t, n) {
1313
try {
14-
var n = e[r](t),
15-
o = n.value,
14+
var r = e[t](n),
15+
o = r.value,
1616
u = o instanceof OverloadYield;
17-
_Promise.resolve(u ? o.v : o).then(function (t) {
17+
_Promise.resolve(u ? o.v : o).then(function (n) {
1818
if (u) {
19-
var i = "return" === r ? "return" : "next";
20-
if (!o.k || t.done) return resume(i, t);
21-
t = e[i](t).value;
19+
var i = "return" === t && o.k ? t : "next";
20+
if (!o.k || n.done) return resume(i, n);
21+
n = e[i](n).value;
2222
}
23-
settle(n.done ? "return" : "normal", t);
23+
settle(!!r.done, n);
2424
}, function (e) {
2525
resume("throw", e);
2626
});
2727
} catch (e) {
28-
settle("throw", e);
28+
settle(2, e);
2929
}
3030
}
31-
function settle(e, n) {
32-
switch (e) {
33-
case "return":
34-
r.resolve({
35-
value: n,
36-
done: !0
37-
});
38-
break;
39-
case "throw":
40-
r.reject(n);
41-
break;
42-
default:
43-
r.resolve({
44-
value: n,
45-
done: !1
46-
});
47-
}
48-
(r = r.next) ? resume(r.key, r.arg) : t = null;
31+
function settle(e, r) {
32+
2 === e ? t.reject(r) : t.resolve({
33+
value: r,
34+
done: e
35+
}), (t = t.next) ? resume(t.key, t.arg) : n = null;
4936
}
50-
this._invoke = function (e, n) {
37+
this._invoke = function (e, r) {
5138
return new _Promise(function (o, u) {
5239
var i = {
5340
key: e,
54-
arg: n,
41+
arg: r,
5542
resolve: o,
5643
reject: u,
5744
next: null
5845
};
59-
t ? t = t.next = i : (r = t = i, resume(e, n));
46+
n ? n = n.next = i : (t = n = i, resume(e, r));
6047
});
6148
}, "function" != typeof e["return"] && (this["return"] = void 0);
6249
}

0 commit comments

Comments
 (0)