@@ -8,9 +8,10 @@ namespace ts {
8
8
}
9
9
10
10
interface ActiveLabel {
11
+ next : ActiveLabel | undefined ;
11
12
name : __String ;
12
13
breakTarget : FlowLabel ;
13
- continueTarget : FlowLabel ;
14
+ continueTarget : FlowLabel | undefined ;
14
15
referenced : boolean ;
15
16
}
16
17
@@ -199,7 +200,7 @@ namespace ts {
199
200
let currentFalseTarget : FlowLabel | undefined ;
200
201
let currentExceptionTarget : FlowLabel | undefined ;
201
202
let preSwitchCaseFlow : FlowNode | undefined ;
202
- let activeLabels : ActiveLabel [ ] | undefined ;
203
+ let activeLabelList : ActiveLabel | undefined ;
203
204
let hasExplicitReturn : boolean ;
204
205
205
206
// state used for emit helpers
@@ -271,7 +272,7 @@ namespace ts {
271
272
currentTrueTarget = undefined ;
272
273
currentFalseTarget = undefined ;
273
274
currentExceptionTarget = undefined ;
274
- activeLabels = undefined ! ;
275
+ activeLabelList = undefined ;
275
276
hasExplicitReturn = false ;
276
277
emitFlags = NodeFlags . None ;
277
278
subtreeTransformFlags = TransformFlags . None ;
@@ -629,7 +630,7 @@ namespace ts {
629
630
const saveContinueTarget = currentContinueTarget ;
630
631
const saveReturnTarget = currentReturnTarget ;
631
632
const saveExceptionTarget = currentExceptionTarget ;
632
- const saveActiveLabels = activeLabels ;
633
+ const saveActiveLabelList = activeLabelList ;
633
634
const saveHasExplicitReturn = hasExplicitReturn ;
634
635
const isIIFE = containerFlags & ContainerFlags . IsFunctionExpression && ! hasModifier ( node , ModifierFlags . Async ) &&
635
636
! ( < FunctionLikeDeclaration > node ) . asteriskToken && ! ! getImmediatelyInvokedFunctionExpression ( node ) ;
@@ -647,7 +648,7 @@ namespace ts {
647
648
currentExceptionTarget = undefined ;
648
649
currentBreakTarget = undefined ;
649
650
currentContinueTarget = undefined ;
650
- activeLabels = undefined ;
651
+ activeLabelList = undefined ;
651
652
hasExplicitReturn = false ;
652
653
bindChildren ( node ) ;
653
654
// Reset all reachability check related flags on node (for incremental scenarios)
@@ -675,7 +676,7 @@ namespace ts {
675
676
currentContinueTarget = saveContinueTarget ;
676
677
currentReturnTarget = saveReturnTarget ;
677
678
currentExceptionTarget = saveExceptionTarget ;
678
- activeLabels = saveActiveLabels ;
679
+ activeLabelList = saveActiveLabelList ;
679
680
hasExplicitReturn = saveHasExplicitReturn ;
680
681
}
681
682
else if ( containerFlags & ContainerFlags . IsInterface ) {
@@ -1063,8 +1064,18 @@ namespace ts {
1063
1064
currentContinueTarget = saveContinueTarget ;
1064
1065
}
1065
1066
1067
+ function setContinueTarget ( node : Node , target : FlowLabel ) {
1068
+ let label = activeLabelList ;
1069
+ while ( label && node . parent . kind === SyntaxKind . LabeledStatement ) {
1070
+ label . continueTarget = target ;
1071
+ label = label . next ;
1072
+ node = node . parent ;
1073
+ }
1074
+ return target ;
1075
+ }
1076
+
1066
1077
function bindWhileStatement ( node : WhileStatement ) : void {
1067
- const preWhileLabel = createLoopLabel ( ) ;
1078
+ const preWhileLabel = setContinueTarget ( node , createLoopLabel ( ) ) ;
1068
1079
const preBodyLabel = createBranchLabel ( ) ;
1069
1080
const postWhileLabel = createBranchLabel ( ) ;
1070
1081
addAntecedent ( preWhileLabel , currentFlow ) ;
@@ -1078,13 +1089,8 @@ namespace ts {
1078
1089
1079
1090
function bindDoStatement ( node : DoStatement ) : void {
1080
1091
const preDoLabel = createLoopLabel ( ) ;
1081
- const enclosingLabeledStatement = node . parent . kind === SyntaxKind . LabeledStatement
1082
- ? lastOrUndefined ( activeLabels ! )
1083
- : undefined ;
1084
- // if do statement is wrapped in labeled statement then target labels for break/continue with or without
1085
- // label should be the same
1086
- const preConditionLabel = enclosingLabeledStatement ? enclosingLabeledStatement . continueTarget : createBranchLabel ( ) ;
1087
- const postDoLabel = enclosingLabeledStatement ? enclosingLabeledStatement . breakTarget : createBranchLabel ( ) ;
1092
+ const preConditionLabel = setContinueTarget ( node , createBranchLabel ( ) ) ;
1093
+ const postDoLabel = createBranchLabel ( ) ;
1088
1094
addAntecedent ( preDoLabel , currentFlow ) ;
1089
1095
currentFlow = preDoLabel ;
1090
1096
bindIterativeStatement ( node . statement , postDoLabel , preConditionLabel ) ;
@@ -1095,7 +1101,7 @@ namespace ts {
1095
1101
}
1096
1102
1097
1103
function bindForStatement ( node : ForStatement ) : void {
1098
- const preLoopLabel = createLoopLabel ( ) ;
1104
+ const preLoopLabel = setContinueTarget ( node , createLoopLabel ( ) ) ;
1099
1105
const preBodyLabel = createBranchLabel ( ) ;
1100
1106
const postLoopLabel = createBranchLabel ( ) ;
1101
1107
bind ( node . initializer ) ;
@@ -1110,7 +1116,7 @@ namespace ts {
1110
1116
}
1111
1117
1112
1118
function bindForInOrForOfStatement ( node : ForInOrOfStatement ) : void {
1113
- const preLoopLabel = createLoopLabel ( ) ;
1119
+ const preLoopLabel = setContinueTarget ( node , createLoopLabel ( ) ) ;
1114
1120
const postLoopLabel = createBranchLabel ( ) ;
1115
1121
bind ( node . expression ) ;
1116
1122
addAntecedent ( preLoopLabel , currentFlow ) ;
@@ -1154,11 +1160,9 @@ namespace ts {
1154
1160
}
1155
1161
1156
1162
function findActiveLabel ( name : __String ) {
1157
- if ( activeLabels ) {
1158
- for ( const label of activeLabels ) {
1159
- if ( label . name === name ) {
1160
- return label ;
1161
- }
1163
+ for ( let label = activeLabelList ; label ; label = label . next ) {
1164
+ if ( label . name === name ) {
1165
+ return label ;
1162
1166
}
1163
1167
}
1164
1168
return undefined ;
@@ -1313,21 +1317,6 @@ namespace ts {
1313
1317
bindEach ( node . statements ) ;
1314
1318
}
1315
1319
1316
- function pushActiveLabel ( name : __String , breakTarget : FlowLabel , continueTarget : FlowLabel ) : ActiveLabel {
1317
- const activeLabel : ActiveLabel = {
1318
- name,
1319
- breakTarget,
1320
- continueTarget,
1321
- referenced : false
1322
- } ;
1323
- ( activeLabels || ( activeLabels = [ ] ) ) . push ( activeLabel ) ;
1324
- return activeLabel ;
1325
- }
1326
-
1327
- function popActiveLabel ( ) {
1328
- activeLabels ! . pop ( ) ;
1329
- }
1330
-
1331
1320
function bindExpressionStatement ( node : ExpressionStatement ) : void {
1332
1321
bind ( node . expression ) ;
1333
1322
// A top level call expression with a dotted function name and at least one argument
@@ -1341,21 +1330,22 @@ namespace ts {
1341
1330
}
1342
1331
1343
1332
function bindLabeledStatement ( node : LabeledStatement ) : void {
1344
- const preStatementLabel = createLoopLabel ( ) ;
1345
1333
const postStatementLabel = createBranchLabel ( ) ;
1334
+ activeLabelList = {
1335
+ next : activeLabelList ,
1336
+ name : node . label . escapedText ,
1337
+ breakTarget : postStatementLabel ,
1338
+ continueTarget : undefined ,
1339
+ referenced : false
1340
+ } ;
1346
1341
bind ( node . label ) ;
1347
- addAntecedent ( preStatementLabel , currentFlow ) ;
1348
- const activeLabel = pushActiveLabel ( node . label . escapedText , postStatementLabel , preStatementLabel ) ;
1349
1342
bind ( node . statement ) ;
1350
- popActiveLabel ( ) ;
1351
- if ( ! activeLabel . referenced && ! options . allowUnusedLabels ) {
1343
+ if ( ! activeLabelList . referenced && ! options . allowUnusedLabels ) {
1352
1344
errorOrSuggestionOnNode ( unusedLabelIsError ( options ) , node . label , Diagnostics . Unused_label ) ;
1353
1345
}
1354
- if ( ! node . statement || node . statement . kind !== SyntaxKind . DoStatement ) {
1355
- // do statement sets current flow inside bindDoStatement
1356
- addAntecedent ( postStatementLabel , currentFlow ) ;
1357
- currentFlow = finishFlowLabel ( postStatementLabel ) ;
1358
- }
1346
+ activeLabelList = activeLabelList . next ;
1347
+ addAntecedent ( postStatementLabel , currentFlow ) ;
1348
+ currentFlow = finishFlowLabel ( postStatementLabel ) ;
1359
1349
}
1360
1350
1361
1351
function bindDestructuringTargetFlow ( node : Expression ) {
0 commit comments