mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-12-12 20:25:48 -06:00
fix for-in enumeration containing yield in generator (#51295)
This commit is contained in:
parent
3d2b4017eb
commit
7f8426f4df
@ -1516,7 +1516,6 @@ namespace ts {
|
||||
}
|
||||
|
||||
function transformAndEmitForInStatement(node: ForInStatement) {
|
||||
// TODO(rbuckton): Source map locations
|
||||
if (containsYield(node)) {
|
||||
// [source]
|
||||
// for (var p in o) {
|
||||
@ -1524,32 +1523,37 @@ namespace ts {
|
||||
// }
|
||||
//
|
||||
// [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"),
|
||||
@ -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)) {
|
||||
@ -1582,7 +1589,7 @@ namespace ts {
|
||||
Debug.assert(isLeftHandSideExpression(variable));
|
||||
}
|
||||
|
||||
emitAssignment(variable, factory.createElementAccessExpression(keysArray, keysIndex));
|
||||
emitAssignment(variable, key);
|
||||
transformAndEmitEmbeddedStatement(node.statement);
|
||||
|
||||
markLabel(incrementLabel);
|
||||
|
||||
@ -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];
|
||||
@ -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];
|
||||
@ -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];
|
||||
@ -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];
|
||||
@ -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];
|
||||
@ -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];
|
||||
@ -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];
|
||||
|
||||
@ -0,0 +1,68 @@
|
||||
//// [yieldInForInInDownlevelGenerator.ts]
|
||||
// https://github.com/microsoft/TypeScript/issues/49808
|
||||
function* gen() {
|
||||
var obj: any = { foo: 1, bar: 2 };
|
||||
for (var key in obj) {
|
||||
yield key;
|
||||
delete obj.bar;
|
||||
}
|
||||
}
|
||||
|
||||
//// [yieldInForInInDownlevelGenerator.js]
|
||||
var __generator = (this && this.__generator) || function (thisArg, body) {
|
||||
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
||||
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
||||
function verb(n) { return function (v) { return step([n, v]); }; }
|
||||
function step(op) {
|
||||
if (f) throw new TypeError("Generator is already executing.");
|
||||
while (_) try {
|
||||
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;
|
||||
if (y = 0, t) op = [op[0] & 2, t.value];
|
||||
switch (op[0]) {
|
||||
case 0: case 1: t = op; break;
|
||||
case 4: _.label++; return { value: op[1], done: false };
|
||||
case 5: _.label++; y = op[1]; op = [0]; continue;
|
||||
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
||||
default:
|
||||
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
||||
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
||||
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
||||
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
||||
if (t[2]) _.ops.pop();
|
||||
_.trys.pop(); continue;
|
||||
}
|
||||
op = body.call(thisArg, _);
|
||||
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
||||
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
||||
}
|
||||
};
|
||||
// https://github.com/microsoft/TypeScript/issues/49808
|
||||
function gen() {
|
||||
var obj, _a, _b, _c, _i, key;
|
||||
return __generator(this, function (_d) {
|
||||
switch (_d.label) {
|
||||
case 0:
|
||||
obj = { foo: 1, bar: 2 };
|
||||
_a = obj;
|
||||
_b = [];
|
||||
for (_c in _a)
|
||||
_b.push(_c);
|
||||
_i = 0;
|
||||
_d.label = 1;
|
||||
case 1:
|
||||
if (!(_i < _b.length)) return [3 /*break*/, 4];
|
||||
_c = _b[_i];
|
||||
if (!(_c in _a)) return [3 /*break*/, 3];
|
||||
key = _c;
|
||||
return [4 /*yield*/, key];
|
||||
case 2:
|
||||
_d.sent();
|
||||
delete obj.bar;
|
||||
_d.label = 3;
|
||||
case 3:
|
||||
_i++;
|
||||
return [3 /*break*/, 1];
|
||||
case 4: return [2 /*return*/];
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -0,0 +1,21 @@
|
||||
=== tests/cases/compiler/yieldInForInInDownlevelGenerator.ts ===
|
||||
// https://github.com/microsoft/TypeScript/issues/49808
|
||||
function* gen() {
|
||||
>gen : Symbol(gen, Decl(yieldInForInInDownlevelGenerator.ts, 0, 0))
|
||||
|
||||
var obj: any = { foo: 1, bar: 2 };
|
||||
>obj : Symbol(obj, Decl(yieldInForInInDownlevelGenerator.ts, 2, 5))
|
||||
>foo : Symbol(foo, Decl(yieldInForInInDownlevelGenerator.ts, 2, 18))
|
||||
>bar : Symbol(bar, Decl(yieldInForInInDownlevelGenerator.ts, 2, 26))
|
||||
|
||||
for (var key in obj) {
|
||||
>key : Symbol(key, Decl(yieldInForInInDownlevelGenerator.ts, 3, 10))
|
||||
>obj : Symbol(obj, Decl(yieldInForInInDownlevelGenerator.ts, 2, 5))
|
||||
|
||||
yield key;
|
||||
>key : Symbol(key, Decl(yieldInForInInDownlevelGenerator.ts, 3, 10))
|
||||
|
||||
delete obj.bar;
|
||||
>obj : Symbol(obj, Decl(yieldInForInInDownlevelGenerator.ts, 2, 5))
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,28 @@
|
||||
=== tests/cases/compiler/yieldInForInInDownlevelGenerator.ts ===
|
||||
// https://github.com/microsoft/TypeScript/issues/49808
|
||||
function* gen() {
|
||||
>gen : () => Generator<string, void, unknown>
|
||||
|
||||
var obj: any = { foo: 1, bar: 2 };
|
||||
>obj : any
|
||||
>{ foo: 1, bar: 2 } : { foo: number; bar: number; }
|
||||
>foo : number
|
||||
>1 : 1
|
||||
>bar : number
|
||||
>2 : 2
|
||||
|
||||
for (var key in obj) {
|
||||
>key : string
|
||||
>obj : any
|
||||
|
||||
yield key;
|
||||
>yield key : any
|
||||
>key : string
|
||||
|
||||
delete obj.bar;
|
||||
>delete obj.bar : boolean
|
||||
>obj.bar : any
|
||||
>obj : any
|
||||
>bar : any
|
||||
}
|
||||
}
|
||||
10
tests/cases/compiler/yieldInForInInDownlevelGenerator.ts
Normal file
10
tests/cases/compiler/yieldInForInInDownlevelGenerator.ts
Normal file
@ -0,0 +1,10 @@
|
||||
// @target: es5
|
||||
// @lib: esnext
|
||||
// https://github.com/microsoft/TypeScript/issues/49808
|
||||
function* gen() {
|
||||
var obj: any = { foo: 1, bar: 2 };
|
||||
for (var key in obj) {
|
||||
yield key;
|
||||
delete obj.bar;
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user