Skip to content

Commit 7183b14

Browse files
authored
Fix captured let/const in 'for' condition or incrementer (microsoft#47681)
1 parent 9d5f62a commit 7183b14

File tree

2 files changed

+28
-14
lines changed

2 files changed

+28
-14
lines changed

src/compiler/transformers/es2015.ts

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2954,9 +2954,11 @@ namespace ts {
29542954
// variables declared in the loop initializer that will be changed inside the loop
29552955
const loopOutParameters: LoopOutParameter[] = [];
29562956
if (loopInitializer && (getCombinedNodeFlags(loopInitializer) & NodeFlags.BlockScoped)) {
2957-
const hasCapturedBindingsInForInitializer = shouldConvertInitializerOfForStatement(node);
2957+
const hasCapturedBindingsInForHead = shouldConvertInitializerOfForStatement(node) ||
2958+
shouldConvertConditionOfForStatement(node) ||
2959+
shouldConvertIncrementorOfForStatement(node);
29582960
for (const decl of loopInitializer.declarations) {
2959-
processLoopVariableDeclaration(node, decl, loopParameters, loopOutParameters, hasCapturedBindingsInForInitializer);
2961+
processLoopVariableDeclaration(node, decl, loopParameters, loopOutParameters, hasCapturedBindingsInForHead);
29602962
}
29612963
}
29622964

@@ -3434,26 +3436,32 @@ namespace ts {
34343436
});
34353437
}
34363438

3437-
function processLoopVariableDeclaration(container: IterationStatement, decl: VariableDeclaration | BindingElement, loopParameters: ParameterDeclaration[], loopOutParameters: LoopOutParameter[], hasCapturedBindingsInForInitializer: boolean) {
3439+
function processLoopVariableDeclaration(container: IterationStatement, decl: VariableDeclaration | BindingElement, loopParameters: ParameterDeclaration[], loopOutParameters: LoopOutParameter[], hasCapturedBindingsInForHead: boolean) {
34383440
const name = decl.name;
34393441
if (isBindingPattern(name)) {
34403442
for (const element of name.elements) {
34413443
if (!isOmittedExpression(element)) {
3442-
processLoopVariableDeclaration(container, element, loopParameters, loopOutParameters, hasCapturedBindingsInForInitializer);
3444+
processLoopVariableDeclaration(container, element, loopParameters, loopOutParameters, hasCapturedBindingsInForHead);
34433445
}
34443446
}
34453447
}
34463448
else {
34473449
loopParameters.push(factory.createParameterDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, name));
34483450
const checkFlags = resolver.getNodeCheckFlags(decl);
3449-
if (checkFlags & NodeCheckFlags.NeedsLoopOutParameter || hasCapturedBindingsInForInitializer) {
3451+
if (checkFlags & NodeCheckFlags.NeedsLoopOutParameter || hasCapturedBindingsInForHead) {
34503452
const outParamName = factory.createUniqueName("out_" + idText(name));
34513453
let flags: LoopOutParameterFlags = 0;
34523454
if (checkFlags & NodeCheckFlags.NeedsLoopOutParameter) {
34533455
flags |= LoopOutParameterFlags.Body;
34543456
}
3455-
if (isForStatement(container) && container.initializer && resolver.isBindingCapturedByNode(container.initializer, decl)) {
3456-
flags |= LoopOutParameterFlags.Initializer;
3457+
if (isForStatement(container)) {
3458+
if (container.initializer && resolver.isBindingCapturedByNode(container.initializer, decl)) {
3459+
flags |= LoopOutParameterFlags.Initializer;
3460+
}
3461+
if (container.condition && resolver.isBindingCapturedByNode(container.condition, decl) ||
3462+
container.incrementor && resolver.isBindingCapturedByNode(container.incrementor, decl)) {
3463+
flags |= LoopOutParameterFlags.Body;
3464+
}
34573465
}
34583466
loopOutParameters.push({ flags, originalName: name, outParamName });
34593467
}

tests/baselines/reference/capturedLetConstInLoop1.js

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -231,11 +231,13 @@ var _loop_11 = function (y) {
231231
else
232232
inc_1 = true;
233233
if (!(use(function () { return y; }), y < 1))
234-
return "break";
234+
return out_y_2 = y, "break";
235+
out_y_2 = y;
235236
};
236-
var inc_1 = false;
237+
var out_y_2, inc_1 = false;
237238
for (var y = 0;;) {
238239
var state_1 = _loop_11(y);
240+
y = out_y_2;
239241
if (state_1 === "break")
240242
break;
241243
}
@@ -244,28 +246,32 @@ var _loop_12 = function (y) {
244246
use(function () { return y; }), ++y;
245247
else
246248
inc_2 = true;
249+
out_y_3 = y;
247250
};
248-
var inc_2 = false;
251+
var out_y_3, inc_2 = false;
249252
for (var y = 0; y < 1;) {
250253
_loop_12(y);
254+
y = out_y_3;
251255
}
252256
var _loop_init_2 = function () {
253257
var y = (use(function () { return y; }), 0);
254-
out_y_2 = y;
258+
out_y_4 = y;
255259
};
256260
var _loop_13 = function (y) {
257261
if (inc_3)
258262
use(function () { return y; }), ++y;
259263
else
260264
inc_3 = true;
261265
if (!(use(function () { return y; }), y < 1))
262-
return out_y_2 = y, "break";
266+
return out_y_4 = y, "break";
263267
use(function () { return y; });
268+
out_y_4 = y;
264269
};
265-
var out_y_2, inc_3 = false;
270+
var out_y_4, inc_3 = false;
266271
_loop_init_2();
267-
for (var y = out_y_2;;) {
272+
for (var y = out_y_4;;) {
268273
var state_2 = _loop_13(y);
274+
y = out_y_4;
269275
if (state_2 === "break")
270276
break;
271277
}

0 commit comments

Comments
 (0)