Skip to content

Commit b267492

Browse files
authored
Merge pull request #15282 from Microsoft/fix15156
Fix captured loop block scope binding in generator
2 parents 6793466 + 6c17613 commit b267492

File tree

5 files changed

+142
-5
lines changed

5 files changed

+142
-5
lines changed

src/compiler/transformers/es2015.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2714,9 +2714,8 @@ namespace ts {
27142714
loopBody = createBlock([loopBody], /*multiline*/ true);
27152715
}
27162716

2717-
const isAsyncBlockContainingAwait =
2718-
hierarchyFacts & HierarchyFacts.AsyncFunctionBody
2719-
&& (node.statement.transformFlags & TransformFlags.ContainsYield) !== 0;
2717+
const containsYield = (node.statement.transformFlags & TransformFlags.ContainsYield) !== 0;
2718+
const isAsyncBlockContainingAwait = containsYield && (hierarchyFacts & HierarchyFacts.AsyncFunctionBody) !== 0;
27202719

27212720
let loopBodyFlags: EmitFlags = 0;
27222721
if (currentState.containsLexicalThis) {
@@ -2739,7 +2738,7 @@ namespace ts {
27392738
setEmitFlags(
27402739
createFunctionExpression(
27412740
/*modifiers*/ undefined,
2742-
isAsyncBlockContainingAwait ? createToken(SyntaxKind.AsteriskToken) : undefined,
2741+
containsYield ? createToken(SyntaxKind.AsteriskToken) : undefined,
27432742
/*name*/ undefined,
27442743
/*typeParameters*/ undefined,
27452744
loopParameters,
@@ -2833,7 +2832,7 @@ namespace ts {
28332832
));
28342833
}
28352834

2836-
const convertedLoopBodyStatements = generateCallToConvertedLoop(functionName, loopParameters, currentState, isAsyncBlockContainingAwait);
2835+
const convertedLoopBodyStatements = generateCallToConvertedLoop(functionName, loopParameters, currentState, containsYield);
28372836

28382837
let loop: Statement;
28392838
if (convert) {
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
//// [blockScopedBindingsInDownlevelGenerator.ts]
2+
function* a() {
3+
for (const i of [1,2,3]) {
4+
(() => i)()
5+
yield i
6+
}
7+
}
8+
9+
//// [blockScopedBindingsInDownlevelGenerator.js]
10+
var __generator = (this && this.__generator) || function (thisArg, body) {
11+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
12+
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
13+
function verb(n) { return function (v) { return step([n, v]); }; }
14+
function step(op) {
15+
if (f) throw new TypeError("Generator is already executing.");
16+
while (_) try {
17+
if (f = 1, y && (t = y[op[0] & 2 ? "return" : op[0] ? "throw" : "next"]) && !(t = t.call(y, op[1])).done) return t;
18+
if (y = 0, t) op = [0, t.value];
19+
switch (op[0]) {
20+
case 0: case 1: t = op; break;
21+
case 4: _.label++; return { value: op[1], done: false };
22+
case 5: _.label++; y = op[1]; op = [0]; continue;
23+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
24+
default:
25+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
26+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
27+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
28+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
29+
if (t[2]) _.ops.pop();
30+
_.trys.pop(); continue;
31+
}
32+
op = body.call(thisArg, _);
33+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
34+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
35+
}
36+
};
37+
var __values = (this && this.__values) || function (o) {
38+
var m = typeof Symbol === "function" && o[Symbol.iterator], i = 0;
39+
if (m) return m.call(o);
40+
return {
41+
next: function () {
42+
if (o && i >= o.length) o = void 0;
43+
return { value: o && o[i++], done: !o };
44+
}
45+
};
46+
};
47+
function a() {
48+
var _loop_1, _a, _b, i, e_1_1, e_1, _c;
49+
return __generator(this, function (_d) {
50+
switch (_d.label) {
51+
case 0:
52+
_loop_1 = function (i) {
53+
return __generator(this, function (_a) {
54+
switch (_a.label) {
55+
case 0:
56+
(function () { return i; })();
57+
return [4 /*yield*/, i];
58+
case 1:
59+
_a.sent();
60+
return [2 /*return*/];
61+
}
62+
});
63+
};
64+
_d.label = 1;
65+
case 1:
66+
_d.trys.push([1, 6, 7, 8]);
67+
_a = __values([1, 2, 3]), _b = _a.next();
68+
_d.label = 2;
69+
case 2:
70+
if (!!_b.done) return [3 /*break*/, 5];
71+
i = _b.value;
72+
return [5 /*yield**/, _loop_1(i)];
73+
case 3:
74+
_d.sent();
75+
_d.label = 4;
76+
case 4:
77+
_b = _a.next();
78+
return [3 /*break*/, 2];
79+
case 5: return [3 /*break*/, 8];
80+
case 6:
81+
e_1_1 = _d.sent();
82+
e_1 = { error: e_1_1 };
83+
return [3 /*break*/, 8];
84+
case 7:
85+
try {
86+
if (_b && !_b.done && (_c = _a.return)) _c.call(_a);
87+
}
88+
finally { if (e_1) throw e_1.error; }
89+
return [7 /*endfinally*/];
90+
case 8: return [2 /*return*/];
91+
}
92+
});
93+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
=== tests/cases/compiler/blockScopedBindingsInDownlevelGenerator.ts ===
2+
function* a() {
3+
>a : Symbol(a, Decl(blockScopedBindingsInDownlevelGenerator.ts, 0, 0))
4+
5+
for (const i of [1,2,3]) {
6+
>i : Symbol(i, Decl(blockScopedBindingsInDownlevelGenerator.ts, 1, 12))
7+
8+
(() => i)()
9+
>i : Symbol(i, Decl(blockScopedBindingsInDownlevelGenerator.ts, 1, 12))
10+
11+
yield i
12+
>i : Symbol(i, Decl(blockScopedBindingsInDownlevelGenerator.ts, 1, 12))
13+
}
14+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
=== tests/cases/compiler/blockScopedBindingsInDownlevelGenerator.ts ===
2+
function* a() {
3+
>a : () => IterableIterator<number>
4+
5+
for (const i of [1,2,3]) {
6+
>i : number
7+
>[1,2,3] : number[]
8+
>1 : 1
9+
>2 : 2
10+
>3 : 3
11+
12+
(() => i)()
13+
>(() => i)() : number
14+
>(() => i) : () => number
15+
>() => i : () => number
16+
>i : number
17+
18+
yield i
19+
>yield i : any
20+
>i : number
21+
}
22+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// @target: es5
2+
// @downlevelIteration: true
3+
// @lib: es2015
4+
function* a() {
5+
for (const i of [1,2,3]) {
6+
(() => i)()
7+
yield i
8+
}
9+
}

0 commit comments

Comments
 (0)