@@ -5,6 +5,38 @@ namespace ts {
5
5
AsyncMethodsWithSuper = 1 << 0
6
6
}
7
7
8
+ // Facts we track as we traverse the tree
9
+ const enum HierarchyFacts {
10
+ None = 0 ,
11
+
12
+ //
13
+ // Ancestor facts
14
+ //
15
+
16
+ HasLexicalThis = 1 << 0 ,
17
+ IterationContainer = 1 << 1 ,
18
+ // NOTE: do not add more ancestor flags without also updating AncestorFactsMask below.
19
+
20
+ //
21
+ // Ancestor masks
22
+ //
23
+
24
+ AncestorFactsMask = ( IterationContainer << 1 ) - 1 ,
25
+
26
+ SourceFileIncludes = HasLexicalThis ,
27
+ SourceFileExcludes = IterationContainer ,
28
+ StrictModeSourceFileIncludes = None ,
29
+
30
+ ClassOrFunctionIncludes = HasLexicalThis ,
31
+ ClassOrFunctionExcludes = IterationContainer ,
32
+
33
+ ArrowFunctionIncludes = None ,
34
+ ArrowFunctionExcludes = ClassOrFunctionExcludes ,
35
+
36
+ IterationStatementIncludes = IterationContainer ,
37
+ IterationStatementExcludes = None ,
38
+ }
39
+
8
40
export function transformES2018 ( context : TransformationContext ) {
9
41
const {
10
42
resumeLexicalEnvironment,
@@ -26,7 +58,7 @@ namespace ts {
26
58
let enabledSubstitutions : ESNextSubstitutionFlags ;
27
59
let enclosingFunctionFlags : FunctionFlags ;
28
60
let enclosingSuperContainerFlags : NodeCheckFlags = 0 ;
29
- let hasLexicalThis : boolean ;
61
+ let hierarchyFacts : HierarchyFacts = 0 ;
30
62
31
63
let currentSourceFile : SourceFile ;
32
64
let taggedTemplateStringDeclarations : VariableDeclaration [ ] ;
@@ -40,6 +72,30 @@ namespace ts {
40
72
41
73
return chainBundle ( transformSourceFile ) ;
42
74
75
+ function affectsSubtree ( excludeFacts : HierarchyFacts , includeFacts : HierarchyFacts ) {
76
+ return hierarchyFacts !== ( hierarchyFacts & ~ excludeFacts | includeFacts ) ;
77
+ }
78
+
79
+ /**
80
+ * Sets the `HierarchyFacts` for this node prior to visiting this node's subtree, returning the facts set prior to modification.
81
+ * @param excludeFacts The existing `HierarchyFacts` to reset before visiting the subtree.
82
+ * @param includeFacts The new `HierarchyFacts` to set before visiting the subtree.
83
+ */
84
+ function enterSubtree ( excludeFacts : HierarchyFacts , includeFacts : HierarchyFacts ) {
85
+ const ancestorFacts = hierarchyFacts ;
86
+ hierarchyFacts = ( hierarchyFacts & ~ excludeFacts | includeFacts ) & HierarchyFacts . AncestorFactsMask ;
87
+ return ancestorFacts ;
88
+ }
89
+
90
+ /**
91
+ * Restores the `HierarchyFacts` for this node's ancestor after visiting this node's
92
+ * subtree.
93
+ * @param ancestorFacts The `HierarchyFacts` of the ancestor to restore after visiting the subtree.
94
+ */
95
+ function exitSubtree ( ancestorFacts : HierarchyFacts ) {
96
+ hierarchyFacts = ancestorFacts ;
97
+ }
98
+
43
99
function recordTaggedTemplateString ( temp : Identifier ) {
44
100
taggedTemplateStringDeclarations = append (
45
101
taggedTemplateStringDeclarations ,
@@ -75,11 +131,11 @@ namespace ts {
75
131
return node ;
76
132
}
77
133
78
- function doWithLexicalThis < T , U > ( cb : ( value : T ) => U , value : T ) {
79
- if ( ! hasLexicalThis ) {
80
- hasLexicalThis = true ;
134
+ function doWithHierarchyFacts < T , U > ( cb : ( value : T ) => U , value : T , excludeFacts : HierarchyFacts , includeFacts : HierarchyFacts ) {
135
+ if ( affectsSubtree ( excludeFacts , includeFacts ) ) {
136
+ const ancestorFacts = enterSubtree ( excludeFacts , includeFacts ) ;
81
137
const result = cb ( value ) ;
82
- hasLexicalThis = false ;
138
+ exitSubtree ( ancestorFacts ) ;
83
139
return result ;
84
140
}
85
141
return cb ( value ) ;
@@ -112,26 +168,66 @@ namespace ts {
112
168
return visitVariableStatement ( node as VariableStatement ) ;
113
169
case SyntaxKind . VariableDeclaration :
114
170
return visitVariableDeclaration ( node as VariableDeclaration ) ;
171
+ case SyntaxKind . DoStatement :
172
+ case SyntaxKind . WhileStatement :
173
+ case SyntaxKind . ForInStatement :
174
+ return doWithHierarchyFacts (
175
+ visitDefault ,
176
+ node ,
177
+ HierarchyFacts . IterationStatementExcludes ,
178
+ HierarchyFacts . IterationStatementIncludes ) ;
115
179
case SyntaxKind . ForOfStatement :
116
180
return visitForOfStatement ( node as ForOfStatement , /*outermostLabeledStatement*/ undefined ) ;
117
181
case SyntaxKind . ForStatement :
118
- return visitForStatement ( node as ForStatement ) ;
182
+ return doWithHierarchyFacts (
183
+ visitForStatement ,
184
+ node as ForStatement ,
185
+ HierarchyFacts . IterationStatementExcludes ,
186
+ HierarchyFacts . IterationStatementIncludes ) ;
119
187
case SyntaxKind . VoidExpression :
120
188
return visitVoidExpression ( node as VoidExpression ) ;
121
189
case SyntaxKind . Constructor :
122
- return doWithLexicalThis ( visitConstructorDeclaration , node as ConstructorDeclaration ) ;
190
+ return doWithHierarchyFacts (
191
+ visitConstructorDeclaration ,
192
+ node as ConstructorDeclaration ,
193
+ HierarchyFacts . ClassOrFunctionExcludes ,
194
+ HierarchyFacts . ClassOrFunctionIncludes ) ;
123
195
case SyntaxKind . MethodDeclaration :
124
- return doWithLexicalThis ( visitMethodDeclaration , node as MethodDeclaration ) ;
196
+ return doWithHierarchyFacts (
197
+ visitMethodDeclaration ,
198
+ node as MethodDeclaration ,
199
+ HierarchyFacts . ClassOrFunctionExcludes ,
200
+ HierarchyFacts . ClassOrFunctionIncludes ) ;
125
201
case SyntaxKind . GetAccessor :
126
- return doWithLexicalThis ( visitGetAccessorDeclaration , node as GetAccessorDeclaration ) ;
202
+ return doWithHierarchyFacts (
203
+ visitGetAccessorDeclaration ,
204
+ node as GetAccessorDeclaration ,
205
+ HierarchyFacts . ClassOrFunctionExcludes ,
206
+ HierarchyFacts . ClassOrFunctionIncludes ) ;
127
207
case SyntaxKind . SetAccessor :
128
- return doWithLexicalThis ( visitSetAccessorDeclaration , node as SetAccessorDeclaration ) ;
208
+ return doWithHierarchyFacts (
209
+ visitSetAccessorDeclaration ,
210
+ node as SetAccessorDeclaration ,
211
+ HierarchyFacts . ClassOrFunctionExcludes ,
212
+ HierarchyFacts . ClassOrFunctionIncludes ) ;
129
213
case SyntaxKind . FunctionDeclaration :
130
- return doWithLexicalThis ( visitFunctionDeclaration , node as FunctionDeclaration ) ;
214
+ return doWithHierarchyFacts (
215
+ visitFunctionDeclaration ,
216
+ node as FunctionDeclaration ,
217
+ HierarchyFacts . ClassOrFunctionExcludes ,
218
+ HierarchyFacts . ClassOrFunctionIncludes ) ;
131
219
case SyntaxKind . FunctionExpression :
132
- return doWithLexicalThis ( visitFunctionExpression , node as FunctionExpression ) ;
220
+ return doWithHierarchyFacts (
221
+ visitFunctionExpression ,
222
+ node as FunctionExpression ,
223
+ HierarchyFacts . ClassOrFunctionExcludes ,
224
+ HierarchyFacts . ClassOrFunctionIncludes ) ;
133
225
case SyntaxKind . ArrowFunction :
134
- return visitArrowFunction ( node as ArrowFunction ) ;
226
+ return doWithHierarchyFacts (
227
+ visitArrowFunction ,
228
+ node as ArrowFunction ,
229
+ HierarchyFacts . ArrowFunctionExcludes ,
230
+ HierarchyFacts . ArrowFunctionIncludes ) ;
135
231
case SyntaxKind . Parameter :
136
232
return visitParameter ( node as ParameterDeclaration ) ;
137
233
case SyntaxKind . ExpressionStatement :
@@ -152,7 +248,11 @@ namespace ts {
152
248
return visitEachChild ( node , visitor , context ) ;
153
249
case SyntaxKind . ClassDeclaration :
154
250
case SyntaxKind . ClassExpression :
155
- return doWithLexicalThis ( visitDefault , node ) ;
251
+ return doWithHierarchyFacts (
252
+ visitDefault ,
253
+ node ,
254
+ HierarchyFacts . ClassOrFunctionExcludes ,
255
+ HierarchyFacts . ClassOrFunctionIncludes ) ;
156
256
default :
157
257
return visitEachChild ( node , visitor , context ) ;
158
258
}
@@ -231,7 +331,7 @@ namespace ts {
231
331
if ( statement . kind === SyntaxKind . ForOfStatement && ( < ForOfStatement > statement ) . awaitModifier ) {
232
332
return visitForOfStatement ( < ForOfStatement > statement , node ) ;
233
333
}
234
- return restoreEnclosingLabel ( visitEachChild ( statement , visitor , context ) , node ) ;
334
+ return restoreEnclosingLabel ( visitNode ( statement , visitor , isStatement , liftToBlock ) , node ) ;
235
335
}
236
336
return visitEachChild ( node , visitor , context ) ;
237
337
}
@@ -311,14 +411,20 @@ namespace ts {
311
411
}
312
412
313
413
function visitSourceFile ( node : SourceFile ) : SourceFile {
414
+ const ancestorFacts = enterSubtree (
415
+ HierarchyFacts . SourceFileExcludes ,
416
+ isEffectiveStrictModeSourceFile ( node , compilerOptions ) ?
417
+ HierarchyFacts . StrictModeSourceFileIncludes :
418
+ HierarchyFacts . SourceFileIncludes ) ;
314
419
exportedVariableStatement = false ;
315
- hasLexicalThis = ! isEffectiveStrictModeSourceFile ( node , compilerOptions ) ;
316
420
const visited = visitEachChild ( node , visitor , context ) ;
317
421
const statement = concatenate ( visited . statements , taggedTemplateStringDeclarations && [
318
422
createVariableStatement ( /*modifiers*/ undefined ,
319
423
createVariableDeclarationList ( taggedTemplateStringDeclarations ) )
320
424
] ) ;
321
- return updateSourceFileNode ( visited , setTextRange ( createNodeArray ( statement ) , node . statements ) ) ;
425
+ const result = updateSourceFileNode ( visited , setTextRange ( createNodeArray ( statement ) , node . statements ) ) ;
426
+ exitSubtree ( ancestorFacts ) ;
427
+ return result ;
322
428
}
323
429
324
430
function visitTaggedTemplateExpression ( node : TaggedTemplateExpression ) {
@@ -441,15 +547,15 @@ namespace ts {
441
547
* @param node A ForOfStatement.
442
548
*/
443
549
function visitForOfStatement ( node : ForOfStatement , outermostLabeledStatement : LabeledStatement | undefined ) : VisitResult < Statement > {
550
+ const ancestorFacts = enterSubtree ( HierarchyFacts . IterationStatementExcludes , HierarchyFacts . IterationStatementIncludes ) ;
444
551
if ( node . initializer . transformFlags & TransformFlags . ContainsObjectRestOrSpread ) {
445
552
node = transformForOfStatementWithObjectRest ( node ) ;
446
553
}
447
- if ( node . awaitModifier ) {
448
- return transformForAwaitOfStatement ( node , outermostLabeledStatement ) ;
449
- }
450
- else {
451
- return restoreEnclosingLabel ( visitEachChild ( node , visitor , context ) , outermostLabeledStatement ) ;
452
- }
554
+ const result = node . awaitModifier ?
555
+ transformForAwaitOfStatement ( node , outermostLabeledStatement , ancestorFacts ) :
556
+ restoreEnclosingLabel ( visitEachChild ( node , visitor , context ) , outermostLabeledStatement ) ;
557
+ exitSubtree ( ancestorFacts ) ;
558
+ return result ;
453
559
}
454
560
455
561
function transformForOfStatementWithObjectRest ( node : ForOfStatement ) {
@@ -528,7 +634,7 @@ namespace ts {
528
634
: createAwait ( expression ) ;
529
635
}
530
636
531
- function transformForAwaitOfStatement ( node : ForOfStatement , outermostLabeledStatement : LabeledStatement | undefined ) {
637
+ function transformForAwaitOfStatement ( node : ForOfStatement , outermostLabeledStatement : LabeledStatement | undefined , ancestorFacts : HierarchyFacts ) {
532
638
const expression = visitNode ( node . expression , visitor , isExpression ) ;
533
639
const iterator = isIdentifier ( expression ) ? getGeneratedNameForNode ( expression ) : createTempVariable ( /*recordTempVariable*/ undefined ) ;
534
640
const result = isIdentifier ( expression ) ? getGeneratedNameForNode ( iterator ) : createTempVariable ( /*recordTempVariable*/ undefined ) ;
@@ -544,13 +650,18 @@ namespace ts {
544
650
hoistVariableDeclaration ( errorRecord ) ;
545
651
hoistVariableDeclaration ( returnMethod ) ;
546
652
653
+ // if we are enclosed in an outer loop ensure we reset 'errorRecord' per each iteration
654
+ const initializer = ancestorFacts & HierarchyFacts . IterationContainer ?
655
+ inlineExpressions ( [ createAssignment ( errorRecord , createVoidZero ( ) ) , callValues ] ) :
656
+ callValues ;
657
+
547
658
const forStatement = setEmitFlags (
548
659
setTextRange (
549
660
createFor (
550
661
/*initializer*/ setEmitFlags (
551
662
setTextRange (
552
663
createVariableDeclarationList ( [
553
- setTextRange ( createVariableDeclaration ( iterator , /*type*/ undefined , callValues ) , node . expression ) ,
664
+ setTextRange ( createVariableDeclaration ( iterator , /*type*/ undefined , initializer ) , node . expression ) ,
554
665
createVariableDeclaration ( result )
555
666
] ) ,
556
667
node . expression
@@ -809,7 +920,7 @@ namespace ts {
809
920
visitLexicalEnvironment ( node . body ! . statements , visitor , context , statementOffset )
810
921
)
811
922
) ,
812
- hasLexicalThis
923
+ ! ! ( hierarchyFacts & HierarchyFacts . HasLexicalThis )
813
924
)
814
925
) ;
815
926
0 commit comments