@@ -5,6 +5,38 @@ namespace ts {
55 AsyncMethodsWithSuper = 1 << 0
66 }
77
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+
840 export function transformES2018 ( context : TransformationContext ) {
941 const {
1042 resumeLexicalEnvironment,
@@ -26,7 +58,7 @@ namespace ts {
2658 let enabledSubstitutions : ESNextSubstitutionFlags ;
2759 let enclosingFunctionFlags : FunctionFlags ;
2860 let enclosingSuperContainerFlags : NodeCheckFlags = 0 ;
29- let hasLexicalThis : boolean ;
61+ let hierarchyFacts : HierarchyFacts = 0 ;
3062
3163 let currentSourceFile : SourceFile ;
3264 let taggedTemplateStringDeclarations : VariableDeclaration [ ] ;
@@ -40,6 +72,30 @@ namespace ts {
4072
4173 return chainBundle ( transformSourceFile ) ;
4274
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+
4399 function recordTaggedTemplateString ( temp : Identifier ) {
44100 taggedTemplateStringDeclarations = append (
45101 taggedTemplateStringDeclarations ,
@@ -75,11 +131,11 @@ namespace ts {
75131 return node ;
76132 }
77133
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 ) ;
81137 const result = cb ( value ) ;
82- hasLexicalThis = false ;
138+ exitSubtree ( ancestorFacts ) ;
83139 return result ;
84140 }
85141 return cb ( value ) ;
@@ -112,26 +168,66 @@ namespace ts {
112168 return visitVariableStatement ( node as VariableStatement ) ;
113169 case SyntaxKind . VariableDeclaration :
114170 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 ) ;
115179 case SyntaxKind . ForOfStatement :
116180 return visitForOfStatement ( node as ForOfStatement , /*outermostLabeledStatement*/ undefined ) ;
117181 case SyntaxKind . ForStatement :
118- return visitForStatement ( node as ForStatement ) ;
182+ return doWithHierarchyFacts (
183+ visitForStatement ,
184+ node as ForStatement ,
185+ HierarchyFacts . IterationStatementExcludes ,
186+ HierarchyFacts . IterationStatementIncludes ) ;
119187 case SyntaxKind . VoidExpression :
120188 return visitVoidExpression ( node as VoidExpression ) ;
121189 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 ) ;
123195 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 ) ;
125201 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 ) ;
127207 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 ) ;
129213 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 ) ;
131219 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 ) ;
133225 case SyntaxKind . ArrowFunction :
134- return visitArrowFunction ( node as ArrowFunction ) ;
226+ return doWithHierarchyFacts (
227+ visitArrowFunction ,
228+ node as ArrowFunction ,
229+ HierarchyFacts . ArrowFunctionExcludes ,
230+ HierarchyFacts . ArrowFunctionIncludes ) ;
135231 case SyntaxKind . Parameter :
136232 return visitParameter ( node as ParameterDeclaration ) ;
137233 case SyntaxKind . ExpressionStatement :
@@ -152,7 +248,11 @@ namespace ts {
152248 return visitEachChild ( node , visitor , context ) ;
153249 case SyntaxKind . ClassDeclaration :
154250 case SyntaxKind . ClassExpression :
155- return doWithLexicalThis ( visitDefault , node ) ;
251+ return doWithHierarchyFacts (
252+ visitDefault ,
253+ node ,
254+ HierarchyFacts . ClassOrFunctionExcludes ,
255+ HierarchyFacts . ClassOrFunctionIncludes ) ;
156256 default :
157257 return visitEachChild ( node , visitor , context ) ;
158258 }
@@ -231,7 +331,7 @@ namespace ts {
231331 if ( statement . kind === SyntaxKind . ForOfStatement && ( < ForOfStatement > statement ) . awaitModifier ) {
232332 return visitForOfStatement ( < ForOfStatement > statement , node ) ;
233333 }
234- return restoreEnclosingLabel ( visitEachChild ( statement , visitor , context ) , node ) ;
334+ return restoreEnclosingLabel ( visitNode ( statement , visitor , isStatement , liftToBlock ) , node ) ;
235335 }
236336 return visitEachChild ( node , visitor , context ) ;
237337 }
@@ -311,14 +411,20 @@ namespace ts {
311411 }
312412
313413 function visitSourceFile ( node : SourceFile ) : SourceFile {
414+ const ancestorFacts = enterSubtree (
415+ HierarchyFacts . SourceFileExcludes ,
416+ isEffectiveStrictModeSourceFile ( node , compilerOptions ) ?
417+ HierarchyFacts . StrictModeSourceFileIncludes :
418+ HierarchyFacts . SourceFileIncludes ) ;
314419 exportedVariableStatement = false ;
315- hasLexicalThis = ! isEffectiveStrictModeSourceFile ( node , compilerOptions ) ;
316420 const visited = visitEachChild ( node , visitor , context ) ;
317421 const statement = concatenate ( visited . statements , taggedTemplateStringDeclarations && [
318422 createVariableStatement ( /*modifiers*/ undefined ,
319423 createVariableDeclarationList ( taggedTemplateStringDeclarations ) )
320424 ] ) ;
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 ;
322428 }
323429
324430 function visitTaggedTemplateExpression ( node : TaggedTemplateExpression ) {
@@ -441,15 +547,15 @@ namespace ts {
441547 * @param node A ForOfStatement.
442548 */
443549 function visitForOfStatement ( node : ForOfStatement , outermostLabeledStatement : LabeledStatement | undefined ) : VisitResult < Statement > {
550+ const ancestorFacts = enterSubtree ( HierarchyFacts . IterationStatementExcludes , HierarchyFacts . IterationStatementIncludes ) ;
444551 if ( node . initializer . transformFlags & TransformFlags . ContainsObjectRestOrSpread ) {
445552 node = transformForOfStatementWithObjectRest ( node ) ;
446553 }
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 ;
453559 }
454560
455561 function transformForOfStatementWithObjectRest ( node : ForOfStatement ) {
@@ -528,7 +634,7 @@ namespace ts {
528634 : createAwait ( expression ) ;
529635 }
530636
531- function transformForAwaitOfStatement ( node : ForOfStatement , outermostLabeledStatement : LabeledStatement | undefined ) {
637+ function transformForAwaitOfStatement ( node : ForOfStatement , outermostLabeledStatement : LabeledStatement | undefined , ancestorFacts : HierarchyFacts ) {
532638 const expression = visitNode ( node . expression , visitor , isExpression ) ;
533639 const iterator = isIdentifier ( expression ) ? getGeneratedNameForNode ( expression ) : createTempVariable ( /*recordTempVariable*/ undefined ) ;
534640 const result = isIdentifier ( expression ) ? getGeneratedNameForNode ( iterator ) : createTempVariable ( /*recordTempVariable*/ undefined ) ;
@@ -544,13 +650,18 @@ namespace ts {
544650 hoistVariableDeclaration ( errorRecord ) ;
545651 hoistVariableDeclaration ( returnMethod ) ;
546652
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+
547658 const forStatement = setEmitFlags (
548659 setTextRange (
549660 createFor (
550661 /*initializer*/ setEmitFlags (
551662 setTextRange (
552663 createVariableDeclarationList ( [
553- setTextRange ( createVariableDeclaration ( iterator , /*type*/ undefined , callValues ) , node . expression ) ,
664+ setTextRange ( createVariableDeclaration ( iterator , /*type*/ undefined , initializer ) , node . expression ) ,
554665 createVariableDeclaration ( result )
555666 ] ) ,
556667 node . expression
@@ -809,7 +920,7 @@ namespace ts {
809920 visitLexicalEnvironment ( node . body ! . statements , visitor , context , statementOffset )
810921 )
811922 ) ,
812- hasLexicalThis
923+ ! ! ( hierarchyFacts & HierarchyFacts . HasLexicalThis )
813924 )
814925 ) ;
815926
0 commit comments