Skip to content

Commit

Permalink
fix for-in enumeration containing yield in generator (#51295)
Browse files Browse the repository at this point in the history
  • Loading branch information
rbuckton committed Oct 28, 2022
1 parent 3d2b401 commit 7f8426f
Show file tree
Hide file tree
Showing 6 changed files with 244 additions and 92 deletions.
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

0 comments on commit 7f8426f

Please sign in to comment.