Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix for-in enumeration containing yield in generator #51295

Merged
merged 1 commit into from Oct 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
33 changes: 20 additions & 13 deletions src/compiler/transformers/generators.ts
Expand Up @@ -1516,40 +1516,44 @@ namespace ts {
}

function transformAndEmitForInStatement(node: ForInStatement) {
// TODO(rbuckton): Source map locations
if (containsYield(node)) {
// [source]
// for (var p in o) {
// /*body*/
// }
//
// [intermediate]
// .local _a, _b, _i
// _a = [];
// for (_b in o) _a.push(_b);
// .local _b, _a, _c, _i
// _b = [];
// _a = o;
// for (_c in _a) _b.push(_c);
// _i = 0;
// .loop incrementLabel, endLoopLabel
// .mark conditionLabel
// .brfalse endLoopLabel, (_i < _a.length)
// p = _a[_i];
// .brfalse endLoopLabel, (_i < _b.length)
// _c = _b[_i];
// .brfalse incrementLabel, (_c in _a)
// p = _c;
// /*body*/
// .mark incrementLabel
// _b++;
// _c++;
// .br conditionLabel
// .endloop
// .mark endLoopLabel

const keysArray = declareLocal(); // _a
const key = declareLocal(); // _b
const obj = declareLocal(); // _a
const keysArray = declareLocal(); // _b
const key = declareLocal(); // _c
const keysIndex = factory.createLoopVariable(); // _i
const initializer = node.initializer;
hoistVariableDeclaration(keysIndex);
emitAssignment(obj, visitNode(node.expression, visitor, isExpression));
emitAssignment(keysArray, factory.createArrayLiteralExpression());

emitStatement(
factory.createForInStatement(
key,
visitNode(node.expression, visitor, isExpression),
obj,
factory.createExpressionStatement(
factory.createCallExpression(
factory.createPropertyAccessExpression(keysArray, "push"),
Expand All @@ -1564,10 +1568,13 @@ namespace ts {

const conditionLabel = defineLabel();
const incrementLabel = defineLabel();
const endLabel = beginLoopBlock(incrementLabel);
const endLoopLabel = beginLoopBlock(incrementLabel);

markLabel(conditionLabel);
emitBreakWhenFalse(endLabel, factory.createLessThan(keysIndex, factory.createPropertyAccessExpression(keysArray, "length")));
emitBreakWhenFalse(endLoopLabel, factory.createLessThan(keysIndex, factory.createPropertyAccessExpression(keysArray, "length")));

emitAssignment(key, factory.createElementAccessExpression(keysArray, keysIndex));
emitBreakWhenFalse(incrementLabel, factory.createBinaryExpression(key, SyntaxKind.InKeyword, obj));

let variable: Expression;
if (isVariableDeclarationList(initializer)) {
Expand All @@ -1582,7 +1589,7 @@ namespace ts {
Debug.assert(isLeftHandSideExpression(variable));
}

emitAssignment(variable, factory.createElementAccessExpression(keysArray, keysIndex));
emitAssignment(variable, key);
transformAndEmitEmbeddedStatement(node.statement);

markLabel(incrementLabel);
Expand Down
176 changes: 97 additions & 79 deletions tests/baselines/reference/es5-asyncFunctionForInStatements.js
Expand Up @@ -50,22 +50,24 @@ function forInStatement0() {
}
function forInStatement1() {
return __awaiter(this, void 0, void 0, function () {
var _a, _b, _i;
return __generator(this, function (_c) {
switch (_c.label) {
case 0:
_a = [];
return [4 /*yield*/, y];
var _a, _b, _c, _i;
return __generator(this, function (_d) {
switch (_d.label) {
case 0: return [4 /*yield*/, y];
case 1:
for (_b in _c.sent())
_a.push(_b);
_a = _d.sent();
_b = [];
for (_c in _a)
_b.push(_c);
_i = 0;
_c.label = 2;
_d.label = 2;
case 2:
if (!(_i < _a.length)) return [3 /*break*/, 4];
x = _a[_i];
if (!(_i < _b.length)) return [3 /*break*/, 4];
_c = _b[_i];
if (!(_c in _a)) return [3 /*break*/, 3];
x = _c;
z;
_c.label = 3;
_d.label = 3;
case 3:
_i++;
return [3 /*break*/, 2];
Expand All @@ -76,22 +78,25 @@ function forInStatement1() {
}
function forInStatement2() {
return __awaiter(this, void 0, void 0, function () {
var _a, _b, _i;
return __generator(this, function (_c) {
switch (_c.label) {
var _a, _b, _c, _i;
return __generator(this, function (_d) {
switch (_d.label) {
case 0:
_a = [];
for (_b in y)
_a.push(_b);
_a = y;
_b = [];
for (_c in _a)
_b.push(_c);
_i = 0;
_c.label = 1;
_d.label = 1;
case 1:
if (!(_i < _a.length)) return [3 /*break*/, 4];
x = _a[_i];
if (!(_i < _b.length)) return [3 /*break*/, 4];
_c = _b[_i];
if (!(_c in _a)) return [3 /*break*/, 3];
x = _c;
return [4 /*yield*/, z];
case 2:
_c.sent();
_c.label = 3;
_d.sent();
_d.label = 3;
case 3:
_i++;
return [3 /*break*/, 1];
Expand All @@ -102,22 +107,25 @@ function forInStatement2() {
}
function forInStatement3() {
return __awaiter(this, void 0, void 0, function () {
var _a, _b, _i;
return __generator(this, function (_c) {
switch (_c.label) {
var _a, _b, _c, _i;
return __generator(this, function (_d) {
switch (_d.label) {
case 0:
_a = [];
for (_b in y)
_a.push(_b);
_a = y;
_b = [];
for (_c in _a)
_b.push(_c);
_i = 0;
_c.label = 1;
_d.label = 1;
case 1:
if (!(_i < _a.length)) return [3 /*break*/, 4];
if (!(_i < _b.length)) return [3 /*break*/, 4];
_c = _b[_i];
if (!(_c in _a)) return [3 /*break*/, 3];
return [4 /*yield*/, x];
case 2:
(_c.sent()).a = _a[_i];
(_d.sent()).a = _c;
z;
_c.label = 3;
_d.label = 3;
case 3:
_i++;
return [3 /*break*/, 1];
Expand All @@ -128,22 +136,24 @@ function forInStatement3() {
}
function forInStatement4() {
return __awaiter(this, void 0, void 0, function () {
var _a, _b, _i;
return __generator(this, function (_c) {
switch (_c.label) {
case 0:
_a = [];
return [4 /*yield*/, y];
var _a, _b, _c, _i;
return __generator(this, function (_d) {
switch (_d.label) {
case 0: return [4 /*yield*/, y];
case 1:
for (_b in _c.sent())
_a.push(_b);
_a = _d.sent();
_b = [];
for (_c in _a)
_b.push(_c);
_i = 0;
_c.label = 2;
_d.label = 2;
case 2:
if (!(_i < _a.length)) return [3 /*break*/, 4];
x.a = _a[_i];
if (!(_i < _b.length)) return [3 /*break*/, 4];
_c = _b[_i];
if (!(_c in _a)) return [3 /*break*/, 3];
x.a = _c;
z;
_c.label = 3;
_d.label = 3;
case 3:
_i++;
return [3 /*break*/, 2];
Expand All @@ -154,22 +164,25 @@ function forInStatement4() {
}
function forInStatement5() {
return __awaiter(this, void 0, void 0, function () {
var _a, _b, _i;
return __generator(this, function (_c) {
switch (_c.label) {
var _a, _b, _c, _i;
return __generator(this, function (_d) {
switch (_d.label) {
case 0:
_a = [];
for (_b in y)
_a.push(_b);
_a = y;
_b = [];
for (_c in _a)
_b.push(_c);
_i = 0;
_c.label = 1;
_d.label = 1;
case 1:
if (!(_i < _a.length)) return [3 /*break*/, 4];
x.a = _a[_i];
if (!(_i < _b.length)) return [3 /*break*/, 4];
_c = _b[_i];
if (!(_c in _a)) return [3 /*break*/, 3];
x.a = _c;
return [4 /*yield*/, z];
case 2:
_c.sent();
_c.label = 3;
_d.sent();
_d.label = 3;
case 3:
_i++;
return [3 /*break*/, 1];
Expand All @@ -191,22 +204,24 @@ function forInStatement6() {
}
function forInStatement7() {
return __awaiter(this, void 0, void 0, function () {
var _a, _b, _i, b;
return __generator(this, function (_c) {
switch (_c.label) {
case 0:
_a = [];
return [4 /*yield*/, y];
var _a, _b, _c, _i, b;
return __generator(this, function (_d) {
switch (_d.label) {
case 0: return [4 /*yield*/, y];
case 1:
for (_b in _c.sent())
_a.push(_b);
_a = _d.sent();
_b = [];
for (_c in _a)
_b.push(_c);
_i = 0;
_c.label = 2;
_d.label = 2;
case 2:
if (!(_i < _a.length)) return [3 /*break*/, 4];
b = _a[_i];
if (!(_i < _b.length)) return [3 /*break*/, 4];
_c = _b[_i];
if (!(_c in _a)) return [3 /*break*/, 3];
b = _c;
z;
_c.label = 3;
_d.label = 3;
case 3:
_i++;
return [3 /*break*/, 2];
Expand All @@ -217,22 +232,25 @@ function forInStatement7() {
}
function forInStatement8() {
return __awaiter(this, void 0, void 0, function () {
var _a, _b, _i, c;
return __generator(this, function (_c) {
switch (_c.label) {
var _a, _b, _c, _i, c;
return __generator(this, function (_d) {
switch (_d.label) {
case 0:
_a = [];
for (_b in y)
_a.push(_b);
_a = y;
_b = [];
for (_c in _a)
_b.push(_c);
_i = 0;
_c.label = 1;
_d.label = 1;
case 1:
if (!(_i < _a.length)) return [3 /*break*/, 4];
c = _a[_i];
if (!(_i < _b.length)) return [3 /*break*/, 4];
_c = _b[_i];
if (!(_c in _a)) return [3 /*break*/, 3];
c = _c;
return [4 /*yield*/, z];
case 2:
_c.sent();
_c.label = 3;
_d.sent();
_d.label = 3;
case 3:
_i++;
return [3 /*break*/, 1];
Expand Down