• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*@internal*/
2namespace ts {
3    const enum ESNextSubstitutionFlags {
4        /** Enables substitutions for async methods with `super` calls. */
5        AsyncMethodsWithSuper = 1 << 0
6    }
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
40    export function transformES2018(context: TransformationContext) {
41        const {
42            factory,
43            getEmitHelperFactory: emitHelpers,
44            resumeLexicalEnvironment,
45            endLexicalEnvironment,
46            hoistVariableDeclaration
47        } = context;
48
49        const resolver = context.getEmitResolver();
50        const compilerOptions = context.getCompilerOptions();
51        const languageVersion = getEmitScriptTarget(compilerOptions);
52
53        const previousOnEmitNode = context.onEmitNode;
54        context.onEmitNode = onEmitNode;
55
56        const previousOnSubstituteNode = context.onSubstituteNode;
57        context.onSubstituteNode = onSubstituteNode;
58
59        let exportedVariableStatement = false;
60        let enabledSubstitutions: ESNextSubstitutionFlags;
61        let enclosingFunctionFlags: FunctionFlags;
62        let enclosingSuperContainerFlags: NodeCheckFlags = 0;
63        let hierarchyFacts: HierarchyFacts = 0;
64
65        let currentSourceFile: SourceFile;
66        let taggedTemplateStringDeclarations: VariableDeclaration[];
67
68        /** Keeps track of property names accessed on super (`super.x`) within async functions. */
69        let capturedSuperProperties: Set<__String>;
70        /** Whether the async function contains an element access on super (`super[x]`). */
71        let hasSuperElementAccess: boolean;
72        /** A set of node IDs for generated super accessors. */
73        const substitutedSuperAccessors: boolean[] = [];
74
75        return chainBundle(context, transformSourceFile);
76
77        function affectsSubtree(excludeFacts: HierarchyFacts, includeFacts: HierarchyFacts) {
78            return hierarchyFacts !== (hierarchyFacts & ~excludeFacts | includeFacts);
79        }
80
81        /**
82         * Sets the `HierarchyFacts` for this node prior to visiting this node's subtree, returning the facts set prior to modification.
83         * @param excludeFacts The existing `HierarchyFacts` to reset before visiting the subtree.
84         * @param includeFacts The new `HierarchyFacts` to set before visiting the subtree.
85         */
86        function enterSubtree(excludeFacts: HierarchyFacts, includeFacts: HierarchyFacts) {
87            const ancestorFacts = hierarchyFacts;
88            hierarchyFacts = (hierarchyFacts & ~excludeFacts | includeFacts) & HierarchyFacts.AncestorFactsMask;
89            return ancestorFacts;
90        }
91
92        /**
93         * Restores the `HierarchyFacts` for this node's ancestor after visiting this node's
94         * subtree.
95         * @param ancestorFacts The `HierarchyFacts` of the ancestor to restore after visiting the subtree.
96         */
97        function exitSubtree(ancestorFacts: HierarchyFacts) {
98            hierarchyFacts = ancestorFacts;
99        }
100
101        function recordTaggedTemplateString(temp: Identifier) {
102            taggedTemplateStringDeclarations = append(
103                taggedTemplateStringDeclarations,
104                factory.createVariableDeclaration(temp));
105        }
106
107        function transformSourceFile(node: SourceFile) {
108            if (node.isDeclarationFile) {
109                return node;
110            }
111
112            currentSourceFile = node;
113            const visited = visitSourceFile(node);
114            addEmitHelpers(visited, context.readEmitHelpers());
115
116            currentSourceFile = undefined!;
117            taggedTemplateStringDeclarations = undefined!;
118            return visited;
119        }
120
121        function visitor(node: Node): VisitResult<Node> {
122            return visitorWorker(node, /*expressionResultIsUnused*/ false);
123        }
124
125        function visitorWithUnusedExpressionResult(node: Node): VisitResult<Node> {
126            return visitorWorker(node, /*expressionResultIsUnused*/ true);
127        }
128
129        function visitorNoAsyncModifier(node: Node): VisitResult<Node> {
130            if (node.kind === SyntaxKind.AsyncKeyword) {
131                return undefined;
132            }
133            return node;
134        }
135
136        function doWithHierarchyFacts<T, U>(cb: (value: T) => U, value: T, excludeFacts: HierarchyFacts, includeFacts: HierarchyFacts) {
137            if (affectsSubtree(excludeFacts, includeFacts)) {
138                const ancestorFacts = enterSubtree(excludeFacts, includeFacts);
139                const result = cb(value);
140                exitSubtree(ancestorFacts);
141                return result;
142            }
143            return cb(value);
144        }
145
146        function visitDefault(node: Node): VisitResult<Node> {
147            return visitEachChild(node, visitor, context);
148        }
149
150        /**
151         * @param expressionResultIsUnused Indicates the result of an expression is unused by the parent node (i.e., the left side of a comma or the
152         * expression of an `ExpressionStatement`).
153         */
154        function visitorWorker(node: Node, expressionResultIsUnused: boolean): VisitResult<Node> {
155            if ((node.transformFlags & TransformFlags.ContainsES2018) === 0) {
156                return node;
157            }
158            switch (node.kind) {
159                case SyntaxKind.AwaitExpression:
160                    return visitAwaitExpression(node as AwaitExpression);
161                case SyntaxKind.YieldExpression:
162                    return visitYieldExpression(node as YieldExpression);
163                case SyntaxKind.ReturnStatement:
164                    return visitReturnStatement(node as ReturnStatement);
165                case SyntaxKind.LabeledStatement:
166                    return visitLabeledStatement(node as LabeledStatement);
167                case SyntaxKind.ObjectLiteralExpression:
168                    return visitObjectLiteralExpression(node as ObjectLiteralExpression);
169                case SyntaxKind.BinaryExpression:
170                    return visitBinaryExpression(node as BinaryExpression, expressionResultIsUnused);
171                case SyntaxKind.CommaListExpression:
172                    return visitCommaListExpression(node as CommaListExpression, expressionResultIsUnused);
173                case SyntaxKind.CatchClause:
174                    return visitCatchClause(node as CatchClause);
175                case SyntaxKind.VariableStatement:
176                    return visitVariableStatement(node as VariableStatement);
177                case SyntaxKind.VariableDeclaration:
178                    return visitVariableDeclaration(node as VariableDeclaration);
179                case SyntaxKind.DoStatement:
180                case SyntaxKind.WhileStatement:
181                case SyntaxKind.ForInStatement:
182                    return doWithHierarchyFacts(
183                        visitDefault,
184                        node,
185                        HierarchyFacts.IterationStatementExcludes,
186                        HierarchyFacts.IterationStatementIncludes);
187                case SyntaxKind.ForOfStatement:
188                    return visitForOfStatement(node as ForOfStatement, /*outermostLabeledStatement*/ undefined);
189                case SyntaxKind.ForStatement:
190                    return doWithHierarchyFacts(
191                        visitForStatement,
192                        node as ForStatement,
193                        HierarchyFacts.IterationStatementExcludes,
194                        HierarchyFacts.IterationStatementIncludes);
195                case SyntaxKind.VoidExpression:
196                    return visitVoidExpression(node as VoidExpression);
197                case SyntaxKind.Constructor:
198                    return doWithHierarchyFacts(
199                        visitConstructorDeclaration,
200                        node as ConstructorDeclaration,
201                        HierarchyFacts.ClassOrFunctionExcludes,
202                        HierarchyFacts.ClassOrFunctionIncludes);
203                case SyntaxKind.MethodDeclaration:
204                    return doWithHierarchyFacts(
205                        visitMethodDeclaration,
206                        node as MethodDeclaration,
207                        HierarchyFacts.ClassOrFunctionExcludes,
208                        HierarchyFacts.ClassOrFunctionIncludes);
209                case SyntaxKind.GetAccessor:
210                    return doWithHierarchyFacts(
211                        visitGetAccessorDeclaration,
212                        node as GetAccessorDeclaration,
213                        HierarchyFacts.ClassOrFunctionExcludes,
214                        HierarchyFacts.ClassOrFunctionIncludes);
215                case SyntaxKind.SetAccessor:
216                    return doWithHierarchyFacts(
217                        visitSetAccessorDeclaration,
218                        node as SetAccessorDeclaration,
219                        HierarchyFacts.ClassOrFunctionExcludes,
220                        HierarchyFacts.ClassOrFunctionIncludes);
221                case SyntaxKind.FunctionDeclaration:
222                    return doWithHierarchyFacts(
223                        visitFunctionDeclaration,
224                        node as FunctionDeclaration,
225                        HierarchyFacts.ClassOrFunctionExcludes,
226                        HierarchyFacts.ClassOrFunctionIncludes);
227                case SyntaxKind.FunctionExpression:
228                    return doWithHierarchyFacts(
229                        visitFunctionExpression,
230                        node as FunctionExpression,
231                        HierarchyFacts.ClassOrFunctionExcludes,
232                        HierarchyFacts.ClassOrFunctionIncludes);
233                case SyntaxKind.ArrowFunction:
234                    return doWithHierarchyFacts(
235                        visitArrowFunction,
236                        node as ArrowFunction,
237                        HierarchyFacts.ArrowFunctionExcludes,
238                        HierarchyFacts.ArrowFunctionIncludes);
239                case SyntaxKind.Parameter:
240                    return visitParameter(node as ParameterDeclaration);
241                case SyntaxKind.ExpressionStatement:
242                    return visitExpressionStatement(node as ExpressionStatement);
243                case SyntaxKind.ParenthesizedExpression:
244                    return visitParenthesizedExpression(node as ParenthesizedExpression, expressionResultIsUnused);
245                case SyntaxKind.TaggedTemplateExpression:
246                    return visitTaggedTemplateExpression(node as TaggedTemplateExpression);
247                case SyntaxKind.PropertyAccessExpression:
248                    if (capturedSuperProperties && isPropertyAccessExpression(node) && node.expression.kind === SyntaxKind.SuperKeyword) {
249                        capturedSuperProperties.add(node.name.escapedText);
250                    }
251                    return visitEachChild(node, visitor, context);
252                case SyntaxKind.ElementAccessExpression:
253                    if (capturedSuperProperties && (<ElementAccessExpression>node).expression.kind === SyntaxKind.SuperKeyword) {
254                        hasSuperElementAccess = true;
255                    }
256                    return visitEachChild(node, visitor, context);
257                case SyntaxKind.ClassDeclaration:
258                case SyntaxKind.ClassExpression:
259                    return doWithHierarchyFacts(
260                        visitDefault,
261                        node,
262                        HierarchyFacts.ClassOrFunctionExcludes,
263                        HierarchyFacts.ClassOrFunctionIncludes);
264                default:
265                    return visitEachChild(node, visitor, context);
266            }
267        }
268
269        function visitAwaitExpression(node: AwaitExpression): Expression {
270            if (enclosingFunctionFlags & FunctionFlags.Async && enclosingFunctionFlags & FunctionFlags.Generator) {
271                return setOriginalNode(
272                    setTextRange(
273                        factory.createYieldExpression(/*asteriskToken*/ undefined, emitHelpers().createAwaitHelper(visitNode(node.expression, visitor, isExpression))),
274                        /*location*/ node
275                    ),
276                    node
277                );
278            }
279            return visitEachChild(node, visitor, context);
280        }
281
282        function visitYieldExpression(node: YieldExpression) {
283            if (enclosingFunctionFlags & FunctionFlags.Async && enclosingFunctionFlags & FunctionFlags.Generator) {
284                if (node.asteriskToken) {
285                    const expression = visitNode(Debug.assertDefined(node.expression), visitor, isExpression);
286
287                    return setOriginalNode(
288                        setTextRange(
289                            factory.createYieldExpression(
290                                /*asteriskToken*/ undefined,
291                                emitHelpers().createAwaitHelper(
292                                    factory.updateYieldExpression(
293                                        node,
294                                        node.asteriskToken,
295                                        setTextRange(
296                                            emitHelpers().createAsyncDelegatorHelper(
297                                                setTextRange(
298                                                    emitHelpers().createAsyncValuesHelper(expression),
299                                                    expression
300                                                )
301                                            ),
302                                            expression
303                                        )
304                                    )
305                                )
306                            ),
307                            node
308                        ),
309                        node
310                    );
311                }
312
313                return setOriginalNode(
314                    setTextRange(
315                        factory.createYieldExpression(
316                            /*asteriskToken*/ undefined,
317                            createDownlevelAwait(
318                                node.expression
319                                    ? visitNode(node.expression, visitor, isExpression)
320                                    : factory.createVoidZero()
321                            )
322                        ),
323                        node
324                    ),
325                    node
326                );
327            }
328
329            return visitEachChild(node, visitor, context);
330        }
331
332        function visitReturnStatement(node: ReturnStatement) {
333            if (enclosingFunctionFlags & FunctionFlags.Async && enclosingFunctionFlags & FunctionFlags.Generator) {
334                return factory.updateReturnStatement(node, createDownlevelAwait(
335                    node.expression ? visitNode(node.expression, visitor, isExpression) : factory.createVoidZero()
336                ));
337            }
338
339            return visitEachChild(node, visitor, context);
340        }
341
342        function visitLabeledStatement(node: LabeledStatement) {
343            if (enclosingFunctionFlags & FunctionFlags.Async) {
344                const statement = unwrapInnermostStatementOfLabel(node);
345                if (statement.kind === SyntaxKind.ForOfStatement && (<ForOfStatement>statement).awaitModifier) {
346                    return visitForOfStatement(<ForOfStatement>statement, node);
347                }
348                return factory.restoreEnclosingLabel(visitNode(statement, visitor, isStatement, factory.liftToBlock), node);
349            }
350            return visitEachChild(node, visitor, context);
351        }
352
353        function chunkObjectLiteralElements(elements: readonly ObjectLiteralElementLike[]): Expression[] {
354            let chunkObject: ObjectLiteralElementLike[] | undefined;
355            const objects: Expression[] = [];
356            for (const e of elements) {
357                if (e.kind === SyntaxKind.SpreadAssignment) {
358                    if (chunkObject) {
359                        objects.push(factory.createObjectLiteralExpression(chunkObject));
360                        chunkObject = undefined;
361                    }
362                    const target = e.expression;
363                    objects.push(visitNode(target, visitor, isExpression));
364                }
365                else {
366                    chunkObject = append(chunkObject, e.kind === SyntaxKind.PropertyAssignment
367                        ? factory.createPropertyAssignment(e.name, visitNode(e.initializer, visitor, isExpression))
368                        : visitNode(e, visitor, isObjectLiteralElementLike));
369                }
370            }
371            if (chunkObject) {
372                objects.push(factory.createObjectLiteralExpression(chunkObject));
373            }
374
375            return objects;
376        }
377
378        function visitObjectLiteralExpression(node: ObjectLiteralExpression): Expression {
379            if (node.transformFlags & TransformFlags.ContainsObjectRestOrSpread) {
380                // spread elements emit like so:
381                // non-spread elements are chunked together into object literals, and then all are passed to __assign:
382                //     { a, ...o, b } => __assign(__assign({a}, o), {b});
383                // If the first element is a spread element, then the first argument to __assign is {}:
384                //     { ...o, a, b, ...o2 } => __assign(__assign(__assign({}, o), {a, b}), o2)
385                //
386                // We cannot call __assign with more than two elements, since any element could cause side effects. For
387                // example:
388                //      var k = { a: 1, b: 2 };
389                //      var o = { a: 3, ...k, b: k.a++ };
390                //      // expected: { a: 1, b: 1 }
391                // If we translate the above to `__assign({ a: 3 }, k, { b: k.a++ })`, the `k.a++` will evaluate before
392                // `k` is spread and we end up with `{ a: 2, b: 1 }`.
393                //
394                // This also occurs for spread elements, not just property assignments:
395                //      var k = { a: 1, get b() { l = { z: 9 }; return 2; } };
396                //      var l = { c: 3 };
397                //      var o = { ...k, ...l };
398                //      // expected: { a: 1, b: 2, z: 9 }
399                // If we translate the above to `__assign({}, k, l)`, the `l` will evaluate before `k` is spread and we
400                // end up with `{ a: 1, b: 2, c: 3 }`
401                const objects = chunkObjectLiteralElements(node.properties);
402                if (objects.length && objects[0].kind !== SyntaxKind.ObjectLiteralExpression) {
403                    objects.unshift(factory.createObjectLiteralExpression());
404                }
405                let expression: Expression = objects[0];
406                if (objects.length > 1) {
407                    for (let i = 1; i < objects.length; i++) {
408                        expression = emitHelpers().createAssignHelper([expression, objects[i]]);
409                    }
410                    return expression;
411                }
412                else {
413                    return emitHelpers().createAssignHelper(objects);
414                }
415            }
416            return visitEachChild(node, visitor, context);
417        }
418
419        function visitExpressionStatement(node: ExpressionStatement): ExpressionStatement {
420            return visitEachChild(node, visitorWithUnusedExpressionResult, context);
421        }
422
423        /**
424         * @param expressionResultIsUnused Indicates the result of an expression is unused by the parent node (i.e., the left side of a comma or the
425         * expression of an `ExpressionStatement`).
426         */
427        function visitParenthesizedExpression(node: ParenthesizedExpression, expressionResultIsUnused: boolean): ParenthesizedExpression {
428            return visitEachChild(node, expressionResultIsUnused ? visitorWithUnusedExpressionResult : visitor, context);
429        }
430
431        function visitSourceFile(node: SourceFile): SourceFile {
432            const ancestorFacts = enterSubtree(
433                HierarchyFacts.SourceFileExcludes,
434                isEffectiveStrictModeSourceFile(node, compilerOptions) ?
435                    HierarchyFacts.StrictModeSourceFileIncludes :
436                    HierarchyFacts.SourceFileIncludes);
437            exportedVariableStatement = false;
438            const visited = visitEachChild(node, visitor, context);
439            const statement = concatenate(visited.statements, taggedTemplateStringDeclarations && [
440                factory.createVariableStatement(/*modifiers*/ undefined,
441                    factory.createVariableDeclarationList(taggedTemplateStringDeclarations))
442            ]);
443            const result = factory.updateSourceFile(visited, setTextRange(factory.createNodeArray(statement), node.statements));
444            exitSubtree(ancestorFacts);
445            return result;
446        }
447
448        function visitTaggedTemplateExpression(node: TaggedTemplateExpression) {
449            return processTaggedTemplateExpression(
450                context,
451                node,
452                visitor,
453                currentSourceFile,
454                recordTaggedTemplateString,
455                ProcessLevel.LiftRestriction
456            );
457        }
458
459        /**
460         * Visits a BinaryExpression that contains a destructuring assignment.
461         *
462         * @param node A BinaryExpression node.
463         * @param expressionResultIsUnused Indicates the result of an expression is unused by the parent node (i.e., the left side of a comma or the
464         * expression of an `ExpressionStatement`).
465         */
466        function visitBinaryExpression(node: BinaryExpression, expressionResultIsUnused: boolean): Expression {
467            if (isDestructuringAssignment(node) && node.left.transformFlags & TransformFlags.ContainsObjectRestOrSpread) {
468                return flattenDestructuringAssignment(
469                    node,
470                    visitor,
471                    context,
472                    FlattenLevel.ObjectRest,
473                    !expressionResultIsUnused
474                );
475            }
476            if (node.operatorToken.kind === SyntaxKind.CommaToken) {
477                return factory.updateBinaryExpression(
478                    node,
479                    visitNode(node.left, visitorWithUnusedExpressionResult, isExpression),
480                    node.operatorToken,
481                    visitNode(node.right, expressionResultIsUnused ? visitorWithUnusedExpressionResult : visitor, isExpression)
482                );
483            }
484            return visitEachChild(node, visitor, context);
485        }
486
487        /**
488         * @param expressionResultIsUnused Indicates the result of an expression is unused by the parent node (i.e., the left side of a comma or the
489         * expression of an `ExpressionStatement`).
490         */
491        function visitCommaListExpression(node: CommaListExpression, expressionResultIsUnused: boolean): Expression {
492            if (expressionResultIsUnused) {
493                return visitEachChild(node, visitorWithUnusedExpressionResult, context);
494            }
495            let result: Expression[] | undefined;
496            for (let i = 0; i < node.elements.length; i++) {
497                const element = node.elements[i];
498                const visited = visitNode(element, i < node.elements.length - 1 ? visitorWithUnusedExpressionResult : visitor, isExpression);
499                if (result || visited !== element) {
500                    result ||= node.elements.slice(0, i);
501                    result.push(visited);
502                }
503            }
504            const elements = result ? setTextRange(factory.createNodeArray(result), node.elements) : node.elements;
505            return factory.updateCommaListExpression(node, elements);
506        }
507
508        function visitCatchClause(node: CatchClause) {
509            if (node.variableDeclaration &&
510                isBindingPattern(node.variableDeclaration.name) &&
511                node.variableDeclaration.name.transformFlags & TransformFlags.ContainsObjectRestOrSpread) {
512                const name = factory.getGeneratedNameForNode(node.variableDeclaration.name);
513                const updatedDecl = factory.updateVariableDeclaration(node.variableDeclaration, node.variableDeclaration.name, /*exclamationToken*/ undefined, /*type*/ undefined, name);
514                const visitedBindings = flattenDestructuringBinding(updatedDecl, visitor, context, FlattenLevel.ObjectRest);
515                let block = visitNode(node.block, visitor, isBlock);
516                if (some(visitedBindings)) {
517                    block = factory.updateBlock(block, [
518                        factory.createVariableStatement(/*modifiers*/ undefined, visitedBindings),
519                        ...block.statements,
520                    ]);
521                }
522                return factory.updateCatchClause(
523                    node,
524                    factory.updateVariableDeclaration(node.variableDeclaration, name, /*exclamationToken*/ undefined, /*type*/ undefined, /*initializer*/ undefined),
525                    block);
526            }
527            return visitEachChild(node, visitor, context);
528        }
529
530        function visitVariableStatement(node: VariableStatement): VisitResult<VariableStatement> {
531            if (hasSyntacticModifier(node, ModifierFlags.Export)) {
532                const savedExportedVariableStatement = exportedVariableStatement;
533                exportedVariableStatement = true;
534                const visited = visitEachChild(node, visitor, context);
535                exportedVariableStatement = savedExportedVariableStatement;
536                return visited;
537            }
538            return visitEachChild(node, visitor, context);
539        }
540
541        /**
542         * Visits a VariableDeclaration node with a binding pattern.
543         *
544         * @param node A VariableDeclaration node.
545         */
546        function visitVariableDeclaration(node: VariableDeclaration): VisitResult<VariableDeclaration> {
547            if (exportedVariableStatement) {
548                const savedExportedVariableStatement = exportedVariableStatement;
549                exportedVariableStatement = false;
550                const visited = visitVariableDeclarationWorker(node, /*exportedVariableStatement*/ true);
551                exportedVariableStatement = savedExportedVariableStatement;
552                return visited;
553            }
554            return visitVariableDeclarationWorker(node, /*exportedVariableStatement*/ false);
555        }
556
557        function visitVariableDeclarationWorker(node: VariableDeclaration, exportedVariableStatement: boolean): VisitResult<VariableDeclaration> {
558            // If we are here it is because the name contains a binding pattern with a rest somewhere in it.
559            if (isBindingPattern(node.name) && node.name.transformFlags & TransformFlags.ContainsObjectRestOrSpread) {
560                return flattenDestructuringBinding(
561                    node,
562                    visitor,
563                    context,
564                    FlattenLevel.ObjectRest,
565                    /*rval*/ undefined,
566                    exportedVariableStatement
567                );
568            }
569            return visitEachChild(node, visitor, context);
570        }
571
572        function visitForStatement(node: ForStatement): VisitResult<Statement> {
573            return factory.updateForStatement(
574                node,
575                visitNode(node.initializer, visitorWithUnusedExpressionResult, isForInitializer),
576                visitNode(node.condition, visitor, isExpression),
577                visitNode(node.incrementor, visitorWithUnusedExpressionResult, isExpression),
578                visitNode(node.statement, visitor, isStatement)
579            );
580        }
581
582        function visitVoidExpression(node: VoidExpression) {
583            return visitEachChild(node, visitorWithUnusedExpressionResult, context);
584        }
585
586        /**
587         * Visits a ForOfStatement and converts it into a ES2015-compatible ForOfStatement.
588         *
589         * @param node A ForOfStatement.
590         */
591        function visitForOfStatement(node: ForOfStatement, outermostLabeledStatement: LabeledStatement | undefined): VisitResult<Statement> {
592            const ancestorFacts = enterSubtree(HierarchyFacts.IterationStatementExcludes, HierarchyFacts.IterationStatementIncludes);
593            if (node.initializer.transformFlags & TransformFlags.ContainsObjectRestOrSpread) {
594                node = transformForOfStatementWithObjectRest(node);
595            }
596            const result = node.awaitModifier ?
597                transformForAwaitOfStatement(node, outermostLabeledStatement, ancestorFacts) :
598                factory.restoreEnclosingLabel(visitEachChild(node, visitor, context), outermostLabeledStatement);
599            exitSubtree(ancestorFacts);
600            return result;
601        }
602
603        function transformForOfStatementWithObjectRest(node: ForOfStatement) {
604            const initializerWithoutParens = skipParentheses(node.initializer) as ForInitializer;
605            if (isVariableDeclarationList(initializerWithoutParens) || isAssignmentPattern(initializerWithoutParens)) {
606                let bodyLocation: TextRange | undefined;
607                let statementsLocation: TextRange | undefined;
608                const temp = factory.createTempVariable(/*recordTempVariable*/ undefined);
609                const statements: Statement[] = [createForOfBindingStatement(factory, initializerWithoutParens, temp)];
610                if (isBlock(node.statement)) {
611                    addRange(statements, node.statement.statements);
612                    bodyLocation = node.statement;
613                    statementsLocation = node.statement.statements;
614                }
615                else if (node.statement) {
616                    append(statements, node.statement);
617                    bodyLocation = node.statement;
618                    statementsLocation = node.statement;
619                }
620                return factory.updateForOfStatement(
621                    node,
622                    node.awaitModifier,
623                    setTextRange(
624                        factory.createVariableDeclarationList(
625                            [
626                                setTextRange(factory.createVariableDeclaration(temp), node.initializer)
627                            ],
628                            NodeFlags.Let
629                        ),
630                        node.initializer
631                    ),
632                    node.expression,
633                    setTextRange(
634                        factory.createBlock(
635                            setTextRange(factory.createNodeArray(statements), statementsLocation),
636                            /*multiLine*/ true
637                        ),
638                        bodyLocation
639                    )
640                );
641            }
642            return node;
643        }
644
645        function convertForOfStatementHead(node: ForOfStatement, boundValue: Expression) {
646            const binding = createForOfBindingStatement(factory, node.initializer, boundValue);
647
648            let bodyLocation: TextRange | undefined;
649            let statementsLocation: TextRange | undefined;
650            const statements: Statement[] = [visitNode(binding, visitor, isStatement)];
651            const statement = visitNode(node.statement, visitor, isStatement);
652            if (isBlock(statement)) {
653                addRange(statements, statement.statements);
654                bodyLocation = statement;
655                statementsLocation = statement.statements;
656            }
657            else {
658                statements.push(statement);
659            }
660
661            return setEmitFlags(
662                setTextRange(
663                    factory.createBlock(
664                        setTextRange(factory.createNodeArray(statements), statementsLocation),
665                        /*multiLine*/ true
666                    ),
667                    bodyLocation
668                ),
669                EmitFlags.NoSourceMap | EmitFlags.NoTokenSourceMaps
670            );
671        }
672
673        function createDownlevelAwait(expression: Expression) {
674            return enclosingFunctionFlags & FunctionFlags.Generator
675                ? factory.createYieldExpression(/*asteriskToken*/ undefined, emitHelpers().createAwaitHelper(expression))
676                : factory.createAwaitExpression(expression);
677        }
678
679        function transformForAwaitOfStatement(node: ForOfStatement, outermostLabeledStatement: LabeledStatement | undefined, ancestorFacts: HierarchyFacts) {
680            const expression = visitNode(node.expression, visitor, isExpression);
681            const iterator = isIdentifier(expression) ? factory.getGeneratedNameForNode(expression) : factory.createTempVariable(/*recordTempVariable*/ undefined);
682            const result = isIdentifier(expression) ? factory.getGeneratedNameForNode(iterator) : factory.createTempVariable(/*recordTempVariable*/ undefined);
683            const errorRecord = factory.createUniqueName("e");
684            const catchVariable = factory.getGeneratedNameForNode(errorRecord);
685            const returnMethod = factory.createTempVariable(/*recordTempVariable*/ undefined);
686            const callValues = setTextRange(emitHelpers().createAsyncValuesHelper(expression), node.expression);
687            const callNext = factory.createCallExpression(factory.createPropertyAccessExpression(iterator, "next"), /*typeArguments*/ undefined, []);
688            const getDone = factory.createPropertyAccessExpression(result, "done");
689            const getValue = factory.createPropertyAccessExpression(result, "value");
690            const callReturn = factory.createFunctionCallCall(returnMethod, iterator, []);
691
692            hoistVariableDeclaration(errorRecord);
693            hoistVariableDeclaration(returnMethod);
694
695            // if we are enclosed in an outer loop ensure we reset 'errorRecord' per each iteration
696            const initializer = ancestorFacts & HierarchyFacts.IterationContainer ?
697                factory.inlineExpressions([factory.createAssignment(errorRecord, factory.createVoidZero()), callValues]) :
698                callValues;
699
700            const forStatement = setEmitFlags(
701                setTextRange(
702                    factory.createForStatement(
703                        /*initializer*/ setEmitFlags(
704                            setTextRange(
705                                factory.createVariableDeclarationList([
706                                    setTextRange(factory.createVariableDeclaration(iterator, /*exclamationToken*/ undefined, /*type*/ undefined, initializer), node.expression),
707                                    factory.createVariableDeclaration(result)
708                                ]),
709                                node.expression
710                            ),
711                            EmitFlags.NoHoisting
712                        ),
713                        /*condition*/ factory.createComma(
714                            factory.createAssignment(result, createDownlevelAwait(callNext)),
715                            factory.createLogicalNot(getDone)
716                        ),
717                        /*incrementor*/ undefined,
718                        /*statement*/ convertForOfStatementHead(node, getValue)
719                    ),
720                    /*location*/ node
721                ),
722                EmitFlags.NoTokenTrailingSourceMaps
723            );
724
725            return factory.createTryStatement(
726                factory.createBlock([
727                    factory.restoreEnclosingLabel(
728                        forStatement,
729                        outermostLabeledStatement
730                    )
731                ]),
732                factory.createCatchClause(
733                    factory.createVariableDeclaration(catchVariable),
734                    setEmitFlags(
735                        factory.createBlock([
736                            factory.createExpressionStatement(
737                                factory.createAssignment(
738                                    errorRecord,
739                                    factory.createObjectLiteralExpression([
740                                        factory.createPropertyAssignment("error", catchVariable)
741                                    ])
742                                )
743                            )
744                        ]),
745                        EmitFlags.SingleLine
746                    )
747                ),
748                factory.createBlock([
749                    factory.createTryStatement(
750                        /*tryBlock*/ factory.createBlock([
751                            setEmitFlags(
752                                factory.createIfStatement(
753                                    factory.createLogicalAnd(
754                                        factory.createLogicalAnd(
755                                            result,
756                                            factory.createLogicalNot(getDone)
757                                        ),
758                                        factory.createAssignment(
759                                            returnMethod,
760                                            factory.createPropertyAccessExpression(iterator, "return")
761                                        )
762                                    ),
763                                    factory.createExpressionStatement(createDownlevelAwait(callReturn))
764                                ),
765                                EmitFlags.SingleLine
766                            )
767                        ]),
768                        /*catchClause*/ undefined,
769                        /*finallyBlock*/ setEmitFlags(
770                            factory.createBlock([
771                                setEmitFlags(
772                                    factory.createIfStatement(
773                                        errorRecord,
774                                        factory.createThrowStatement(
775                                            factory.createPropertyAccessExpression(errorRecord, "error")
776                                        )
777                                    ),
778                                    EmitFlags.SingleLine
779                                )
780                            ]),
781                            EmitFlags.SingleLine
782                        )
783                    )
784                ])
785            );
786        }
787
788        function visitParameter(node: ParameterDeclaration): ParameterDeclaration {
789            if (node.transformFlags & TransformFlags.ContainsObjectRestOrSpread) {
790                // Binding patterns are converted into a generated name and are
791                // evaluated inside the function body.
792                return factory.updateParameterDeclaration(
793                    node,
794                    /*decorators*/ undefined,
795                    /*modifiers*/ undefined,
796                    node.dotDotDotToken,
797                    factory.getGeneratedNameForNode(node),
798                    /*questionToken*/ undefined,
799                    /*type*/ undefined,
800                    visitNode(node.initializer, visitor, isExpression)
801                );
802            }
803            return visitEachChild(node, visitor, context);
804        }
805
806        function visitConstructorDeclaration(node: ConstructorDeclaration) {
807            const savedEnclosingFunctionFlags = enclosingFunctionFlags;
808            enclosingFunctionFlags = FunctionFlags.Normal;
809            const updated = factory.updateConstructorDeclaration(
810                node,
811                /*decorators*/ undefined,
812                node.modifiers,
813                visitParameterList(node.parameters, visitor, context),
814                transformFunctionBody(node)
815            );
816            enclosingFunctionFlags = savedEnclosingFunctionFlags;
817            return updated;
818        }
819
820        function visitGetAccessorDeclaration(node: GetAccessorDeclaration) {
821            const savedEnclosingFunctionFlags = enclosingFunctionFlags;
822            enclosingFunctionFlags = FunctionFlags.Normal;
823            const updated = factory.updateGetAccessorDeclaration(
824                node,
825                /*decorators*/ undefined,
826                node.modifiers,
827                visitNode(node.name, visitor, isPropertyName),
828                visitParameterList(node.parameters, visitor, context),
829                /*type*/ undefined,
830                transformFunctionBody(node)
831            );
832            enclosingFunctionFlags = savedEnclosingFunctionFlags;
833            return updated;
834        }
835
836        function visitSetAccessorDeclaration(node: SetAccessorDeclaration) {
837            const savedEnclosingFunctionFlags = enclosingFunctionFlags;
838            enclosingFunctionFlags = FunctionFlags.Normal;
839            const updated = factory.updateSetAccessorDeclaration(
840                node,
841                /*decorators*/ undefined,
842                node.modifiers,
843                visitNode(node.name, visitor, isPropertyName),
844                visitParameterList(node.parameters, visitor, context),
845                transformFunctionBody(node)
846            );
847            enclosingFunctionFlags = savedEnclosingFunctionFlags;
848            return updated;
849        }
850
851        function visitMethodDeclaration(node: MethodDeclaration) {
852            const savedEnclosingFunctionFlags = enclosingFunctionFlags;
853            enclosingFunctionFlags = getFunctionFlags(node);
854            const updated = factory.updateMethodDeclaration(
855                node,
856                /*decorators*/ undefined,
857                enclosingFunctionFlags & FunctionFlags.Generator
858                    ? visitNodes(node.modifiers, visitorNoAsyncModifier, isModifier)
859                    : node.modifiers,
860                enclosingFunctionFlags & FunctionFlags.Async
861                    ? undefined
862                    : node.asteriskToken,
863                visitNode(node.name, visitor, isPropertyName),
864                visitNode<Token<SyntaxKind.QuestionToken>>(/*questionToken*/ undefined, visitor, isToken),
865                /*typeParameters*/ undefined,
866                visitParameterList(node.parameters, visitor, context),
867                /*type*/ undefined,
868                enclosingFunctionFlags & FunctionFlags.Async && enclosingFunctionFlags & FunctionFlags.Generator
869                    ? transformAsyncGeneratorFunctionBody(node)
870                    : transformFunctionBody(node)
871            );
872            enclosingFunctionFlags = savedEnclosingFunctionFlags;
873            return updated;
874        }
875
876        function visitFunctionDeclaration(node: FunctionDeclaration) {
877            const savedEnclosingFunctionFlags = enclosingFunctionFlags;
878            enclosingFunctionFlags = getFunctionFlags(node);
879            const updated = factory.updateFunctionDeclaration(
880                node,
881                /*decorators*/ undefined,
882                enclosingFunctionFlags & FunctionFlags.Generator
883                    ? visitNodes(node.modifiers, visitorNoAsyncModifier, isModifier)
884                    : node.modifiers,
885                enclosingFunctionFlags & FunctionFlags.Async
886                    ? undefined
887                    : node.asteriskToken,
888                node.name,
889                /*typeParameters*/ undefined,
890                visitParameterList(node.parameters, visitor, context),
891                /*type*/ undefined,
892                enclosingFunctionFlags & FunctionFlags.Async && enclosingFunctionFlags & FunctionFlags.Generator
893                    ? transformAsyncGeneratorFunctionBody(node)
894                    : transformFunctionBody(node)
895            );
896            enclosingFunctionFlags = savedEnclosingFunctionFlags;
897            return updated;
898        }
899
900        function visitArrowFunction(node: ArrowFunction) {
901            const savedEnclosingFunctionFlags = enclosingFunctionFlags;
902            enclosingFunctionFlags = getFunctionFlags(node);
903            const updated = factory.updateArrowFunction(
904                node,
905                node.modifiers,
906                /*typeParameters*/ undefined,
907                visitParameterList(node.parameters, visitor, context),
908                /*type*/ undefined,
909                node.equalsGreaterThanToken,
910                transformFunctionBody(node),
911            );
912            enclosingFunctionFlags = savedEnclosingFunctionFlags;
913            return updated;
914        }
915
916        function visitFunctionExpression(node: FunctionExpression) {
917            const savedEnclosingFunctionFlags = enclosingFunctionFlags;
918            enclosingFunctionFlags = getFunctionFlags(node);
919            const updated = factory.updateFunctionExpression(
920                node,
921                enclosingFunctionFlags & FunctionFlags.Generator
922                    ? visitNodes(node.modifiers, visitorNoAsyncModifier, isModifier)
923                    : node.modifiers,
924                enclosingFunctionFlags & FunctionFlags.Async
925                    ? undefined
926                    : node.asteriskToken,
927                node.name,
928                /*typeParameters*/ undefined,
929                visitParameterList(node.parameters, visitor, context),
930                /*type*/ undefined,
931                enclosingFunctionFlags & FunctionFlags.Async && enclosingFunctionFlags & FunctionFlags.Generator
932                    ? transformAsyncGeneratorFunctionBody(node)
933                    : transformFunctionBody(node)
934            );
935            enclosingFunctionFlags = savedEnclosingFunctionFlags;
936            return updated;
937        }
938
939        function transformAsyncGeneratorFunctionBody(node: MethodDeclaration | AccessorDeclaration | FunctionDeclaration | FunctionExpression): FunctionBody {
940            resumeLexicalEnvironment();
941            const statements: Statement[] = [];
942            const statementOffset = factory.copyPrologue(node.body!.statements, statements, /*ensureUseStrict*/ false, visitor);
943            appendObjectRestAssignmentsIfNeeded(statements, node);
944
945            const savedCapturedSuperProperties = capturedSuperProperties;
946            const savedHasSuperElementAccess = hasSuperElementAccess;
947            capturedSuperProperties = new Set();
948            hasSuperElementAccess = false;
949
950            const returnStatement = factory.createReturnStatement(
951                emitHelpers().createAsyncGeneratorHelper(
952                    factory.createFunctionExpression(
953                        /*modifiers*/ undefined,
954                        factory.createToken(SyntaxKind.AsteriskToken),
955                        node.name && factory.getGeneratedNameForNode(node.name),
956                        /*typeParameters*/ undefined,
957                        /*parameters*/ [],
958                        /*type*/ undefined,
959                        factory.updateBlock(
960                            node.body!,
961                            visitLexicalEnvironment(node.body!.statements, visitor, context, statementOffset)
962                        )
963                    ),
964                    !!(hierarchyFacts & HierarchyFacts.HasLexicalThis)
965                )
966            );
967
968            // Minor optimization, emit `_super` helper to capture `super` access in an arrow.
969            // This step isn't needed if we eventually transform this to ES5.
970            const emitSuperHelpers = languageVersion >= ScriptTarget.ES2015 && resolver.getNodeCheckFlags(node) & (NodeCheckFlags.AsyncMethodWithSuperBinding | NodeCheckFlags.AsyncMethodWithSuper);
971
972            if (emitSuperHelpers) {
973                enableSubstitutionForAsyncMethodsWithSuper();
974                const variableStatement = createSuperAccessVariableStatement(factory, resolver, node, capturedSuperProperties);
975                substitutedSuperAccessors[getNodeId(variableStatement)] = true;
976                insertStatementsAfterStandardPrologue(statements, [variableStatement]);
977            }
978
979            statements.push(returnStatement);
980
981            insertStatementsAfterStandardPrologue(statements, endLexicalEnvironment());
982            const block = factory.updateBlock(node.body!, statements);
983
984            if (emitSuperHelpers && hasSuperElementAccess) {
985                if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.AsyncMethodWithSuperBinding) {
986                    addEmitHelper(block, advancedAsyncSuperHelper);
987                }
988                else if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.AsyncMethodWithSuper) {
989                    addEmitHelper(block, asyncSuperHelper);
990                }
991            }
992
993            capturedSuperProperties = savedCapturedSuperProperties;
994            hasSuperElementAccess = savedHasSuperElementAccess;
995
996            return block;
997        }
998
999        function transformFunctionBody(node: FunctionDeclaration | FunctionExpression | ConstructorDeclaration | MethodDeclaration | AccessorDeclaration): FunctionBody;
1000        function transformFunctionBody(node: ArrowFunction): ConciseBody;
1001        function transformFunctionBody(node: FunctionLikeDeclaration): ConciseBody {
1002            resumeLexicalEnvironment();
1003            let statementOffset = 0;
1004            const statements: Statement[] = [];
1005            const body = visitNode(node.body, visitor, isConciseBody) ?? factory.createBlock([]);
1006            if (isBlock(body)) {
1007                statementOffset = factory.copyPrologue(body.statements, statements, /*ensureUseStrict*/ false, visitor);
1008            }
1009            addRange(statements, appendObjectRestAssignmentsIfNeeded(/*statements*/ undefined, node));
1010            const leadingStatements = endLexicalEnvironment();
1011            if (statementOffset > 0 || some(statements) || some(leadingStatements)) {
1012                const block = factory.converters.convertToFunctionBlock(body, /*multiLine*/ true);
1013                insertStatementsAfterStandardPrologue(statements, leadingStatements);
1014                addRange(statements, block.statements.slice(statementOffset));
1015                return factory.updateBlock(block, setTextRange(factory.createNodeArray(statements), block.statements));
1016            }
1017            return body;
1018        }
1019
1020        function appendObjectRestAssignmentsIfNeeded(statements: Statement[] | undefined, node: FunctionLikeDeclaration): Statement[] | undefined {
1021            for (const parameter of node.parameters) {
1022                if (parameter.transformFlags & TransformFlags.ContainsObjectRestOrSpread) {
1023                    const temp = factory.getGeneratedNameForNode(parameter);
1024                    const declarations = flattenDestructuringBinding(
1025                        parameter,
1026                        visitor,
1027                        context,
1028                        FlattenLevel.ObjectRest,
1029                        temp,
1030                        /*doNotRecordTempVariablesInLine*/ false,
1031                        /*skipInitializer*/ true,
1032                    );
1033                    if (some(declarations)) {
1034                        const statement = factory.createVariableStatement(
1035                            /*modifiers*/ undefined,
1036                            factory.createVariableDeclarationList(
1037                                declarations
1038                            )
1039                        );
1040                        setEmitFlags(statement, EmitFlags.CustomPrologue);
1041                        statements = append(statements, statement);
1042                    }
1043                }
1044            }
1045            return statements;
1046        }
1047
1048        function enableSubstitutionForAsyncMethodsWithSuper() {
1049            if ((enabledSubstitutions & ESNextSubstitutionFlags.AsyncMethodsWithSuper) === 0) {
1050                enabledSubstitutions |= ESNextSubstitutionFlags.AsyncMethodsWithSuper;
1051
1052                // We need to enable substitutions for call, property access, and element access
1053                // if we need to rewrite super calls.
1054                context.enableSubstitution(SyntaxKind.CallExpression);
1055                context.enableSubstitution(SyntaxKind.PropertyAccessExpression);
1056                context.enableSubstitution(SyntaxKind.ElementAccessExpression);
1057
1058                // We need to be notified when entering and exiting declarations that bind super.
1059                context.enableEmitNotification(SyntaxKind.ClassDeclaration);
1060                context.enableEmitNotification(SyntaxKind.MethodDeclaration);
1061                context.enableEmitNotification(SyntaxKind.GetAccessor);
1062                context.enableEmitNotification(SyntaxKind.SetAccessor);
1063                context.enableEmitNotification(SyntaxKind.Constructor);
1064                // We need to be notified when entering the generated accessor arrow functions.
1065                context.enableEmitNotification(SyntaxKind.VariableStatement);
1066            }
1067        }
1068
1069        /**
1070         * Called by the printer just before a node is printed.
1071         *
1072         * @param hint A hint as to the intended usage of the node.
1073         * @param node The node to be printed.
1074         * @param emitCallback The callback used to emit the node.
1075         */
1076        function onEmitNode(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void) {
1077            // If we need to support substitutions for `super` in an async method,
1078            // we should track it here.
1079            if (enabledSubstitutions & ESNextSubstitutionFlags.AsyncMethodsWithSuper && isSuperContainer(node)) {
1080                const superContainerFlags = resolver.getNodeCheckFlags(node) & (NodeCheckFlags.AsyncMethodWithSuper | NodeCheckFlags.AsyncMethodWithSuperBinding);
1081                if (superContainerFlags !== enclosingSuperContainerFlags) {
1082                    const savedEnclosingSuperContainerFlags = enclosingSuperContainerFlags;
1083                    enclosingSuperContainerFlags = superContainerFlags;
1084                    previousOnEmitNode(hint, node, emitCallback);
1085                    enclosingSuperContainerFlags = savedEnclosingSuperContainerFlags;
1086                    return;
1087                }
1088            }
1089            // Disable substitution in the generated super accessor itself.
1090            else if (enabledSubstitutions && substitutedSuperAccessors[getNodeId(node)]) {
1091                const savedEnclosingSuperContainerFlags = enclosingSuperContainerFlags;
1092                enclosingSuperContainerFlags = 0 as NodeCheckFlags;
1093                previousOnEmitNode(hint, node, emitCallback);
1094                enclosingSuperContainerFlags = savedEnclosingSuperContainerFlags;
1095                return;
1096            }
1097
1098            previousOnEmitNode(hint, node, emitCallback);
1099        }
1100
1101        /**
1102         * Hooks node substitutions.
1103         *
1104         * @param hint The context for the emitter.
1105         * @param node The node to substitute.
1106         */
1107        function onSubstituteNode(hint: EmitHint, node: Node) {
1108            node = previousOnSubstituteNode(hint, node);
1109            if (hint === EmitHint.Expression && enclosingSuperContainerFlags) {
1110                return substituteExpression(<Expression>node);
1111            }
1112            return node;
1113        }
1114
1115        function substituteExpression(node: Expression) {
1116            switch (node.kind) {
1117                case SyntaxKind.PropertyAccessExpression:
1118                    return substitutePropertyAccessExpression(<PropertyAccessExpression>node);
1119                case SyntaxKind.ElementAccessExpression:
1120                    return substituteElementAccessExpression(<ElementAccessExpression>node);
1121                case SyntaxKind.CallExpression:
1122                    return substituteCallExpression(<CallExpression>node);
1123            }
1124            return node;
1125        }
1126
1127        function substitutePropertyAccessExpression(node: PropertyAccessExpression) {
1128            if (node.expression.kind === SyntaxKind.SuperKeyword) {
1129                return setTextRange(
1130                    factory.createPropertyAccessExpression(
1131                        factory.createUniqueName("_super", GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel),
1132                        node.name),
1133                    node
1134                );
1135            }
1136            return node;
1137        }
1138
1139        function substituteElementAccessExpression(node: ElementAccessExpression) {
1140            if (node.expression.kind === SyntaxKind.SuperKeyword) {
1141                return createSuperElementAccessInAsyncMethod(
1142                    node.argumentExpression,
1143                    node
1144                );
1145            }
1146            return node;
1147        }
1148
1149        function substituteCallExpression(node: CallExpression): Expression {
1150            const expression = node.expression;
1151            if (isSuperProperty(expression)) {
1152                const argumentExpression = isPropertyAccessExpression(expression)
1153                    ? substitutePropertyAccessExpression(expression)
1154                    : substituteElementAccessExpression(expression);
1155                return factory.createCallExpression(
1156                    factory.createPropertyAccessExpression(argumentExpression, "call"),
1157                    /*typeArguments*/ undefined,
1158                    [
1159                        factory.createThis(),
1160                        ...node.arguments
1161                    ]
1162                );
1163            }
1164            return node;
1165        }
1166
1167        function isSuperContainer(node: Node) {
1168            const kind = node.kind;
1169            return kind === SyntaxKind.ClassDeclaration
1170                || kind === SyntaxKind.Constructor
1171                || kind === SyntaxKind.MethodDeclaration
1172                || kind === SyntaxKind.GetAccessor
1173                || kind === SyntaxKind.SetAccessor;
1174        }
1175
1176        function createSuperElementAccessInAsyncMethod(argumentExpression: Expression, location: TextRange): LeftHandSideExpression {
1177            if (enclosingSuperContainerFlags & NodeCheckFlags.AsyncMethodWithSuperBinding) {
1178                return setTextRange(
1179                    factory.createPropertyAccessExpression(
1180                        factory.createCallExpression(
1181                            factory.createIdentifier("_superIndex"),
1182                            /*typeArguments*/ undefined,
1183                            [argumentExpression]
1184                        ),
1185                        "value"
1186                    ),
1187                    location
1188                );
1189            }
1190            else {
1191                return setTextRange(
1192                    factory.createCallExpression(
1193                        factory.createIdentifier("_superIndex"),
1194                        /*typeArguments*/ undefined,
1195                        [argumentExpression]
1196                    ),
1197                    location
1198                );
1199            }
1200        }
1201    }
1202}
1203