Skip to content

Commit 5b2fba3

Browse files
committed
transformGenerators: handle CommaListExpression
Uses essentially the same code as `visitCommaExpression` (which was moved, to keep both together and close to `visit{Right,Left}AssociativeBinaryExpression`). Fixes microsoft#40614.
1 parent 7a48469 commit 5b2fba3

File tree

5 files changed

+486
-36
lines changed

5 files changed

+486
-36
lines changed

src/compiler/transformers/generators.ts

Lines changed: 61 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,8 @@ namespace ts {
397397
switch (node.kind) {
398398
case SyntaxKind.BinaryExpression:
399399
return visitBinaryExpression(<BinaryExpression>node);
400+
case SyntaxKind.CommaListExpression:
401+
return visitCommaListExpression(<CommaListExpression>node);
400402
case SyntaxKind.ConditionalExpression:
401403
return visitConditionalExpression(<ConditionalExpression>node);
402404
case SyntaxKind.YieldExpression:
@@ -772,6 +774,65 @@ namespace ts {
772774
return visitEachChild(node, visitor, context);
773775
}
774776

777+
/**
778+
* Visits a comma expression containing `yield`.
779+
*
780+
* @param node The node to visit.
781+
*/
782+
function visitCommaExpression(node: BinaryExpression) {
783+
// [source]
784+
// x = a(), yield, b();
785+
//
786+
// [intermediate]
787+
// a();
788+
// .yield resumeLabel
789+
// .mark resumeLabel
790+
// x = %sent%, b();
791+
792+
let pendingExpressions: Expression[] = [];
793+
visit(node.left);
794+
visit(node.right);
795+
return factory.inlineExpressions(pendingExpressions);
796+
797+
function visit(node: Expression) {
798+
if (isBinaryExpression(node) && node.operatorToken.kind === SyntaxKind.CommaToken) {
799+
visit(node.left);
800+
visit(node.right);
801+
}
802+
else {
803+
if (containsYield(node) && pendingExpressions.length > 0) {
804+
emitWorker(OpCode.Statement, [factory.createExpressionStatement(factory.inlineExpressions(pendingExpressions))]);
805+
pendingExpressions = [];
806+
}
807+
808+
pendingExpressions.push(visitNode(node, visitor, isExpression));
809+
}
810+
}
811+
}
812+
813+
/**
814+
* Visits a comma-list expression.
815+
*
816+
* @param node The node to visit.
817+
*/
818+
function visitCommaListExpression(node: CommaListExpression) {
819+
// flattened version of `visitCommaExpression`
820+
let pendingExpressions: Expression[] = [];
821+
for (const elem of node.elements) {
822+
if (isBinaryExpression(elem) && elem.operatorToken.kind === SyntaxKind.CommaToken) {
823+
pendingExpressions.push(visitCommaExpression(elem));
824+
}
825+
else {
826+
if (containsYield(elem) && pendingExpressions.length > 0) {
827+
emitWorker(OpCode.Statement, [factory.createExpressionStatement(factory.inlineExpressions(pendingExpressions))]);
828+
pendingExpressions = [];
829+
}
830+
pendingExpressions.push(visitNode(elem, visitor, isExpression));
831+
}
832+
}
833+
return factory.inlineExpressions(pendingExpressions);
834+
}
835+
775836
/**
776837
* Visits a logical binary expression containing `yield`.
777838
*
@@ -825,42 +886,6 @@ namespace ts {
825886
return resultLocal;
826887
}
827888

828-
/**
829-
* Visits a comma expression containing `yield`.
830-
*
831-
* @param node The node to visit.
832-
*/
833-
function visitCommaExpression(node: BinaryExpression) {
834-
// [source]
835-
// x = a(), yield, b();
836-
//
837-
// [intermediate]
838-
// a();
839-
// .yield resumeLabel
840-
// .mark resumeLabel
841-
// x = %sent%, b();
842-
843-
let pendingExpressions: Expression[] = [];
844-
visit(node.left);
845-
visit(node.right);
846-
return factory.inlineExpressions(pendingExpressions);
847-
848-
function visit(node: Expression) {
849-
if (isBinaryExpression(node) && node.operatorToken.kind === SyntaxKind.CommaToken) {
850-
visit(node.left);
851-
visit(node.right);
852-
}
853-
else {
854-
if (containsYield(node) && pendingExpressions.length > 0) {
855-
emitWorker(OpCode.Statement, [factory.createExpressionStatement(factory.inlineExpressions(pendingExpressions))]);
856-
pendingExpressions = [];
857-
}
858-
859-
pendingExpressions.push(visitNode(node, visitor, isExpression));
860-
}
861-
}
862-
}
863-
864889
/**
865890
* Visits a conditional expression containing `yield`.
866891
*
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
//// [es5-asyncFunctionLongObjectLiteral.ts]
2+
// the generated code from both should be similar
3+
4+
const fooShort = async () => {
5+
return {
6+
a: await Promise.resolve(0),
7+
b: await Promise.resolve(1),
8+
c: await Promise.resolve(2),
9+
d: await Promise.resolve(3),
10+
e: await Promise.resolve(4),
11+
};
12+
}
13+
14+
const fooLong = async () => {
15+
return {
16+
a: await Promise.resolve(0),
17+
b: await Promise.resolve(1),
18+
c: await Promise.resolve(2),
19+
d: await Promise.resolve(3),
20+
e: await Promise.resolve(4),
21+
f: await Promise.resolve(5),
22+
g: await Promise.resolve(6),
23+
h: await Promise.resolve(7),
24+
i: await Promise.resolve(8),
25+
j: await Promise.resolve(9),
26+
};
27+
}
28+
29+
30+
//// [es5-asyncFunctionLongObjectLiteral.js]
31+
// the generated code from both should be similar
32+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
33+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
34+
return new (P || (P = Promise))(function (resolve, reject) {
35+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
36+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
37+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
38+
step((generator = generator.apply(thisArg, _arguments || [])).next());
39+
});
40+
};
41+
var __generator = (this && this.__generator) || function (thisArg, body) {
42+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
43+
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
44+
function verb(n) { return function (v) { return step([n, v]); }; }
45+
function step(op) {
46+
if (f) throw new TypeError("Generator is already executing.");
47+
while (_) try {
48+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
49+
if (y = 0, t) op = [op[0] & 2, t.value];
50+
switch (op[0]) {
51+
case 0: case 1: t = op; break;
52+
case 4: _.label++; return { value: op[1], done: false };
53+
case 5: _.label++; y = op[1]; op = [0]; continue;
54+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
55+
default:
56+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
57+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
58+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
59+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
60+
if (t[2]) _.ops.pop();
61+
_.trys.pop(); continue;
62+
}
63+
op = body.call(thisArg, _);
64+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
65+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
66+
}
67+
};
68+
var _this = this;
69+
var fooShort = function () { return __awaiter(_this, void 0, void 0, function () {
70+
var _a;
71+
return __generator(this, function (_b) {
72+
switch (_b.label) {
73+
case 0:
74+
_a = {};
75+
return [4 /*yield*/, Promise.resolve(0)];
76+
case 1:
77+
_a.a = _b.sent();
78+
return [4 /*yield*/, Promise.resolve(1)];
79+
case 2:
80+
_a.b = _b.sent();
81+
return [4 /*yield*/, Promise.resolve(2)];
82+
case 3:
83+
_a.c = _b.sent();
84+
return [4 /*yield*/, Promise.resolve(3)];
85+
case 4:
86+
_a.d = _b.sent();
87+
return [4 /*yield*/, Promise.resolve(4)];
88+
case 5: return [2 /*return*/, (_a.e = _b.sent(),
89+
_a)];
90+
}
91+
});
92+
}); };
93+
var fooLong = function () { return __awaiter(_this, void 0, void 0, function () {
94+
var _a;
95+
return __generator(this, function (_b) {
96+
switch (_b.label) {
97+
case 0:
98+
_a = {};
99+
return [4 /*yield*/, Promise.resolve(0)];
100+
case 1:
101+
_a.a = _b.sent();
102+
return [4 /*yield*/, Promise.resolve(1)];
103+
case 2:
104+
_a.b = _b.sent();
105+
return [4 /*yield*/, Promise.resolve(2)];
106+
case 3:
107+
_a.c = _b.sent();
108+
return [4 /*yield*/, Promise.resolve(3)];
109+
case 4:
110+
_a.d = _b.sent();
111+
return [4 /*yield*/, Promise.resolve(4)];
112+
case 5:
113+
_a.e = _b.sent();
114+
return [4 /*yield*/, Promise.resolve(5)];
115+
case 6:
116+
_a.f = _b.sent();
117+
return [4 /*yield*/, Promise.resolve(6)];
118+
case 7:
119+
_a.g = _b.sent();
120+
return [4 /*yield*/, Promise.resolve(7)];
121+
case 8:
122+
_a.h = _b.sent();
123+
return [4 /*yield*/, Promise.resolve(8)];
124+
case 9:
125+
_a.i = _b.sent();
126+
return [4 /*yield*/, Promise.resolve(9)];
127+
case 10: return [2 /*return*/, (_a.j = _b.sent(),
128+
_a)];
129+
}
130+
});
131+
}); };
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
=== tests/cases/compiler/es5-asyncFunctionLongObjectLiteral.ts ===
2+
// the generated code from both should be similar
3+
4+
const fooShort = async () => {
5+
>fooShort : Symbol(fooShort, Decl(es5-asyncFunctionLongObjectLiteral.ts, 2, 5))
6+
7+
return {
8+
a: await Promise.resolve(0),
9+
>a : Symbol(a, Decl(es5-asyncFunctionLongObjectLiteral.ts, 3, 12))
10+
>Promise.resolve : Symbol(PromiseConstructor.resolve, Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --))
11+
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --))
12+
>resolve : Symbol(PromiseConstructor.resolve, Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --))
13+
14+
b: await Promise.resolve(1),
15+
>b : Symbol(b, Decl(es5-asyncFunctionLongObjectLiteral.ts, 4, 36))
16+
>Promise.resolve : Symbol(PromiseConstructor.resolve, Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --))
17+
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --))
18+
>resolve : Symbol(PromiseConstructor.resolve, Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --))
19+
20+
c: await Promise.resolve(2),
21+
>c : Symbol(c, Decl(es5-asyncFunctionLongObjectLiteral.ts, 5, 36))
22+
>Promise.resolve : Symbol(PromiseConstructor.resolve, Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --))
23+
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --))
24+
>resolve : Symbol(PromiseConstructor.resolve, Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --))
25+
26+
d: await Promise.resolve(3),
27+
>d : Symbol(d, Decl(es5-asyncFunctionLongObjectLiteral.ts, 6, 36))
28+
>Promise.resolve : Symbol(PromiseConstructor.resolve, Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --))
29+
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --))
30+
>resolve : Symbol(PromiseConstructor.resolve, Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --))
31+
32+
e: await Promise.resolve(4),
33+
>e : Symbol(e, Decl(es5-asyncFunctionLongObjectLiteral.ts, 7, 36))
34+
>Promise.resolve : Symbol(PromiseConstructor.resolve, Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --))
35+
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --))
36+
>resolve : Symbol(PromiseConstructor.resolve, Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --))
37+
38+
};
39+
}
40+
41+
const fooLong = async () => {
42+
>fooLong : Symbol(fooLong, Decl(es5-asyncFunctionLongObjectLiteral.ts, 12, 5))
43+
44+
return {
45+
a: await Promise.resolve(0),
46+
>a : Symbol(a, Decl(es5-asyncFunctionLongObjectLiteral.ts, 13, 12))
47+
>Promise.resolve : Symbol(PromiseConstructor.resolve, Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --))
48+
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --))
49+
>resolve : Symbol(PromiseConstructor.resolve, Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --))
50+
51+
b: await Promise.resolve(1),
52+
>b : Symbol(b, Decl(es5-asyncFunctionLongObjectLiteral.ts, 14, 36))
53+
>Promise.resolve : Symbol(PromiseConstructor.resolve, Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --))
54+
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --))
55+
>resolve : Symbol(PromiseConstructor.resolve, Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --))
56+
57+
c: await Promise.resolve(2),
58+
>c : Symbol(c, Decl(es5-asyncFunctionLongObjectLiteral.ts, 15, 36))
59+
>Promise.resolve : Symbol(PromiseConstructor.resolve, Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --))
60+
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --))
61+
>resolve : Symbol(PromiseConstructor.resolve, Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --))
62+
63+
d: await Promise.resolve(3),
64+
>d : Symbol(d, Decl(es5-asyncFunctionLongObjectLiteral.ts, 16, 36))
65+
>Promise.resolve : Symbol(PromiseConstructor.resolve, Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --))
66+
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --))
67+
>resolve : Symbol(PromiseConstructor.resolve, Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --))
68+
69+
e: await Promise.resolve(4),
70+
>e : Symbol(e, Decl(es5-asyncFunctionLongObjectLiteral.ts, 17, 36))
71+
>Promise.resolve : Symbol(PromiseConstructor.resolve, Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --))
72+
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --))
73+
>resolve : Symbol(PromiseConstructor.resolve, Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --))
74+
75+
f: await Promise.resolve(5),
76+
>f : Symbol(f, Decl(es5-asyncFunctionLongObjectLiteral.ts, 18, 36))
77+
>Promise.resolve : Symbol(PromiseConstructor.resolve, Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --))
78+
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --))
79+
>resolve : Symbol(PromiseConstructor.resolve, Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --))
80+
81+
g: await Promise.resolve(6),
82+
>g : Symbol(g, Decl(es5-asyncFunctionLongObjectLiteral.ts, 19, 36))
83+
>Promise.resolve : Symbol(PromiseConstructor.resolve, Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --))
84+
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --))
85+
>resolve : Symbol(PromiseConstructor.resolve, Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --))
86+
87+
h: await Promise.resolve(7),
88+
>h : Symbol(h, Decl(es5-asyncFunctionLongObjectLiteral.ts, 20, 36))
89+
>Promise.resolve : Symbol(PromiseConstructor.resolve, Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --))
90+
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --))
91+
>resolve : Symbol(PromiseConstructor.resolve, Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --))
92+
93+
i: await Promise.resolve(8),
94+
>i : Symbol(i, Decl(es5-asyncFunctionLongObjectLiteral.ts, 21, 36))
95+
>Promise.resolve : Symbol(PromiseConstructor.resolve, Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --))
96+
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --))
97+
>resolve : Symbol(PromiseConstructor.resolve, Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --))
98+
99+
j: await Promise.resolve(9),
100+
>j : Symbol(j, Decl(es5-asyncFunctionLongObjectLiteral.ts, 22, 36))
101+
>Promise.resolve : Symbol(PromiseConstructor.resolve, Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --))
102+
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --))
103+
>resolve : Symbol(PromiseConstructor.resolve, Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --))
104+
105+
};
106+
}
107+

0 commit comments

Comments
 (0)