• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1import {
2    __String, AccessExpression, AnnotationDeclaration, AnnotationPropertyDeclaration, addRelatedInfo, append, appendIfUnique, ArrayBindingElement, ArrayLiteralExpression,
3    ArrowFunction, AssignmentDeclarationKind, BinaryExpression, BinaryOperatorToken, BindableAccessExpression,
4    BindableObjectDefinePropertyCall, BindablePropertyAssignmentExpression, BindableStaticAccessExpression,
5    BindableStaticNameExpression, BindableStaticPropertyAssignmentExpression, BindingElement, Block,
6    BreakOrContinueStatement, CallChain, CallExpression, CaseBlock, CaseClause, cast, CatchClause, ClassLikeDeclaration,
7    ClassStaticBlockDeclaration, CompilerOptions, concatenate, ConditionalExpression, ConditionalTypeNode, contains,
8    createBinaryExpressionTrampoline, createDiagnosticForNodeInSourceFile, createFileDiagnostic, createQueue,
9    createSymbolTable, Debug, Declaration, declarationNameToString, DeleteExpression, DestructuringAssignment,
10    DiagnosticCategory, DiagnosticMessage, DiagnosticRelatedInformation, Diagnostics, DiagnosticWithLocation,
11    DoStatement, DynamicNamedDeclaration, ElementAccessChain, ElementAccessExpression, EntityNameExpression,
12    EnumDeclaration, escapeLeadingUnderscores, ESMap, every, ExportAssignment, exportAssignmentIsAlias,
13    ExportDeclaration, ExportSpecifier, Expression, ExpressionStatement, findAncestor, FlowFlags, FlowLabel, FlowNode,
14    FlowReduceLabel, forEach, forEachChild, ForInOrOfStatement, ForStatement, FunctionDeclaration, FunctionExpression,
15    FunctionLikeDeclaration, GetAccessorDeclaration, getAssignedExpandoInitializer, getAssignmentDeclarationKind,
16    getAssignmentDeclarationPropertyAccessKind, getCombinedModifierFlags, getCombinedNodeFlags, getContainingClass,
17    getEffectiveContainerForJSDocTemplateTag, getElementOrPropertyAccessName, getEmitScriptTarget,
18    getEnclosingBlockScopeContainer, getErrorSpanForNode, getEscapedTextOfIdentifierOrLiteral, getExpandoInitializer,
19    getHostSignatureFromJSDoc, getImmediatelyInvokedFunctionExpression, getJSDocTypeTag, getLeftmostAccessExpression,
20    getNameOfDeclaration, getNameOrArgument, getNodeId, getRangesWhere, getRightMostAssignedExpression,
21    getSourceFileOfNode, getSourceTextOfNodeFromSourceFile, getSpanOfTokenAtPosition, getStrictOptionValue,
22    getSymbolNameForPrivateIdentifier, getTextOfIdentifierOrLiteral, getThisContainer, getTokenPosOfNode,
23    hasDynamicName, hasJSDocNodes, hasSyntacticModifier, Identifier, idText, IfStatement, ImportClause,
24    InternalSymbolName, isAliasableExpression, isAmbientModule, isAnnotationPropertyDeclaration, isAssignmentExpression, isAssignmentOperator,
25    isAssignmentTarget, isAsyncFunction, isAutoAccessorPropertyDeclaration, isBinaryExpression,
26    isBindableObjectDefinePropertyCall, isBindableStaticAccessExpression, isBindableStaticNameExpression,
27    isBindingPattern, isBlock, isBlockOrCatchScoped, isCallExpression, isClassStaticBlockDeclaration,
28    isConditionalTypeNode, isDeclaration, isDeclarationStatement, isDestructuringAssignment, isDottedName, isElementAccessExpression,
29    isEmptyObjectLiteral, isEntityNameExpression, isEnumConst, isEnumDeclaration,
30    isExportAssignment, isExportDeclaration, isExportsIdentifier, isExportSpecifier, isExpression,
31    isExpressionOfOptionalChainRoot, isExternalModule, isExternalOrCommonJsModule, isForInOrOfStatement,
32    isFunctionDeclaration, isFunctionLike, isFunctionLikeDeclaration, isFunctionLikeOrClassStaticBlockDeclaration,
33    isFunctionSymbol, isGlobalScopeAugmentation, isIdentifier, isIdentifierName, isInJSFile, isInTopLevelContext,
34    isJSDocConstructSignature, isJSDocEnumTag, isJSDocTemplateTag, isJSDocTypeAlias, isJsonSourceFile,
35    isLeftHandSideExpression, isLogicalOrCoalescingAssignmentOperator, isModuleAugmentationExternal, isModuleBlock,
36    isModuleDeclaration, isModuleExportsAccessExpression, isNamedDeclaration, isNamespaceExport, isNonNullExpression,
37    isNullishCoalesce, isObjectLiteralExpression, isObjectLiteralMethod,
38    isObjectLiteralOrClassExpressionMethodOrAccessor, isOmittedExpression, isOptionalChain, isOptionalChainRoot,
39    isOutermostOptionalChain, isParameterDeclaration, isParameterPropertyDeclaration, isParenthesizedExpression,
40    isPartOfTypeQuery, isPrefixUnaryExpression, isPrivateIdentifier, isPrologueDirective,
41    isPropertyAccessEntityNameExpression, isPropertyAccessExpression, isPropertyNameLiteral, isPrototypeAccess,
42    isPushOrUnshiftIdentifier, isRequireCall, isShorthandPropertyAssignment, isSignedNumericLiteral, isSourceFile,
43    isSpecialPropertyDeclaration, isStatement, isStatementButNotDeclaration, isStatic, isString, isStringLiteralLike,
44    isStringOrNumericLiteralLike, isThisInitializedDeclaration, isTypeAliasDeclaration, isTypeOfExpression,
45    isVariableDeclaration, isVariableDeclarationInitializedToBareOrAccessedRequire, isVariableStatement,
46    JSDocCallbackTag, JSDocClassTag, JSDocEnumTag, JSDocFunctionType, JSDocParameterTag, JSDocPropertyLikeTag,
47    JSDocSignature, JSDocTypedefTag, JSDocTypeLiteral, JsxAttribute, JsxAttributes, LabeledStatement, length,
48    LiteralLikeElementAccessExpression, Map, MappedTypeNode, MemoryDotting, MethodDeclaration, ModifierFlags,
49    ModuleBlock, ModuleDeclaration, Mutable, NamespaceExportDeclaration, Node, NodeArray, NodeFlags, nodeHasName,
50    nodeIsMissing, nodeIsPresent, NonNullChain, NonNullExpression, NumericLiteral, objectAllocator,
51    ObjectLiteralExpression, OptionalChain, ParameterDeclaration, ParenthesizedExpression, Pattern,
52    PatternAmbientModule, perfLogger, PerformanceDotting, PostfixUnaryExpression, PrefixUnaryExpression, PrivateIdentifier,
53    PropertyAccessChain, PropertyAccessExpression, PropertyDeclaration, PropertySignature, removeFileExtension,
54    ReturnStatement, ScriptTarget, Set, SetAccessorDeclaration, setParent, setParentRecursive, setValueDeclaration,
55    ShorthandPropertyAssignment, shouldPreserveConstEnums, SignatureDeclaration, skipParentheses, sliceAfter, some,
56    SourceFile, SpreadElement, Statement, StringLiteral, SwitchStatement, Symbol, SymbolFlags, symbolName, SymbolTable,
57    SyntaxKind, TextRange, ThrowStatement, TokenFlags, tokenToString, tracing, TracingNode, tryCast, tryParsePattern,
58    TryStatement, TypeLiteralNode, TypeOfExpression, TypeParameterDeclaration, unescapeLeadingUnderscores,
59    unreachableCodeIsError, unusedLabelIsError, VariableDeclaration, WhileStatement, WithStatement,
60} from "./_namespaces/ts";
61import * as performance from "./_namespaces/ts.performance";
62
63/** @internal */
64export const enum ModuleInstanceState {
65    NonInstantiated = 0,
66    Instantiated = 1,
67    ConstEnumOnly = 2
68}
69
70interface ActiveLabel {
71    next: ActiveLabel | undefined;
72    name: __String;
73    breakTarget: FlowLabel;
74    continueTarget: FlowLabel | undefined;
75    referenced: boolean;
76}
77
78/** @internal */
79export function getModuleInstanceState(node: ModuleDeclaration, visited?: ESMap<number, ModuleInstanceState | undefined>): ModuleInstanceState {
80    if (node.body && !node.body.parent) {
81        // getModuleInstanceStateForAliasTarget needs to walk up the parent chain, so parent pointers must be set on this tree already
82        setParent(node.body, node);
83        setParentRecursive(node.body, /*incremental*/ false);
84    }
85    return node.body ? getModuleInstanceStateCached(node.body, visited) : ModuleInstanceState.Instantiated;
86}
87
88function getModuleInstanceStateCached(node: Node, visited = new Map<number, ModuleInstanceState | undefined>()) {
89    const nodeId = getNodeId(node);
90    if (visited.has(nodeId)) {
91        return visited.get(nodeId) || ModuleInstanceState.NonInstantiated;
92    }
93    visited.set(nodeId, undefined);
94    const result = getModuleInstanceStateWorker(node, visited);
95    visited.set(nodeId, result);
96    return result;
97}
98
99function getModuleInstanceStateWorker(node: Node, visited: ESMap<number, ModuleInstanceState | undefined>): ModuleInstanceState {
100    // A module is uninstantiated if it contains only
101    switch (node.kind) {
102        // 1. interface declarations, type alias declarations
103        case SyntaxKind.InterfaceDeclaration:
104        case SyntaxKind.TypeAliasDeclaration:
105            return ModuleInstanceState.NonInstantiated;
106        // 2. const enum declarations
107        case SyntaxKind.EnumDeclaration:
108            if (isEnumConst(node as EnumDeclaration)) {
109                return ModuleInstanceState.ConstEnumOnly;
110            }
111            break;
112        // 3. non-exported import declarations
113        case SyntaxKind.ImportDeclaration:
114        case SyntaxKind.ImportEqualsDeclaration:
115            if (!(hasSyntacticModifier(node, ModifierFlags.Export))) {
116                return ModuleInstanceState.NonInstantiated;
117            }
118            break;
119        // 4. Export alias declarations pointing at only uninstantiated modules or things uninstantiated modules contain
120        case SyntaxKind.ExportDeclaration:
121            const exportDeclaration = node as ExportDeclaration;
122            if (!exportDeclaration.moduleSpecifier && exportDeclaration.exportClause && exportDeclaration.exportClause.kind === SyntaxKind.NamedExports) {
123                let state = ModuleInstanceState.NonInstantiated;
124                for (const specifier of exportDeclaration.exportClause.elements) {
125                    const specifierState = getModuleInstanceStateForAliasTarget(specifier, visited);
126                    if (specifierState > state) {
127                        state = specifierState;
128                    }
129                    if (state === ModuleInstanceState.Instantiated) {
130                        return state;
131                    }
132                }
133                return state;
134            }
135            break;
136        // 5. other uninstantiated module declarations.
137        case SyntaxKind.ModuleBlock: {
138            let state = ModuleInstanceState.NonInstantiated;
139            forEachChild(node, n => {
140                const childState = getModuleInstanceStateCached(n, visited);
141                switch (childState) {
142                    case ModuleInstanceState.NonInstantiated:
143                        // child is non-instantiated - continue searching
144                        return;
145                    case ModuleInstanceState.ConstEnumOnly:
146                        // child is const enum only - record state and continue searching
147                        state = ModuleInstanceState.ConstEnumOnly;
148                        return;
149                    case ModuleInstanceState.Instantiated:
150                        // child is instantiated - record state and stop
151                        state = ModuleInstanceState.Instantiated;
152                        return true;
153                    default:
154                        Debug.assertNever(childState);
155                }
156            });
157            return state;
158        }
159        case SyntaxKind.ModuleDeclaration:
160            return getModuleInstanceState(node as ModuleDeclaration, visited);
161        case SyntaxKind.Identifier:
162            // Only jsdoc typedef definition can exist in jsdoc namespace, and it should
163            // be considered the same as type alias
164            if ((node as Identifier).isInJSDocNamespace) {
165                return ModuleInstanceState.NonInstantiated;
166            }
167    }
168    return ModuleInstanceState.Instantiated;
169}
170
171function getModuleInstanceStateForAliasTarget(specifier: ExportSpecifier, visited: ESMap<number, ModuleInstanceState | undefined>) {
172    const name = specifier.propertyName || specifier.name;
173    let p: Node | undefined = specifier.parent;
174    while (p) {
175        if (isBlock(p) || isModuleBlock(p) || isSourceFile(p)) {
176            const statements = p.statements;
177            let found: ModuleInstanceState | undefined;
178            for (const statement of statements) {
179                if (nodeHasName(statement, name)) {
180                    if (!statement.parent) {
181                        setParent(statement, p);
182                        setParentRecursive(statement, /*incremental*/ false);
183                    }
184                    const state = getModuleInstanceStateCached(statement, visited);
185                    if (found === undefined || state > found) {
186                        found = state;
187                    }
188                    if (found === ModuleInstanceState.Instantiated) {
189                        return found;
190                    }
191                }
192            }
193            if (found !== undefined) {
194                return found;
195            }
196        }
197        p = p.parent;
198    }
199    return ModuleInstanceState.Instantiated; // Couldn't locate, assume could refer to a value
200}
201
202const enum ContainerFlags {
203    // The current node is not a container, and no container manipulation should happen before
204    // recursing into it.
205    None = 0,
206
207    // The current node is a container.  It should be set as the current container (and block-
208    // container) before recursing into it.  The current node does not have locals.  Examples:
209    //
210    //      Classes, ObjectLiterals, TypeLiterals, Interfaces...
211    IsContainer = 1 << 0,
212
213    // The current node is a block-scoped-container.  It should be set as the current block-
214    // container before recursing into it.  Examples:
215    //
216    //      Blocks (when not parented by functions), Catch clauses, For/For-in/For-of statements...
217    IsBlockScopedContainer = 1 << 1,
218
219    // The current node is the container of a control flow path. The current control flow should
220    // be saved and restored, and a new control flow initialized within the container.
221    IsControlFlowContainer = 1 << 2,
222
223    IsFunctionLike = 1 << 3,
224    IsFunctionExpression = 1 << 4,
225    HasLocals = 1 << 5,
226    IsInterface = 1 << 6,
227    IsObjectLiteralOrClassExpressionMethodOrAccessor = 1 << 7,
228}
229
230function initFlowNode<T extends FlowNode>(node: T) {
231    Debug.attachFlowNodeDebugInfo(node);
232    return node;
233}
234
235const binder = createBinder();
236
237/** @internal */
238export function bindSourceFile(file: SourceFile, options: CompilerOptions) {
239    const recordInfo = MemoryDotting.recordStage(MemoryDotting.BINDE_SOURCE_FILE);
240    performance.mark("beforeBind");
241    perfLogger.logStartBindFile("" + file.fileName);
242    binder(file, options);
243    perfLogger.logStopBindFile();
244    performance.mark("afterBind");
245    MemoryDotting.stopRecordStage(recordInfo);
246    performance.measure("Bind", "beforeBind", "afterBind");
247}
248
249function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
250    /* eslint-disable no-var */
251    var file: SourceFile;
252    var options: CompilerOptions;
253    var languageVersion: ScriptTarget;
254    var parent: Node;
255    var container: Node;
256    var thisParentContainer: Node; // Container one level up
257    var blockScopeContainer: Node;
258    var lastContainer: Node;
259    var delayedTypeAliases: (JSDocTypedefTag | JSDocCallbackTag | JSDocEnumTag)[];
260    var seenThisKeyword: boolean;
261
262    // state used by control flow analysis
263    var currentFlow: FlowNode;
264    var currentBreakTarget: FlowLabel | undefined;
265    var currentContinueTarget: FlowLabel | undefined;
266    var currentReturnTarget: FlowLabel | undefined;
267    var currentTrueTarget: FlowLabel | undefined;
268    var currentFalseTarget: FlowLabel | undefined;
269    var currentExceptionTarget: FlowLabel | undefined;
270    var preSwitchCaseFlow: FlowNode | undefined;
271    var activeLabelList: ActiveLabel | undefined;
272    var hasExplicitReturn: boolean;
273
274    // state used for emit helpers
275    var emitFlags: NodeFlags;
276
277    // If this file is an external module, then it is automatically in strict-mode according to
278    // ES6.  If it is not an external module, then we'll determine if it is in strict mode or
279    // not depending on if we see "use strict" in certain places or if we hit a class/namespace
280    // or if compiler options contain alwaysStrict.
281    var inStrictMode: boolean;
282
283    // If we are binding an assignment pattern, we will bind certain expressions differently.
284    var inAssignmentPattern = false;
285
286    var symbolCount = 0;
287
288    var Symbol: new (flags: SymbolFlags, name: __String) => Symbol;
289    var classifiableNames: Set<__String>;
290
291    var unreachableFlow: FlowNode = { flags: FlowFlags.Unreachable };
292    var reportedUnreachableFlow: FlowNode = { flags: FlowFlags.Unreachable };
293    var bindBinaryExpressionFlow = createBindBinaryExpressionFlow();
294    /* eslint-enable no-var */
295
296    return bindSourceFile;
297
298    /**
299     * Inside the binder, we may create a diagnostic for an as-yet unbound node (with potentially no parent pointers, implying no accessible source file)
300     * If so, the node _must_ be in the current file (as that's the only way anything could have traversed to it to yield it as the error node)
301     * This version of `createDiagnosticForNode` uses the binder's context to account for this, and always yields correct diagnostics even in these situations.
302     */
303    function createDiagnosticForNode(node: Node, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number): DiagnosticWithLocation {
304        return createDiagnosticForNodeInSourceFile(getSourceFileOfNode(node) || file, node, message, arg0, arg1, arg2);
305    }
306
307    function bindSourceFile(f: SourceFile, opts: CompilerOptions) {
308        file = f;
309        options = opts;
310        languageVersion = getEmitScriptTarget(options);
311        inStrictMode = bindInStrictMode(file, opts);
312        classifiableNames = new Set();
313        symbolCount = 0;
314
315        Symbol = objectAllocator.getSymbolConstructor();
316
317        // Attach debugging information if necessary
318        Debug.attachFlowNodeDebugInfo(unreachableFlow);
319        Debug.attachFlowNodeDebugInfo(reportedUnreachableFlow);
320
321        if (!file.locals) {
322            tracing?.push(tracing.Phase.Bind, "bindSourceFile", { path: file.path }, /*separateBeginAndEnd*/ true);
323            PerformanceDotting.start("bindSourceFile", file.fileName);
324            bind(file);
325            PerformanceDotting.stop("bindSourceFile");
326            tracing?.pop();
327            file.symbolCount = symbolCount;
328            file.classifiableNames = classifiableNames;
329            delayedBindJSDocTypedefTag();
330        }
331
332        file = undefined!;
333        options = undefined!;
334        languageVersion = undefined!;
335        parent = undefined!;
336        container = undefined!;
337        thisParentContainer = undefined!;
338        blockScopeContainer = undefined!;
339        lastContainer = undefined!;
340        delayedTypeAliases = undefined!;
341        seenThisKeyword = false;
342        currentFlow = undefined!;
343        currentBreakTarget = undefined;
344        currentContinueTarget = undefined;
345        currentReturnTarget = undefined;
346        currentTrueTarget = undefined;
347        currentFalseTarget = undefined;
348        currentExceptionTarget = undefined;
349        activeLabelList = undefined;
350        hasExplicitReturn = false;
351        inAssignmentPattern = false;
352        emitFlags = NodeFlags.None;
353    }
354
355    function bindInStrictMode(file: SourceFile, opts: CompilerOptions): boolean {
356        if (getStrictOptionValue(opts, "alwaysStrict") && !file.isDeclarationFile) {
357            // bind in strict mode source files with alwaysStrict option
358            return true;
359        }
360        else {
361            return !!file.externalModuleIndicator;
362        }
363    }
364
365    function createSymbol(flags: SymbolFlags, name: __String): Symbol {
366        symbolCount++;
367        return new Symbol(flags, name);
368    }
369
370    function addDeclarationToSymbol(symbol: Symbol, node: Declaration, symbolFlags: SymbolFlags) {
371        symbol.flags |= symbolFlags;
372
373        node.symbol = symbol;
374        symbol.declarations = appendIfUnique(symbol.declarations, node);
375
376        if (symbolFlags & (SymbolFlags.Class | SymbolFlags.Enum | SymbolFlags.Module | SymbolFlags.Variable) && !symbol.exports) {
377            symbol.exports = createSymbolTable();
378        }
379
380        if (symbolFlags & (SymbolFlags.Class | SymbolFlags.Interface | SymbolFlags.TypeLiteral | SymbolFlags.ObjectLiteral) && !symbol.members) {
381            symbol.members = createSymbolTable();
382        }
383
384        // On merge of const enum module with class or function, reset const enum only flag (namespaces will already recalculate)
385        if (symbol.constEnumOnlyModule && (symbol.flags & (SymbolFlags.Function | SymbolFlags.Class | SymbolFlags.RegularEnum))) {
386            symbol.constEnumOnlyModule = false;
387        }
388
389        if (symbolFlags & SymbolFlags.Value) {
390            setValueDeclaration(symbol, node);
391        }
392    }
393
394    // Should not be called on a declaration with a computed property name,
395    // unless it is a well known Symbol.
396    function getDeclarationName(node: Declaration): __String | undefined {
397        if (node.kind === SyntaxKind.ExportAssignment) {
398            return (node as ExportAssignment).isExportEquals ? InternalSymbolName.ExportEquals : InternalSymbolName.Default;
399        }
400
401        const name = getNameOfDeclaration(node);
402        if (name) {
403            if (isAmbientModule(node)) {
404                const moduleName = getTextOfIdentifierOrLiteral(name as Identifier | StringLiteral);
405                return (isGlobalScopeAugmentation(node as ModuleDeclaration) ? "__global" : `"${moduleName}"`) as __String;
406            }
407            if (name.kind === SyntaxKind.ComputedPropertyName) {
408                const nameExpression = name.expression;
409                // treat computed property names where expression is string/numeric literal as just string/numeric literal
410                if (isStringOrNumericLiteralLike(nameExpression)) {
411                    return escapeLeadingUnderscores(nameExpression.text);
412                }
413                if (isSignedNumericLiteral(nameExpression)) {
414                    return tokenToString(nameExpression.operator) + nameExpression.operand.text as __String;
415                }
416                else {
417                    Debug.fail("Only computed properties with literal names have declaration names");
418                }
419            }
420            if (isPrivateIdentifier(name)) {
421                // containingClass exists because private names only allowed inside classes
422                const containingClass = getContainingClass(node);
423                if (!containingClass) {
424                    // we can get here in cases where there is already a parse error.
425                    return undefined;
426                }
427                const containingClassSymbol = containingClass.symbol;
428                return getSymbolNameForPrivateIdentifier(containingClassSymbol, name.escapedText);
429            }
430            return isPropertyNameLiteral(name) ? getEscapedTextOfIdentifierOrLiteral(name) : undefined;
431        }
432        switch (node.kind) {
433            case SyntaxKind.Constructor:
434                return InternalSymbolName.Constructor;
435            case SyntaxKind.FunctionType:
436            case SyntaxKind.CallSignature:
437            case SyntaxKind.JSDocSignature:
438                return InternalSymbolName.Call;
439            case SyntaxKind.ConstructorType:
440            case SyntaxKind.ConstructSignature:
441                return InternalSymbolName.New;
442            case SyntaxKind.IndexSignature:
443                return InternalSymbolName.Index;
444            case SyntaxKind.ExportDeclaration:
445                return InternalSymbolName.ExportStar;
446            case SyntaxKind.SourceFile:
447                // json file should behave as
448                // module.exports = ...
449                return InternalSymbolName.ExportEquals;
450            case SyntaxKind.BinaryExpression:
451                if (getAssignmentDeclarationKind(node as BinaryExpression) === AssignmentDeclarationKind.ModuleExports) {
452                    // module.exports = ...
453                    return InternalSymbolName.ExportEquals;
454                }
455                Debug.fail("Unknown binary declaration kind");
456            case SyntaxKind.JSDocFunctionType:
457                return (isJSDocConstructSignature(node) ? InternalSymbolName.New : InternalSymbolName.Call);
458            case SyntaxKind.Parameter:
459                // Parameters with names are handled at the top of this function.  Parameters
460                // without names can only come from JSDocFunctionTypes.
461                Debug.assert(node.parent.kind === SyntaxKind.JSDocFunctionType, "Impossible parameter parent kind", () => `parent is: ${Debug.formatSyntaxKind(node.parent.kind)}, expected JSDocFunctionType`);
462                const functionType = node.parent as JSDocFunctionType;
463                const index = functionType.parameters.indexOf(node as ParameterDeclaration);
464                return "arg" + index as __String;
465        }
466    }
467
468    function getDisplayName(node: Declaration): string {
469        return isNamedDeclaration(node) ? declarationNameToString(node.name) : unescapeLeadingUnderscores(Debug.checkDefined(getDeclarationName(node)));
470    }
471
472    /**
473     * Declares a Symbol for the node and adds it to symbols. Reports errors for conflicting identifier names.
474     * @param symbolTable - The symbol table which node will be added to.
475     * @param parent - node's parent declaration.
476     * @param node - The declaration to be added to the symbol table
477     * @param includes - The SymbolFlags that node has in addition to its declaration type (eg: export, ambient, etc.)
478     * @param excludes - The flags which node cannot be declared alongside in a symbol table. Used to report forbidden declarations.
479     */
480    function declareSymbol(symbolTable: SymbolTable, parent: Symbol | undefined, node: Declaration, includes: SymbolFlags, excludes: SymbolFlags, isReplaceableByMethod?: boolean, isComputedName?: boolean): Symbol {
481        Debug.assert(isComputedName || !hasDynamicName(node));
482
483        const isDefaultExport = hasSyntacticModifier(node, ModifierFlags.Default) || isExportSpecifier(node) && node.name.escapedText === "default";
484
485        // The exported symbol for an export default function/class node is always named "default"
486        const name = isComputedName ? InternalSymbolName.Computed
487            : isDefaultExport && parent ? InternalSymbolName.Default
488            : getDeclarationName(node);
489
490        let symbol: Symbol | undefined;
491        if (name === undefined) {
492            symbol = createSymbol(SymbolFlags.None, InternalSymbolName.Missing);
493        }
494        else {
495            // Check and see if the symbol table already has a symbol with this name.  If not,
496            // create a new symbol with this name and add it to the table.  Note that we don't
497            // give the new symbol any flags *yet*.  This ensures that it will not conflict
498            // with the 'excludes' flags we pass in.
499            //
500            // If we do get an existing symbol, see if it conflicts with the new symbol we're
501            // creating.  For example, a 'var' symbol and a 'class' symbol will conflict within
502            // the same symbol table.  If we have a conflict, report the issue on each
503            // declaration we have for this symbol, and then create a new symbol for this
504            // declaration.
505            //
506            // Note that when properties declared in Javascript constructors
507            // (marked by isReplaceableByMethod) conflict with another symbol, the property loses.
508            // Always. This allows the common Javascript pattern of overwriting a prototype method
509            // with an bound instance method of the same type: `this.method = this.method.bind(this)`
510            //
511            // If we created a new symbol, either because we didn't have a symbol with this name
512            // in the symbol table, or we conflicted with an existing symbol, then just add this
513            // node as the sole declaration of the new symbol.
514            //
515            // Otherwise, we'll be merging into a compatible existing symbol (for example when
516            // you have multiple 'vars' with the same name in the same container).  In this case
517            // just add this node into the declarations list of the symbol.
518            symbol = symbolTable.get(name);
519
520            if (includes & SymbolFlags.Classifiable) {
521                classifiableNames.add(name);
522            }
523
524            if (!symbol) {
525                symbolTable.set(name, symbol = createSymbol(SymbolFlags.None, name));
526                if (isReplaceableByMethod) symbol.isReplaceableByMethod = true;
527            }
528            else if (isReplaceableByMethod && !symbol.isReplaceableByMethod) {
529                // A symbol already exists, so don't add this as a declaration.
530                return symbol;
531            }
532            else if (symbol.flags & excludes) {
533                if (symbol.isReplaceableByMethod) {
534                    // Javascript constructor-declared symbols can be discarded in favor of
535                    // prototype symbols like methods.
536                    symbolTable.set(name, symbol = createSymbol(SymbolFlags.None, name));
537                }
538                else if (!(includes & SymbolFlags.Variable && symbol.flags & SymbolFlags.Assignment)) {
539                    // Assignment declarations are allowed to merge with variables, no matter what other flags they have.
540                    if (isNamedDeclaration(node)) {
541                        setParent(node.name, node);
542                    }
543                    // Report errors every position with duplicate declaration
544                    // Report errors on previous encountered declarations
545                    let message = symbol.flags & SymbolFlags.BlockScopedVariable
546                        ? Diagnostics.Cannot_redeclare_block_scoped_variable_0
547                        : Diagnostics.Duplicate_identifier_0;
548                    let messageNeedsName = true;
549
550                    if (symbol.flags & SymbolFlags.Enum || includes & SymbolFlags.Enum) {
551                        message = Diagnostics.Enum_declarations_can_only_merge_with_namespace_or_other_enum_declarations;
552                        messageNeedsName = false;
553                    }
554
555                    let multipleDefaultExports = false;
556                    if (length(symbol.declarations)) {
557                        // If the current node is a default export of some sort, then check if
558                        // there are any other default exports that we need to error on.
559                        // We'll know whether we have other default exports depending on if `symbol` already has a declaration list set.
560                        if (isDefaultExport) {
561                            message = Diagnostics.A_module_cannot_have_multiple_default_exports;
562                            messageNeedsName = false;
563                            multipleDefaultExports = true;
564                        }
565                        else {
566                            // This is to properly report an error in the case "export default { }" is after export default of class declaration or function declaration.
567                            // Error on multiple export default in the following case:
568                            // 1. multiple export default of class declaration or function declaration by checking NodeFlags.Default
569                            // 2. multiple export default of export assignment. This one doesn't have NodeFlags.Default on (as export default doesn't considered as modifiers)
570                            if (symbol.declarations && symbol.declarations.length &&
571                                (node.kind === SyntaxKind.ExportAssignment && !(node as ExportAssignment).isExportEquals)) {
572                                message = Diagnostics.A_module_cannot_have_multiple_default_exports;
573                                messageNeedsName = false;
574                                multipleDefaultExports = true;
575                            }
576                        }
577                    }
578
579                    const relatedInformation: DiagnosticRelatedInformation[] = [];
580                    if (isTypeAliasDeclaration(node) && nodeIsMissing(node.type) && hasSyntacticModifier(node, ModifierFlags.Export) && symbol.flags & (SymbolFlags.Alias | SymbolFlags.Type | SymbolFlags.Namespace)) {
581                        // export type T; - may have meant export type { T }?
582                        relatedInformation.push(createDiagnosticForNode(node, Diagnostics.Did_you_mean_0, `export type { ${unescapeLeadingUnderscores(node.name.escapedText)} }`));
583                    }
584
585                    const declarationName = getNameOfDeclaration(node) || node;
586                    forEach(symbol.declarations, (declaration, index) => {
587                        const decl = getNameOfDeclaration(declaration) || declaration;
588                        const diag = createDiagnosticForNode(decl, message, messageNeedsName ? getDisplayName(declaration) : undefined);
589                        file.bindDiagnostics.push(
590                            multipleDefaultExports ? addRelatedInfo(diag, createDiagnosticForNode(declarationName, index === 0 ? Diagnostics.Another_export_default_is_here : Diagnostics.and_here)) : diag
591                        );
592                        if (multipleDefaultExports) {
593                            relatedInformation.push(createDiagnosticForNode(decl, Diagnostics.The_first_export_default_is_here));
594                        }
595                    });
596
597                    const diag = createDiagnosticForNode(declarationName, message, messageNeedsName ? getDisplayName(node) : undefined);
598                    file.bindDiagnostics.push(addRelatedInfo(diag, ...relatedInformation));
599
600                    symbol = createSymbol(SymbolFlags.None, name);
601                }
602            }
603        }
604
605        addDeclarationToSymbol(symbol, node, includes);
606        if (symbol.parent) {
607            Debug.assert(symbol.parent === parent, "Existing symbol parent should match new one");
608        }
609        else {
610            symbol.parent = parent;
611        }
612
613        return symbol;
614    }
615
616    function declareModuleMember(node: Declaration, symbolFlags: SymbolFlags, symbolExcludes: SymbolFlags): Symbol {
617        const hasExportModifier = !!(getCombinedModifierFlags(node) & ModifierFlags.Export) || jsdocTreatAsExported(node);
618        if (symbolFlags & SymbolFlags.Alias) {
619            if (node.kind === SyntaxKind.ExportSpecifier || (node.kind === SyntaxKind.ImportEqualsDeclaration && hasExportModifier)) {
620                return declareSymbol(container.symbol.exports!, container.symbol, node, symbolFlags, symbolExcludes);
621            }
622            else {
623                return declareSymbol(container.locals!, /*parent*/ undefined, node, symbolFlags, symbolExcludes);
624            }
625        }
626        else {
627            // Exported module members are given 2 symbols: A local symbol that is classified with an ExportValue flag,
628            // and an associated export symbol with all the correct flags set on it. There are 2 main reasons:
629            //
630            //   1. We treat locals and exports of the same name as mutually exclusive within a container.
631            //      That means the binder will issue a Duplicate Identifier error if you mix locals and exports
632            //      with the same name in the same container.
633            //      TODO: Make this a more specific error and decouple it from the exclusion logic.
634            //   2. When we checkIdentifier in the checker, we set its resolved symbol to the local symbol,
635            //      but return the export symbol (by calling getExportSymbolOfValueSymbolIfExported). That way
636            //      when the emitter comes back to it, it knows not to qualify the name if it was found in a containing scope.
637
638            // NOTE: Nested ambient modules always should go to to 'locals' table to prevent their automatic merge
639            //       during global merging in the checker. Why? The only case when ambient module is permitted inside another module is module augmentation
640            //       and this case is specially handled. Module augmentations should only be merged with original module definition
641            //       and should never be merged directly with other augmentation, and the latter case would be possible if automatic merge is allowed.
642            if (isJSDocTypeAlias(node)) Debug.assert(isInJSFile(node)); // We shouldn't add symbols for JSDoc nodes if not in a JS file.
643            if (!isAmbientModule(node) && (hasExportModifier || container.flags & NodeFlags.ExportContext)) {
644                if (!container.locals || (hasSyntacticModifier(node, ModifierFlags.Default) && !getDeclarationName(node))) {
645                    return declareSymbol(container.symbol.exports!, container.symbol, node, symbolFlags, symbolExcludes); // No local symbol for an unnamed default!
646                }
647                const exportKind = symbolFlags & SymbolFlags.Value ? SymbolFlags.ExportValue : 0;
648                const local = declareSymbol(container.locals, /*parent*/ undefined, node, exportKind, symbolExcludes);
649                local.exportSymbol = declareSymbol(container.symbol.exports!, container.symbol, node, symbolFlags, symbolExcludes);
650                node.localSymbol = local;
651                return local;
652            }
653            else {
654                return declareSymbol(container.locals!, /*parent*/ undefined, node, symbolFlags, symbolExcludes);
655            }
656        }
657    }
658
659    function jsdocTreatAsExported(node: Node) {
660        if (node.parent && isModuleDeclaration(node)) {
661            node = node.parent;
662        }
663        if (!isJSDocTypeAlias(node)) return false;
664        // jsdoc typedef handling is a bit of a doozy, but to summarize, treat the typedef as exported if:
665        // 1. It has an explicit name (since by default typedefs are always directly exported, either at the top level or in a container), or
666        if (!isJSDocEnumTag(node) && !!node.fullName) return true;
667        // 2. The thing a nameless typedef pulls its name from is implicitly a direct export (either by assignment or actual export flag).
668        const declName = getNameOfDeclaration(node);
669        if (!declName) return false;
670        if (isPropertyAccessEntityNameExpression(declName.parent) && isTopLevelNamespaceAssignment(declName.parent)) return true;
671        if (isDeclaration(declName.parent) && getCombinedModifierFlags(declName.parent) & ModifierFlags.Export) return true;
672        // This could potentially be simplified by having `delayedBindJSDocTypedefTag` pass in an override for `hasExportModifier`, since it should
673        // already have calculated and branched on most of this.
674        return false;
675    }
676
677    // All container nodes are kept on a linked list in declaration order. This list is used by
678    // the getLocalNameOfContainer function in the type checker to validate that the local name
679    // used for a container is unique.
680    function bindContainer(node: Mutable<Node>, containerFlags: ContainerFlags) {
681        // Before we recurse into a node's children, we first save the existing parent, container
682        // and block-container.  Then after we pop out of processing the children, we restore
683        // these saved values.
684        const saveContainer = container;
685        const saveThisParentContainer = thisParentContainer;
686        const savedBlockScopeContainer = blockScopeContainer;
687
688        // Depending on what kind of node this is, we may have to adjust the current container
689        // and block-container.   If the current node is a container, then it is automatically
690        // considered the current block-container as well.  Also, for containers that we know
691        // may contain locals, we eagerly initialize the .locals field. We do this because
692        // it's highly likely that the .locals will be needed to place some child in (for example,
693        // a parameter, or variable declaration).
694        //
695        // However, we do not proactively create the .locals for block-containers because it's
696        // totally normal and common for block-containers to never actually have a block-scoped
697        // variable in them.  We don't want to end up allocating an object for every 'block' we
698        // run into when most of them won't be necessary.
699        //
700        // Finally, if this is a block-container, then we clear out any existing .locals object
701        // it may contain within it.  This happens in incremental scenarios.  Because we can be
702        // reusing a node from a previous compilation, that node may have had 'locals' created
703        // for it.  We must clear this so we don't accidentally move any stale data forward from
704        // a previous compilation.
705        if (containerFlags & ContainerFlags.IsContainer) {
706            if (node.kind !== SyntaxKind.ArrowFunction) {
707                thisParentContainer = container;
708            }
709            container = blockScopeContainer = node;
710            if (containerFlags & ContainerFlags.HasLocals) {
711                container.locals = createSymbolTable();
712            }
713            addToContainerChain(container);
714        }
715        else if (containerFlags & ContainerFlags.IsBlockScopedContainer) {
716            blockScopeContainer = node;
717            blockScopeContainer.locals = undefined;
718        }
719        if (containerFlags & ContainerFlags.IsControlFlowContainer) {
720            const saveCurrentFlow = currentFlow;
721            const saveBreakTarget = currentBreakTarget;
722            const saveContinueTarget = currentContinueTarget;
723            const saveReturnTarget = currentReturnTarget;
724            const saveExceptionTarget = currentExceptionTarget;
725            const saveActiveLabelList = activeLabelList;
726            const saveHasExplicitReturn = hasExplicitReturn;
727            const isImmediatelyInvoked =
728                (containerFlags & ContainerFlags.IsFunctionExpression &&
729                    !hasSyntacticModifier(node, ModifierFlags.Async) &&
730                    !(node as FunctionLikeDeclaration).asteriskToken &&
731                    !!getImmediatelyInvokedFunctionExpression(node)) ||
732                node.kind === SyntaxKind.ClassStaticBlockDeclaration;
733            // A non-async, non-generator IIFE is considered part of the containing control flow. Return statements behave
734            // similarly to break statements that exit to a label just past the statement body.
735            if (!isImmediatelyInvoked) {
736                currentFlow = initFlowNode({ flags: FlowFlags.Start });
737                if (containerFlags & (ContainerFlags.IsFunctionExpression | ContainerFlags.IsObjectLiteralOrClassExpressionMethodOrAccessor)) {
738                    currentFlow.node = node as FunctionExpression | ArrowFunction | MethodDeclaration | GetAccessorDeclaration | SetAccessorDeclaration;
739                }
740            }
741            // We create a return control flow graph for IIFEs and constructors. For constructors
742            // we use the return control flow graph in strict property initialization checks.
743            currentReturnTarget = isImmediatelyInvoked || node.kind === SyntaxKind.Constructor || (isInJSFile(node) && (node.kind === SyntaxKind.FunctionDeclaration || node.kind === SyntaxKind.FunctionExpression)) ? createBranchLabel() : undefined;
744            currentExceptionTarget = undefined;
745            currentBreakTarget = undefined;
746            currentContinueTarget = undefined;
747            activeLabelList = undefined;
748            hasExplicitReturn = false;
749            bindChildren(node);
750            // Reset all reachability check related flags on node (for incremental scenarios)
751            node.flags &= ~NodeFlags.ReachabilityAndEmitFlags;
752            if (!(currentFlow.flags & FlowFlags.Unreachable) && containerFlags & ContainerFlags.IsFunctionLike && nodeIsPresent((node as FunctionLikeDeclaration | ClassStaticBlockDeclaration).body)) {
753                node.flags |= NodeFlags.HasImplicitReturn;
754                if (hasExplicitReturn) node.flags |= NodeFlags.HasExplicitReturn;
755                (node as FunctionLikeDeclaration | ClassStaticBlockDeclaration).endFlowNode = currentFlow;
756            }
757            if (node.kind === SyntaxKind.SourceFile) {
758                node.flags |= emitFlags;
759                (node as SourceFile).endFlowNode = currentFlow;
760            }
761
762            if (currentReturnTarget) {
763                addAntecedent(currentReturnTarget, currentFlow);
764                currentFlow = finishFlowLabel(currentReturnTarget);
765                if (node.kind === SyntaxKind.Constructor || node.kind === SyntaxKind.ClassStaticBlockDeclaration || (isInJSFile(node) && (node.kind === SyntaxKind.FunctionDeclaration || node.kind === SyntaxKind.FunctionExpression))) {
766                    (node as FunctionLikeDeclaration | ClassStaticBlockDeclaration).returnFlowNode = currentFlow;
767                }
768            }
769            if (!isImmediatelyInvoked) {
770                currentFlow = saveCurrentFlow;
771            }
772            currentBreakTarget = saveBreakTarget;
773            currentContinueTarget = saveContinueTarget;
774            currentReturnTarget = saveReturnTarget;
775            currentExceptionTarget = saveExceptionTarget;
776            activeLabelList = saveActiveLabelList;
777            hasExplicitReturn = saveHasExplicitReturn;
778        }
779        else if (containerFlags & ContainerFlags.IsInterface) {
780            seenThisKeyword = false;
781            bindChildren(node);
782            node.flags = seenThisKeyword ? node.flags | NodeFlags.ContainsThis : node.flags & ~NodeFlags.ContainsThis;
783        }
784        else {
785            bindChildren(node);
786        }
787
788        container = saveContainer;
789        thisParentContainer = saveThisParentContainer;
790        blockScopeContainer = savedBlockScopeContainer;
791    }
792
793    function bindEachFunctionsFirst(nodes: NodeArray<Node> | undefined): void {
794        bindEach(nodes, n => n.kind === SyntaxKind.FunctionDeclaration ? bind(n) : undefined);
795        bindEach(nodes, n => n.kind !== SyntaxKind.FunctionDeclaration ? bind(n) : undefined);
796    }
797
798    function bindEach(nodes: NodeArray<Node> | undefined, bindFunction: (node: Node) => void = bind): void {
799        if (nodes === undefined) {
800            return;
801        }
802
803        forEach(nodes, bindFunction);
804    }
805
806    function bindEachChild(node: Node) {
807        forEachChild(node, bind, bindEach);
808    }
809
810    function bindChildren(node: Node): void {
811        const saveInAssignmentPattern = inAssignmentPattern;
812        // Most nodes aren't valid in an assignment pattern, so we clear the value here
813        // and set it before we descend into nodes that could actually be part of an assignment pattern.
814        inAssignmentPattern = false;
815        if (checkUnreachable(node)) {
816            bindEachChild(node);
817            bindJSDoc(node);
818            inAssignmentPattern = saveInAssignmentPattern;
819            return;
820        }
821        if (node.kind >= SyntaxKind.FirstStatement && node.kind <= SyntaxKind.LastStatement && !options.allowUnreachableCode) {
822            node.flowNode = currentFlow;
823        }
824        switch (node.kind) {
825            case SyntaxKind.WhileStatement:
826                bindWhileStatement(node as WhileStatement);
827                break;
828            case SyntaxKind.DoStatement:
829                bindDoStatement(node as DoStatement);
830                break;
831            case SyntaxKind.ForStatement:
832                bindForStatement(node as ForStatement);
833                break;
834            case SyntaxKind.ForInStatement:
835            case SyntaxKind.ForOfStatement:
836                bindForInOrForOfStatement(node as ForInOrOfStatement);
837                break;
838            case SyntaxKind.IfStatement:
839                bindIfStatement(node as IfStatement);
840                break;
841            case SyntaxKind.ReturnStatement:
842            case SyntaxKind.ThrowStatement:
843                bindReturnOrThrow(node as ReturnStatement | ThrowStatement);
844                break;
845            case SyntaxKind.BreakStatement:
846            case SyntaxKind.ContinueStatement:
847                bindBreakOrContinueStatement(node as BreakOrContinueStatement);
848                break;
849            case SyntaxKind.TryStatement:
850                bindTryStatement(node as TryStatement);
851                break;
852            case SyntaxKind.SwitchStatement:
853                bindSwitchStatement(node as SwitchStatement);
854                break;
855            case SyntaxKind.CaseBlock:
856                bindCaseBlock(node as CaseBlock);
857                break;
858            case SyntaxKind.CaseClause:
859                bindCaseClause(node as CaseClause);
860                break;
861            case SyntaxKind.ExpressionStatement:
862                bindExpressionStatement(node as ExpressionStatement);
863                break;
864            case SyntaxKind.LabeledStatement:
865                bindLabeledStatement(node as LabeledStatement);
866                break;
867            case SyntaxKind.PrefixUnaryExpression:
868                bindPrefixUnaryExpressionFlow(node as PrefixUnaryExpression);
869                break;
870            case SyntaxKind.PostfixUnaryExpression:
871                bindPostfixUnaryExpressionFlow(node as PostfixUnaryExpression);
872                break;
873            case SyntaxKind.BinaryExpression:
874                if (isDestructuringAssignment(node)) {
875                    // Carry over whether we are in an assignment pattern to
876                    // binary expressions that could actually be an initializer
877                    inAssignmentPattern = saveInAssignmentPattern;
878                    bindDestructuringAssignmentFlow(node);
879                    return;
880                }
881                bindBinaryExpressionFlow(node as BinaryExpression);
882                break;
883            case SyntaxKind.DeleteExpression:
884                bindDeleteExpressionFlow(node as DeleteExpression);
885                break;
886            case SyntaxKind.ConditionalExpression:
887                bindConditionalExpressionFlow(node as ConditionalExpression);
888                break;
889            case SyntaxKind.VariableDeclaration:
890                bindVariableDeclarationFlow(node as VariableDeclaration);
891                break;
892            case SyntaxKind.PropertyAccessExpression:
893            case SyntaxKind.ElementAccessExpression:
894                bindAccessExpressionFlow(node as AccessExpression);
895                break;
896            case SyntaxKind.CallExpression:
897                bindCallExpressionFlow(node as CallExpression);
898                break;
899            case SyntaxKind.NonNullExpression:
900                bindNonNullExpressionFlow(node as NonNullExpression);
901                break;
902            case SyntaxKind.JSDocTypedefTag:
903            case SyntaxKind.JSDocCallbackTag:
904            case SyntaxKind.JSDocEnumTag:
905                bindJSDocTypeAlias(node as JSDocTypedefTag | JSDocCallbackTag | JSDocEnumTag);
906                break;
907            // In source files and blocks, bind functions first to match hoisting that occurs at runtime
908            case SyntaxKind.SourceFile: {
909                bindEachFunctionsFirst((node as SourceFile).statements);
910                bind((node as SourceFile).endOfFileToken);
911                break;
912            }
913            case SyntaxKind.Block:
914            case SyntaxKind.ModuleBlock:
915                bindEachFunctionsFirst((node as Block).statements);
916                break;
917            case SyntaxKind.BindingElement:
918                bindBindingElementFlow(node as BindingElement);
919                break;
920            case SyntaxKind.Parameter:
921                bindParameterFlow(node as ParameterDeclaration);
922                break;
923            case SyntaxKind.ObjectLiteralExpression:
924            case SyntaxKind.ArrayLiteralExpression:
925            case SyntaxKind.PropertyAssignment:
926            case SyntaxKind.SpreadElement:
927                // Carry over whether we are in an assignment pattern of Object and Array literals
928                // as well as their children that are valid assignment targets.
929                inAssignmentPattern = saveInAssignmentPattern;
930                // falls through
931            default:
932                bindEachChild(node);
933                break;
934        }
935        bindJSDoc(node);
936        inAssignmentPattern = saveInAssignmentPattern;
937    }
938
939    function isNarrowingExpression(expr: Expression): boolean {
940        switch (expr.kind) {
941            case SyntaxKind.Identifier:
942            case SyntaxKind.PrivateIdentifier:
943            case SyntaxKind.ThisKeyword:
944            case SyntaxKind.PropertyAccessExpression:
945            case SyntaxKind.ElementAccessExpression:
946                return containsNarrowableReference(expr);
947            case SyntaxKind.CallExpression:
948                return hasNarrowableArgument(expr as CallExpression);
949            case SyntaxKind.ParenthesizedExpression:
950            case SyntaxKind.NonNullExpression:
951                return isNarrowingExpression((expr as ParenthesizedExpression | NonNullExpression).expression);
952            case SyntaxKind.BinaryExpression:
953                return isNarrowingBinaryExpression(expr as BinaryExpression);
954            case SyntaxKind.PrefixUnaryExpression:
955                return (expr as PrefixUnaryExpression).operator === SyntaxKind.ExclamationToken && isNarrowingExpression((expr as PrefixUnaryExpression).operand);
956            case SyntaxKind.TypeOfExpression:
957                return isNarrowingExpression((expr as TypeOfExpression).expression);
958        }
959        return false;
960    }
961
962    function isNarrowableReference(expr: Expression): boolean {
963        return isDottedName(expr)
964            || (isPropertyAccessExpression(expr) || isNonNullExpression(expr) || isParenthesizedExpression(expr)) && isNarrowableReference(expr.expression)
965            || isBinaryExpression(expr) && expr.operatorToken.kind === SyntaxKind.CommaToken && isNarrowableReference(expr.right)
966            || isElementAccessExpression(expr) && (isStringOrNumericLiteralLike(expr.argumentExpression) || isEntityNameExpression(expr.argumentExpression)) && isNarrowableReference(expr.expression)
967            || isAssignmentExpression(expr) && isNarrowableReference(expr.left);
968    }
969
970    function containsNarrowableReference(expr: Expression): boolean {
971        return isNarrowableReference(expr) || isOptionalChain(expr) && containsNarrowableReference(expr.expression);
972    }
973
974    function hasNarrowableArgument(expr: CallExpression) {
975        if (expr.arguments) {
976            for (const argument of expr.arguments) {
977                if (containsNarrowableReference(argument)) {
978                    return true;
979                }
980            }
981        }
982        if (expr.expression.kind === SyntaxKind.PropertyAccessExpression &&
983            containsNarrowableReference((expr.expression as PropertyAccessExpression).expression)) {
984            return true;
985        }
986        return false;
987    }
988
989    function isNarrowingTypeofOperands(expr1: Expression, expr2: Expression) {
990        return isTypeOfExpression(expr1) && isNarrowableOperand(expr1.expression) && isStringLiteralLike(expr2);
991    }
992
993    function isNarrowingBinaryExpression(expr: BinaryExpression) {
994        switch (expr.operatorToken.kind) {
995            case SyntaxKind.EqualsToken:
996            case SyntaxKind.BarBarEqualsToken:
997            case SyntaxKind.AmpersandAmpersandEqualsToken:
998            case SyntaxKind.QuestionQuestionEqualsToken:
999                return containsNarrowableReference(expr.left);
1000            case SyntaxKind.EqualsEqualsToken:
1001            case SyntaxKind.ExclamationEqualsToken:
1002            case SyntaxKind.EqualsEqualsEqualsToken:
1003            case SyntaxKind.ExclamationEqualsEqualsToken:
1004                return isNarrowableOperand(expr.left) || isNarrowableOperand(expr.right) ||
1005                    isNarrowingTypeofOperands(expr.right, expr.left) || isNarrowingTypeofOperands(expr.left, expr.right);
1006            case SyntaxKind.InstanceOfKeyword:
1007                return isNarrowableOperand(expr.left);
1008            case SyntaxKind.InKeyword:
1009                return isNarrowingExpression(expr.right);
1010            case SyntaxKind.CommaToken:
1011                return isNarrowingExpression(expr.right);
1012        }
1013        return false;
1014    }
1015
1016    function isNarrowableOperand(expr: Expression): boolean {
1017        switch (expr.kind) {
1018            case SyntaxKind.ParenthesizedExpression:
1019                return isNarrowableOperand((expr as ParenthesizedExpression).expression);
1020            case SyntaxKind.BinaryExpression:
1021                switch ((expr as BinaryExpression).operatorToken.kind) {
1022                    case SyntaxKind.EqualsToken:
1023                        return isNarrowableOperand((expr as BinaryExpression).left);
1024                    case SyntaxKind.CommaToken:
1025                        return isNarrowableOperand((expr as BinaryExpression).right);
1026                }
1027        }
1028        return containsNarrowableReference(expr);
1029    }
1030
1031    function createBranchLabel(): FlowLabel {
1032        return initFlowNode({ flags: FlowFlags.BranchLabel, antecedents: undefined });
1033    }
1034
1035    function createLoopLabel(): FlowLabel {
1036        return initFlowNode({ flags: FlowFlags.LoopLabel, antecedents: undefined });
1037    }
1038
1039    function createReduceLabel(target: FlowLabel, antecedents: FlowNode[], antecedent: FlowNode): FlowReduceLabel {
1040        return initFlowNode({ flags: FlowFlags.ReduceLabel, target, antecedents, antecedent });
1041    }
1042
1043    function setFlowNodeReferenced(flow: FlowNode) {
1044        // On first reference we set the Referenced flag, thereafter we set the Shared flag
1045        flow.flags |= flow.flags & FlowFlags.Referenced ? FlowFlags.Shared : FlowFlags.Referenced;
1046    }
1047
1048    function addAntecedent(label: FlowLabel, antecedent: FlowNode): void {
1049        if (!(antecedent.flags & FlowFlags.Unreachable) && !contains(label.antecedents, antecedent)) {
1050            (label.antecedents || (label.antecedents = [])).push(antecedent);
1051            setFlowNodeReferenced(antecedent);
1052        }
1053    }
1054
1055    function createFlowCondition(flags: FlowFlags, antecedent: FlowNode, expression: Expression | undefined): FlowNode {
1056        if (antecedent.flags & FlowFlags.Unreachable) {
1057            return antecedent;
1058        }
1059        if (!expression) {
1060            return flags & FlowFlags.TrueCondition ? antecedent : unreachableFlow;
1061        }
1062        if ((expression.kind === SyntaxKind.TrueKeyword && flags & FlowFlags.FalseCondition ||
1063            expression.kind === SyntaxKind.FalseKeyword && flags & FlowFlags.TrueCondition) &&
1064            !isExpressionOfOptionalChainRoot(expression) && !isNullishCoalesce(expression.parent)) {
1065            return unreachableFlow;
1066        }
1067        if (!isNarrowingExpression(expression)) {
1068            return antecedent;
1069        }
1070        setFlowNodeReferenced(antecedent);
1071        return initFlowNode({ flags, antecedent, node: expression });
1072    }
1073
1074    function createFlowSwitchClause(antecedent: FlowNode, switchStatement: SwitchStatement, clauseStart: number, clauseEnd: number): FlowNode {
1075        setFlowNodeReferenced(antecedent);
1076        return initFlowNode({ flags: FlowFlags.SwitchClause, antecedent, switchStatement, clauseStart, clauseEnd });
1077    }
1078
1079    function createFlowMutation(flags: FlowFlags, antecedent: FlowNode, node: Expression | VariableDeclaration | ArrayBindingElement): FlowNode {
1080        setFlowNodeReferenced(antecedent);
1081        const result = initFlowNode({ flags, antecedent, node });
1082        if (currentExceptionTarget) {
1083            addAntecedent(currentExceptionTarget, result);
1084        }
1085        return result;
1086    }
1087
1088    function createFlowCall(antecedent: FlowNode, node: CallExpression): FlowNode {
1089        setFlowNodeReferenced(antecedent);
1090        return initFlowNode({ flags: FlowFlags.Call, antecedent, node });
1091    }
1092
1093    function finishFlowLabel(flow: FlowLabel): FlowNode {
1094        const antecedents = flow.antecedents;
1095        if (!antecedents) {
1096            return unreachableFlow;
1097        }
1098        if (antecedents.length === 1) {
1099            return antecedents[0];
1100        }
1101        return flow;
1102    }
1103
1104    function isStatementCondition(node: Node) {
1105        const parent = node.parent;
1106        switch (parent.kind) {
1107            case SyntaxKind.IfStatement:
1108            case SyntaxKind.WhileStatement:
1109            case SyntaxKind.DoStatement:
1110                return (parent as IfStatement | WhileStatement | DoStatement).expression === node;
1111            case SyntaxKind.ForStatement:
1112            case SyntaxKind.ConditionalExpression:
1113                return (parent as ForStatement | ConditionalExpression).condition === node;
1114        }
1115        return false;
1116    }
1117
1118    function isLogicalExpression(node: Node) {
1119        while (true) {
1120            if (node.kind === SyntaxKind.ParenthesizedExpression) {
1121                node = (node as ParenthesizedExpression).expression;
1122            }
1123            else if (node.kind === SyntaxKind.PrefixUnaryExpression && (node as PrefixUnaryExpression).operator === SyntaxKind.ExclamationToken) {
1124                node = (node as PrefixUnaryExpression).operand;
1125            }
1126            else {
1127                return node.kind === SyntaxKind.BinaryExpression && (
1128                    (node as BinaryExpression).operatorToken.kind === SyntaxKind.AmpersandAmpersandToken ||
1129                    (node as BinaryExpression).operatorToken.kind === SyntaxKind.BarBarToken ||
1130                    (node as BinaryExpression).operatorToken.kind === SyntaxKind.QuestionQuestionToken);
1131            }
1132        }
1133    }
1134
1135    function isLogicalAssignmentExpression(node: Node) {
1136        node = skipParentheses(node);
1137        return isBinaryExpression(node) && isLogicalOrCoalescingAssignmentOperator(node.operatorToken.kind);
1138    }
1139
1140    function isTopLevelLogicalExpression(node: Node): boolean {
1141        while (isParenthesizedExpression(node.parent) ||
1142            isPrefixUnaryExpression(node.parent) && node.parent.operator === SyntaxKind.ExclamationToken) {
1143            node = node.parent;
1144        }
1145        return !isStatementCondition(node) &&
1146            !isLogicalExpression(node.parent) &&
1147            !(isOptionalChain(node.parent) && node.parent.expression === node);
1148    }
1149
1150    function doWithConditionalBranches<T>(action: (value: T) => void, value: T, trueTarget: FlowLabel, falseTarget: FlowLabel) {
1151        const savedTrueTarget = currentTrueTarget;
1152        const savedFalseTarget = currentFalseTarget;
1153        currentTrueTarget = trueTarget;
1154        currentFalseTarget = falseTarget;
1155        action(value);
1156        currentTrueTarget = savedTrueTarget;
1157        currentFalseTarget = savedFalseTarget;
1158    }
1159
1160    function bindCondition(node: Expression | undefined, trueTarget: FlowLabel, falseTarget: FlowLabel) {
1161        doWithConditionalBranches(bind, node, trueTarget, falseTarget);
1162        if (!node || !isLogicalAssignmentExpression(node) && !isLogicalExpression(node) && !(isOptionalChain(node) && isOutermostOptionalChain(node))) {
1163            addAntecedent(trueTarget, createFlowCondition(FlowFlags.TrueCondition, currentFlow, node));
1164            addAntecedent(falseTarget, createFlowCondition(FlowFlags.FalseCondition, currentFlow, node));
1165        }
1166    }
1167
1168    function bindIterativeStatement(node: Statement, breakTarget: FlowLabel, continueTarget: FlowLabel): void {
1169        const saveBreakTarget = currentBreakTarget;
1170        const saveContinueTarget = currentContinueTarget;
1171        currentBreakTarget = breakTarget;
1172        currentContinueTarget = continueTarget;
1173        bind(node);
1174        currentBreakTarget = saveBreakTarget;
1175        currentContinueTarget = saveContinueTarget;
1176    }
1177
1178    function setContinueTarget(node: Node, target: FlowLabel) {
1179        let label = activeLabelList;
1180        while (label && node.parent.kind === SyntaxKind.LabeledStatement) {
1181            label.continueTarget = target;
1182            label = label.next;
1183            node = node.parent;
1184        }
1185        return target;
1186    }
1187
1188    function bindWhileStatement(node: WhileStatement): void {
1189        const preWhileLabel = setContinueTarget(node, createLoopLabel());
1190        const preBodyLabel = createBranchLabel();
1191        const postWhileLabel = createBranchLabel();
1192        addAntecedent(preWhileLabel, currentFlow);
1193        currentFlow = preWhileLabel;
1194        bindCondition(node.expression, preBodyLabel, postWhileLabel);
1195        currentFlow = finishFlowLabel(preBodyLabel);
1196        bindIterativeStatement(node.statement, postWhileLabel, preWhileLabel);
1197        addAntecedent(preWhileLabel, currentFlow);
1198        currentFlow = finishFlowLabel(postWhileLabel);
1199    }
1200
1201    function bindDoStatement(node: DoStatement): void {
1202        const preDoLabel = createLoopLabel();
1203        const preConditionLabel = setContinueTarget(node, createBranchLabel());
1204        const postDoLabel = createBranchLabel();
1205        addAntecedent(preDoLabel, currentFlow);
1206        currentFlow = preDoLabel;
1207        bindIterativeStatement(node.statement, postDoLabel, preConditionLabel);
1208        addAntecedent(preConditionLabel, currentFlow);
1209        currentFlow = finishFlowLabel(preConditionLabel);
1210        bindCondition(node.expression, preDoLabel, postDoLabel);
1211        currentFlow = finishFlowLabel(postDoLabel);
1212    }
1213
1214    function bindForStatement(node: ForStatement): void {
1215        const preLoopLabel = setContinueTarget(node, createLoopLabel());
1216        const preBodyLabel = createBranchLabel();
1217        const postLoopLabel = createBranchLabel();
1218        bind(node.initializer);
1219        addAntecedent(preLoopLabel, currentFlow);
1220        currentFlow = preLoopLabel;
1221        bindCondition(node.condition, preBodyLabel, postLoopLabel);
1222        currentFlow = finishFlowLabel(preBodyLabel);
1223        bindIterativeStatement(node.statement, postLoopLabel, preLoopLabel);
1224        bind(node.incrementor);
1225        addAntecedent(preLoopLabel, currentFlow);
1226        currentFlow = finishFlowLabel(postLoopLabel);
1227    }
1228
1229    function bindForInOrForOfStatement(node: ForInOrOfStatement): void {
1230        const preLoopLabel = setContinueTarget(node, createLoopLabel());
1231        const postLoopLabel = createBranchLabel();
1232        bind(node.expression);
1233        addAntecedent(preLoopLabel, currentFlow);
1234        currentFlow = preLoopLabel;
1235        if (node.kind === SyntaxKind.ForOfStatement) {
1236            bind(node.awaitModifier);
1237        }
1238        addAntecedent(postLoopLabel, currentFlow);
1239        bind(node.initializer);
1240        if (node.initializer.kind !== SyntaxKind.VariableDeclarationList) {
1241            bindAssignmentTargetFlow(node.initializer);
1242        }
1243        bindIterativeStatement(node.statement, postLoopLabel, preLoopLabel);
1244        addAntecedent(preLoopLabel, currentFlow);
1245        currentFlow = finishFlowLabel(postLoopLabel);
1246    }
1247
1248    function bindIfStatement(node: IfStatement): void {
1249        const thenLabel = createBranchLabel();
1250        const elseLabel = createBranchLabel();
1251        const postIfLabel = createBranchLabel();
1252        bindCondition(node.expression, thenLabel, elseLabel);
1253        currentFlow = finishFlowLabel(thenLabel);
1254        bind(node.thenStatement);
1255        addAntecedent(postIfLabel, currentFlow);
1256        currentFlow = finishFlowLabel(elseLabel);
1257        bind(node.elseStatement);
1258        addAntecedent(postIfLabel, currentFlow);
1259        currentFlow = finishFlowLabel(postIfLabel);
1260    }
1261
1262    function bindReturnOrThrow(node: ReturnStatement | ThrowStatement): void {
1263        bind(node.expression);
1264        if (node.kind === SyntaxKind.ReturnStatement) {
1265            hasExplicitReturn = true;
1266            if (currentReturnTarget) {
1267                addAntecedent(currentReturnTarget, currentFlow);
1268            }
1269        }
1270        currentFlow = unreachableFlow;
1271    }
1272
1273    function findActiveLabel(name: __String) {
1274        for (let label = activeLabelList; label; label = label.next) {
1275            if (label.name === name) {
1276                return label;
1277            }
1278        }
1279        return undefined;
1280    }
1281
1282    function bindBreakOrContinueFlow(node: BreakOrContinueStatement, breakTarget: FlowLabel | undefined, continueTarget: FlowLabel | undefined) {
1283        const flowLabel = node.kind === SyntaxKind.BreakStatement ? breakTarget : continueTarget;
1284        if (flowLabel) {
1285            addAntecedent(flowLabel, currentFlow);
1286            currentFlow = unreachableFlow;
1287        }
1288    }
1289
1290    function bindBreakOrContinueStatement(node: BreakOrContinueStatement): void {
1291        bind(node.label);
1292        if (node.label) {
1293            const activeLabel = findActiveLabel(node.label.escapedText);
1294            if (activeLabel) {
1295                activeLabel.referenced = true;
1296                bindBreakOrContinueFlow(node, activeLabel.breakTarget, activeLabel.continueTarget);
1297            }
1298        }
1299        else {
1300            bindBreakOrContinueFlow(node, currentBreakTarget, currentContinueTarget);
1301        }
1302    }
1303
1304    function bindTryStatement(node: TryStatement): void {
1305        // We conservatively assume that *any* code in the try block can cause an exception, but we only need
1306        // to track code that causes mutations (because only mutations widen the possible control flow type of
1307        // a variable). The exceptionLabel is the target label for control flows that result from exceptions.
1308        // We add all mutation flow nodes as antecedents of this label such that we can analyze them as possible
1309        // antecedents of the start of catch or finally blocks. Furthermore, we add the current control flow to
1310        // represent exceptions that occur before any mutations.
1311        const saveReturnTarget = currentReturnTarget;
1312        const saveExceptionTarget = currentExceptionTarget;
1313        const normalExitLabel = createBranchLabel();
1314        const returnLabel = createBranchLabel();
1315        let exceptionLabel = createBranchLabel();
1316        if (node.finallyBlock) {
1317            currentReturnTarget = returnLabel;
1318        }
1319        addAntecedent(exceptionLabel, currentFlow);
1320        currentExceptionTarget = exceptionLabel;
1321        bind(node.tryBlock);
1322        addAntecedent(normalExitLabel, currentFlow);
1323        if (node.catchClause) {
1324            // Start of catch clause is the target of exceptions from try block.
1325            currentFlow = finishFlowLabel(exceptionLabel);
1326            // The currentExceptionTarget now represents control flows from exceptions in the catch clause.
1327            // Effectively, in a try-catch-finally, if an exception occurs in the try block, the catch block
1328            // acts like a second try block.
1329            exceptionLabel = createBranchLabel();
1330            addAntecedent(exceptionLabel, currentFlow);
1331            currentExceptionTarget = exceptionLabel;
1332            bind(node.catchClause);
1333            addAntecedent(normalExitLabel, currentFlow);
1334        }
1335        currentReturnTarget = saveReturnTarget;
1336        currentExceptionTarget = saveExceptionTarget;
1337        if (node.finallyBlock) {
1338            // Possible ways control can reach the finally block:
1339            // 1) Normal completion of try block of a try-finally or try-catch-finally
1340            // 2) Normal completion of catch block (following exception in try block) of a try-catch-finally
1341            // 3) Return in try or catch block of a try-finally or try-catch-finally
1342            // 4) Exception in try block of a try-finally
1343            // 5) Exception in catch block of a try-catch-finally
1344            // When analyzing a control flow graph that starts inside a finally block we want to consider all
1345            // five possibilities above. However, when analyzing a control flow graph that starts outside (past)
1346            // the finally block, we only want to consider the first two (if we're past a finally block then it
1347            // must have completed normally). Likewise, when analyzing a control flow graph from return statements
1348            // in try or catch blocks in an IIFE, we only want to consider the third. To make this possible, we
1349            // inject a ReduceLabel node into the control flow graph. This node contains an alternate reduced
1350            // set of antecedents for the pre-finally label. As control flow analysis passes by a ReduceLabel
1351            // node, the pre-finally label is temporarily switched to the reduced antecedent set.
1352            const finallyLabel = createBranchLabel();
1353            finallyLabel.antecedents = concatenate(concatenate(normalExitLabel.antecedents, exceptionLabel.antecedents), returnLabel.antecedents);
1354            currentFlow = finallyLabel;
1355            bind(node.finallyBlock);
1356            if (currentFlow.flags & FlowFlags.Unreachable) {
1357                // If the end of the finally block is unreachable, the end of the entire try statement is unreachable.
1358                currentFlow = unreachableFlow;
1359            }
1360            else {
1361                // If we have an IIFE return target and return statements in the try or catch blocks, add a control
1362                // flow that goes back through the finally block and back through only the return statements.
1363                if (currentReturnTarget && returnLabel.antecedents) {
1364                    addAntecedent(currentReturnTarget, createReduceLabel(finallyLabel, returnLabel.antecedents, currentFlow));
1365                }
1366                // If we have an outer exception target (i.e. a containing try-finally or try-catch-finally), add a
1367                // control flow that goes back through the finally blok and back through each possible exception source.
1368                if (currentExceptionTarget && exceptionLabel.antecedents) {
1369                    addAntecedent(currentExceptionTarget, createReduceLabel(finallyLabel, exceptionLabel.antecedents, currentFlow));
1370                }
1371                // If the end of the finally block is reachable, but the end of the try and catch blocks are not,
1372                // convert the current flow to unreachable. For example, 'try { return 1; } finally { ... }' should
1373                // result in an unreachable current control flow.
1374                currentFlow = normalExitLabel.antecedents ? createReduceLabel(finallyLabel, normalExitLabel.antecedents, currentFlow) : unreachableFlow;
1375            }
1376        }
1377        else {
1378            currentFlow = finishFlowLabel(normalExitLabel);
1379        }
1380    }
1381
1382    function bindSwitchStatement(node: SwitchStatement): void {
1383        const postSwitchLabel = createBranchLabel();
1384        bind(node.expression);
1385        const saveBreakTarget = currentBreakTarget;
1386        const savePreSwitchCaseFlow = preSwitchCaseFlow;
1387        currentBreakTarget = postSwitchLabel;
1388        preSwitchCaseFlow = currentFlow;
1389        bind(node.caseBlock);
1390        addAntecedent(postSwitchLabel, currentFlow);
1391        const hasDefault = forEach(node.caseBlock.clauses, c => c.kind === SyntaxKind.DefaultClause);
1392        // We mark a switch statement as possibly exhaustive if it has no default clause and if all
1393        // case clauses have unreachable end points (e.g. they all return). Note, we no longer need
1394        // this property in control flow analysis, it's there only for backwards compatibility.
1395        node.possiblyExhaustive = !hasDefault && !postSwitchLabel.antecedents;
1396        if (!hasDefault) {
1397            addAntecedent(postSwitchLabel, createFlowSwitchClause(preSwitchCaseFlow, node, 0, 0));
1398        }
1399        currentBreakTarget = saveBreakTarget;
1400        preSwitchCaseFlow = savePreSwitchCaseFlow;
1401        currentFlow = finishFlowLabel(postSwitchLabel);
1402    }
1403
1404    function bindCaseBlock(node: CaseBlock): void {
1405        const clauses = node.clauses;
1406        const isNarrowingSwitch = isNarrowingExpression(node.parent.expression);
1407        let fallthroughFlow = unreachableFlow;
1408        for (let i = 0; i < clauses.length; i++) {
1409            const clauseStart = i;
1410            while (!clauses[i].statements.length && i + 1 < clauses.length) {
1411                bind(clauses[i]);
1412                i++;
1413            }
1414            const preCaseLabel = createBranchLabel();
1415            addAntecedent(preCaseLabel, isNarrowingSwitch ? createFlowSwitchClause(preSwitchCaseFlow!, node.parent, clauseStart, i + 1) : preSwitchCaseFlow!);
1416            addAntecedent(preCaseLabel, fallthroughFlow);
1417            currentFlow = finishFlowLabel(preCaseLabel);
1418            const clause = clauses[i];
1419            bind(clause);
1420            fallthroughFlow = currentFlow;
1421            if (!(currentFlow.flags & FlowFlags.Unreachable) && i !== clauses.length - 1 && options.noFallthroughCasesInSwitch) {
1422                clause.fallthroughFlowNode = currentFlow;
1423            }
1424        }
1425    }
1426
1427    function bindCaseClause(node: CaseClause): void {
1428        const saveCurrentFlow = currentFlow;
1429        currentFlow = preSwitchCaseFlow!;
1430        bind(node.expression);
1431        currentFlow = saveCurrentFlow;
1432        bindEach(node.statements);
1433    }
1434
1435    function bindExpressionStatement(node: ExpressionStatement): void {
1436        bind(node.expression);
1437        maybeBindExpressionFlowIfCall(node.expression);
1438    }
1439
1440    function maybeBindExpressionFlowIfCall(node: Expression) {
1441        // A top level or comma expression call expression with a dotted function name and at least one argument
1442        // is potentially an assertion and is therefore included in the control flow.
1443        if (node.kind === SyntaxKind.CallExpression) {
1444            const call = node as CallExpression;
1445            if (call.expression.kind !== SyntaxKind.SuperKeyword && isDottedName(call.expression)) {
1446                currentFlow = createFlowCall(currentFlow, call);
1447            }
1448        }
1449    }
1450
1451    function bindLabeledStatement(node: LabeledStatement): void {
1452        const postStatementLabel = createBranchLabel();
1453        activeLabelList = {
1454            next: activeLabelList,
1455            name: node.label.escapedText,
1456            breakTarget: postStatementLabel,
1457            continueTarget: undefined,
1458            referenced: false
1459        };
1460        bind(node.label);
1461        bind(node.statement);
1462        if (!activeLabelList.referenced && !options.allowUnusedLabels) {
1463            errorOrSuggestionOnNode(unusedLabelIsError(options), node.label, Diagnostics.Unused_label);
1464        }
1465        activeLabelList = activeLabelList.next;
1466        addAntecedent(postStatementLabel, currentFlow);
1467        currentFlow = finishFlowLabel(postStatementLabel);
1468    }
1469
1470    function bindDestructuringTargetFlow(node: Expression) {
1471        if (node.kind === SyntaxKind.BinaryExpression && (node as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken) {
1472            bindAssignmentTargetFlow((node as BinaryExpression).left);
1473        }
1474        else {
1475            bindAssignmentTargetFlow(node);
1476        }
1477    }
1478
1479    function bindAssignmentTargetFlow(node: Expression) {
1480        if (isNarrowableReference(node)) {
1481            currentFlow = createFlowMutation(FlowFlags.Assignment, currentFlow, node);
1482        }
1483        else if (node.kind === SyntaxKind.ArrayLiteralExpression) {
1484            for (const e of (node as ArrayLiteralExpression).elements) {
1485                if (e.kind === SyntaxKind.SpreadElement) {
1486                    bindAssignmentTargetFlow((e as SpreadElement).expression);
1487                }
1488                else {
1489                    bindDestructuringTargetFlow(e);
1490                }
1491            }
1492        }
1493        else if (node.kind === SyntaxKind.ObjectLiteralExpression) {
1494            for (const p of (node as ObjectLiteralExpression).properties) {
1495                if (p.kind === SyntaxKind.PropertyAssignment) {
1496                    bindDestructuringTargetFlow(p.initializer);
1497                }
1498                else if (p.kind === SyntaxKind.ShorthandPropertyAssignment) {
1499                    bindAssignmentTargetFlow(p.name);
1500                }
1501                else if (p.kind === SyntaxKind.SpreadAssignment) {
1502                    bindAssignmentTargetFlow(p.expression);
1503                }
1504            }
1505        }
1506    }
1507
1508    function bindLogicalLikeExpression(node: BinaryExpression, trueTarget: FlowLabel, falseTarget: FlowLabel) {
1509        const preRightLabel = createBranchLabel();
1510        if (node.operatorToken.kind === SyntaxKind.AmpersandAmpersandToken || node.operatorToken.kind === SyntaxKind.AmpersandAmpersandEqualsToken) {
1511            bindCondition(node.left, preRightLabel, falseTarget);
1512        }
1513        else {
1514            bindCondition(node.left, trueTarget, preRightLabel);
1515        }
1516        currentFlow = finishFlowLabel(preRightLabel);
1517        bind(node.operatorToken);
1518
1519        if (isLogicalOrCoalescingAssignmentOperator(node.operatorToken.kind)) {
1520            doWithConditionalBranches(bind, node.right, trueTarget, falseTarget);
1521            bindAssignmentTargetFlow(node.left);
1522
1523            addAntecedent(trueTarget, createFlowCondition(FlowFlags.TrueCondition, currentFlow, node));
1524            addAntecedent(falseTarget, createFlowCondition(FlowFlags.FalseCondition, currentFlow, node));
1525        }
1526        else {
1527            bindCondition(node.right, trueTarget, falseTarget);
1528        }
1529    }
1530
1531    function bindPrefixUnaryExpressionFlow(node: PrefixUnaryExpression) {
1532        if (node.operator === SyntaxKind.ExclamationToken) {
1533            const saveTrueTarget = currentTrueTarget;
1534            currentTrueTarget = currentFalseTarget;
1535            currentFalseTarget = saveTrueTarget;
1536            bindEachChild(node);
1537            currentFalseTarget = currentTrueTarget;
1538            currentTrueTarget = saveTrueTarget;
1539        }
1540        else {
1541            bindEachChild(node);
1542            if (node.operator === SyntaxKind.PlusPlusToken || node.operator === SyntaxKind.MinusMinusToken) {
1543                bindAssignmentTargetFlow(node.operand);
1544            }
1545        }
1546    }
1547
1548    function bindPostfixUnaryExpressionFlow(node: PostfixUnaryExpression) {
1549        bindEachChild(node);
1550        if (node.operator === SyntaxKind.PlusPlusToken || node.operator === SyntaxKind.MinusMinusToken) {
1551            bindAssignmentTargetFlow(node.operand);
1552        }
1553    }
1554
1555    function bindDestructuringAssignmentFlow(node: DestructuringAssignment) {
1556        if (inAssignmentPattern) {
1557            inAssignmentPattern = false;
1558            bind(node.operatorToken);
1559            bind(node.right);
1560            inAssignmentPattern = true;
1561            bind(node.left);
1562        }
1563        else {
1564            inAssignmentPattern = true;
1565            bind(node.left);
1566            inAssignmentPattern = false;
1567            bind(node.operatorToken);
1568            bind(node.right);
1569        }
1570        bindAssignmentTargetFlow(node.left);
1571    }
1572
1573    function createBindBinaryExpressionFlow() {
1574        interface WorkArea {
1575            stackIndex: number;
1576            skip: boolean;
1577            inStrictModeStack: (boolean | undefined)[];
1578            parentStack: (Node | undefined)[];
1579        }
1580
1581        return createBinaryExpressionTrampoline(onEnter, onLeft, onOperator, onRight, onExit, /*foldState*/ undefined);
1582
1583        function onEnter(node: BinaryExpression, state: WorkArea | undefined) {
1584            if (state) {
1585                state.stackIndex++;
1586                // Emulate the work that `bind` does before reaching `bindChildren`. A normal call to
1587                // `bindBinaryExpressionFlow` will already have done this work.
1588                setParent(node, parent);
1589                const saveInStrictMode = inStrictMode;
1590                bindWorker(node);
1591                const saveParent = parent;
1592                parent = node;
1593                state.skip = false;
1594                state.inStrictModeStack[state.stackIndex] = saveInStrictMode;
1595                state.parentStack[state.stackIndex] = saveParent;
1596            }
1597            else {
1598                state = {
1599                    stackIndex: 0,
1600                    skip: false,
1601                    inStrictModeStack: [undefined],
1602                    parentStack: [undefined]
1603                };
1604            }
1605            // TODO: bindLogicalExpression is recursive - if we want to handle deeply nested `&&` expressions
1606            // we'll need to handle the `bindLogicalExpression` scenarios in this state machine, too
1607            // For now, though, since the common cases are chained `+`, leaving it recursive is fine
1608            const operator = node.operatorToken.kind;
1609            if (operator === SyntaxKind.AmpersandAmpersandToken ||
1610                operator === SyntaxKind.BarBarToken ||
1611                operator === SyntaxKind.QuestionQuestionToken ||
1612                isLogicalOrCoalescingAssignmentOperator(operator)) {
1613                if (isTopLevelLogicalExpression(node)) {
1614                    const postExpressionLabel = createBranchLabel();
1615                    bindLogicalLikeExpression(node, postExpressionLabel, postExpressionLabel);
1616                    currentFlow = finishFlowLabel(postExpressionLabel);
1617                }
1618                else {
1619                    bindLogicalLikeExpression(node, currentTrueTarget!, currentFalseTarget!);
1620                }
1621                state.skip = true;
1622            }
1623            return state;
1624        }
1625
1626        function onLeft(left: Expression, state: WorkArea, node: BinaryExpression) {
1627            if (!state.skip) {
1628                const maybeBound = maybeBind(left);
1629                if (node.operatorToken.kind === SyntaxKind.CommaToken) {
1630                    maybeBindExpressionFlowIfCall(left);
1631                }
1632                return maybeBound;
1633            }
1634        }
1635
1636        function onOperator(operatorToken: BinaryOperatorToken, state: WorkArea, _node: BinaryExpression) {
1637            if (!state.skip) {
1638                bind(operatorToken);
1639            }
1640        }
1641
1642        function onRight(right: Expression, state: WorkArea, node: BinaryExpression) {
1643            if (!state.skip) {
1644                const maybeBound = maybeBind(right);
1645                if (node.operatorToken.kind === SyntaxKind.CommaToken) {
1646                    maybeBindExpressionFlowIfCall(right);
1647                }
1648                return maybeBound;
1649            }
1650        }
1651
1652        function onExit(node: BinaryExpression, state: WorkArea) {
1653            if (!state.skip) {
1654                const operator = node.operatorToken.kind;
1655                if (isAssignmentOperator(operator) && !isAssignmentTarget(node)) {
1656                    bindAssignmentTargetFlow(node.left);
1657                    if (operator === SyntaxKind.EqualsToken && node.left.kind === SyntaxKind.ElementAccessExpression) {
1658                        const elementAccess = node.left as ElementAccessExpression;
1659                        if (isNarrowableOperand(elementAccess.expression)) {
1660                            currentFlow = createFlowMutation(FlowFlags.ArrayMutation, currentFlow, node);
1661                        }
1662                    }
1663                }
1664            }
1665            const savedInStrictMode = state.inStrictModeStack[state.stackIndex];
1666            const savedParent = state.parentStack[state.stackIndex];
1667            if (savedInStrictMode !== undefined) {
1668                inStrictMode = savedInStrictMode;
1669            }
1670            if (savedParent !== undefined) {
1671                parent = savedParent;
1672            }
1673            state.skip = false;
1674            state.stackIndex--;
1675        }
1676
1677        function maybeBind(node: Node) {
1678            if (node && isBinaryExpression(node) && !isDestructuringAssignment(node)) {
1679                return node;
1680            }
1681            bind(node);
1682        }
1683    }
1684
1685    function bindDeleteExpressionFlow(node: DeleteExpression) {
1686        bindEachChild(node);
1687        if (node.expression.kind === SyntaxKind.PropertyAccessExpression) {
1688            bindAssignmentTargetFlow(node.expression);
1689        }
1690    }
1691
1692    function bindConditionalExpressionFlow(node: ConditionalExpression) {
1693        const trueLabel = createBranchLabel();
1694        const falseLabel = createBranchLabel();
1695        const postExpressionLabel = createBranchLabel();
1696        bindCondition(node.condition, trueLabel, falseLabel);
1697        currentFlow = finishFlowLabel(trueLabel);
1698        bind(node.questionToken);
1699        bind(node.whenTrue);
1700        addAntecedent(postExpressionLabel, currentFlow);
1701        currentFlow = finishFlowLabel(falseLabel);
1702        bind(node.colonToken);
1703        bind(node.whenFalse);
1704        addAntecedent(postExpressionLabel, currentFlow);
1705        currentFlow = finishFlowLabel(postExpressionLabel);
1706    }
1707
1708    function bindInitializedVariableFlow(node: VariableDeclaration | ArrayBindingElement) {
1709        const name = !isOmittedExpression(node) ? node.name : undefined;
1710        if (isBindingPattern(name)) {
1711            for (const child of name.elements) {
1712                bindInitializedVariableFlow(child);
1713            }
1714        }
1715        else {
1716            currentFlow = createFlowMutation(FlowFlags.Assignment, currentFlow, node);
1717        }
1718    }
1719
1720    function bindVariableDeclarationFlow(node: VariableDeclaration) {
1721        bindEachChild(node);
1722        if (node.initializer || isForInOrOfStatement(node.parent.parent)) {
1723            bindInitializedVariableFlow(node);
1724        }
1725    }
1726
1727    function bindBindingElementFlow(node: BindingElement) {
1728        // When evaluating a binding pattern, the initializer is evaluated before the binding pattern, per:
1729        // - https://tc39.es/ecma262/#sec-destructuring-binding-patterns-runtime-semantics-iteratorbindinginitialization
1730        //   - `BindingElement: BindingPattern Initializer?`
1731        // - https://tc39.es/ecma262/#sec-runtime-semantics-keyedbindinginitialization
1732        //   - `BindingElement: BindingPattern Initializer?`
1733        bind(node.dotDotDotToken);
1734        bind(node.propertyName);
1735        bindInitializer(node.initializer);
1736        bind(node.name);
1737    }
1738
1739    function bindParameterFlow(node: ParameterDeclaration) {
1740        bindEach(node.modifiers);
1741        bind(node.dotDotDotToken);
1742        bind(node.questionToken);
1743        bind(node.type);
1744        bindInitializer(node.initializer);
1745        bind(node.name);
1746    }
1747
1748    // a BindingElement/Parameter does not have side effects if initializers are not evaluated and used. (see GH#49759)
1749    function bindInitializer(node: Expression | undefined) {
1750        if (!node) {
1751            return;
1752        }
1753        const entryFlow = currentFlow;
1754        bind(node);
1755        if (entryFlow === unreachableFlow || entryFlow === currentFlow) {
1756            return;
1757        }
1758        const exitFlow = createBranchLabel();
1759        addAntecedent(exitFlow, entryFlow);
1760        addAntecedent(exitFlow, currentFlow);
1761        currentFlow = finishFlowLabel(exitFlow);
1762    }
1763
1764    function bindJSDocTypeAlias(node: JSDocTypedefTag | JSDocCallbackTag | JSDocEnumTag) {
1765        bind(node.tagName);
1766        if (node.kind !== SyntaxKind.JSDocEnumTag && node.fullName) {
1767            // don't bind the type name yet; that's delayed until delayedBindJSDocTypedefTag
1768            setParent(node.fullName, node);
1769            setParentRecursive(node.fullName, /*incremental*/ false);
1770        }
1771        if (typeof node.comment !== "string") {
1772            bindEach(node.comment);
1773        }
1774    }
1775
1776    function bindJSDocClassTag(node: JSDocClassTag) {
1777        bindEachChild(node);
1778        const host = getHostSignatureFromJSDoc(node);
1779        if (host && host.kind !== SyntaxKind.MethodDeclaration) {
1780            addDeclarationToSymbol(host.symbol, host, SymbolFlags.Class);
1781        }
1782    }
1783
1784    function bindOptionalExpression(node: Expression, trueTarget: FlowLabel, falseTarget: FlowLabel) {
1785        doWithConditionalBranches(bind, node, trueTarget, falseTarget);
1786        if (!isOptionalChain(node) || isOutermostOptionalChain(node)) {
1787            addAntecedent(trueTarget, createFlowCondition(FlowFlags.TrueCondition, currentFlow, node));
1788            addAntecedent(falseTarget, createFlowCondition(FlowFlags.FalseCondition, currentFlow, node));
1789        }
1790    }
1791
1792    function bindOptionalChainRest(node: OptionalChain) {
1793        switch (node.kind) {
1794            case SyntaxKind.PropertyAccessExpression:
1795                bind(node.questionDotToken);
1796                bind(node.name);
1797                break;
1798            case SyntaxKind.ElementAccessExpression:
1799                bind(node.questionDotToken);
1800                bind(node.argumentExpression);
1801                break;
1802            case SyntaxKind.CallExpression:
1803                bind(node.questionDotToken);
1804                bindEach(node.typeArguments);
1805                bindEach(node.arguments);
1806                break;
1807        }
1808    }
1809
1810    function bindOptionalChain(node: OptionalChain, trueTarget: FlowLabel, falseTarget: FlowLabel) {
1811        // For an optional chain, we emulate the behavior of a logical expression:
1812        //
1813        // a?.b         -> a && a.b
1814        // a?.b.c       -> a && a.b.c
1815        // a?.b?.c      -> a && a.b && a.b.c
1816        // a?.[x = 1]   -> a && a[x = 1]
1817        //
1818        // To do this we descend through the chain until we reach the root of a chain (the expression with a `?.`)
1819        // and build it's CFA graph as if it were the first condition (`a && ...`). Then we bind the rest
1820        // of the node as part of the "true" branch, and continue to do so as we ascend back up to the outermost
1821        // chain node. We then treat the entire node as the right side of the expression.
1822        const preChainLabel = isOptionalChainRoot(node) ? createBranchLabel() : undefined;
1823        bindOptionalExpression(node.expression, preChainLabel || trueTarget, falseTarget);
1824        if (preChainLabel) {
1825            currentFlow = finishFlowLabel(preChainLabel);
1826        }
1827        doWithConditionalBranches(bindOptionalChainRest, node, trueTarget, falseTarget);
1828        if (isOutermostOptionalChain(node)) {
1829            addAntecedent(trueTarget, createFlowCondition(FlowFlags.TrueCondition, currentFlow, node));
1830            addAntecedent(falseTarget, createFlowCondition(FlowFlags.FalseCondition, currentFlow, node));
1831        }
1832    }
1833
1834    function bindOptionalChainFlow(node: OptionalChain) {
1835        if (isTopLevelLogicalExpression(node)) {
1836            const postExpressionLabel = createBranchLabel();
1837            bindOptionalChain(node, postExpressionLabel, postExpressionLabel);
1838            currentFlow = finishFlowLabel(postExpressionLabel);
1839        }
1840        else {
1841            bindOptionalChain(node, currentTrueTarget!, currentFalseTarget!);
1842        }
1843    }
1844
1845    function bindNonNullExpressionFlow(node: NonNullExpression | NonNullChain) {
1846        if (isOptionalChain(node)) {
1847            bindOptionalChainFlow(node);
1848        }
1849        else {
1850            bindEachChild(node);
1851        }
1852    }
1853
1854    function bindAccessExpressionFlow(node: AccessExpression | PropertyAccessChain | ElementAccessChain) {
1855        if (isOptionalChain(node)) {
1856            bindOptionalChainFlow(node);
1857        }
1858        else {
1859            bindEachChild(node);
1860        }
1861    }
1862
1863    function bindCallExpressionFlow(node: CallExpression | CallChain) {
1864        if (isOptionalChain(node)) {
1865            bindOptionalChainFlow(node);
1866        }
1867        else {
1868            // If the target of the call expression is a function expression or arrow function we have
1869            // an immediately invoked function expression (IIFE). Initialize the flowNode property to
1870            // the current control flow (which includes evaluation of the IIFE arguments).
1871            const expr = skipParentheses(node.expression);
1872            if (expr.kind === SyntaxKind.FunctionExpression || expr.kind === SyntaxKind.ArrowFunction) {
1873                bindEach(node.typeArguments);
1874                bindEach(node.arguments);
1875                bind(node.expression);
1876            }
1877            else {
1878                bindEachChild(node);
1879                if (node.expression.kind === SyntaxKind.SuperKeyword) {
1880                    currentFlow = createFlowCall(currentFlow, node);
1881                }
1882            }
1883        }
1884        if (node.expression.kind === SyntaxKind.PropertyAccessExpression) {
1885            const propertyAccess = node.expression as PropertyAccessExpression;
1886            if (isIdentifier(propertyAccess.name) && isNarrowableOperand(propertyAccess.expression) && isPushOrUnshiftIdentifier(propertyAccess.name)) {
1887                currentFlow = createFlowMutation(FlowFlags.ArrayMutation, currentFlow, node);
1888            }
1889        }
1890    }
1891
1892    function getContainerFlags(node: Node): ContainerFlags {
1893        switch (node.kind) {
1894            case SyntaxKind.ClassExpression:
1895            case SyntaxKind.ClassDeclaration:
1896            case SyntaxKind.StructDeclaration:
1897            case SyntaxKind.AnnotationDeclaration:
1898            case SyntaxKind.EnumDeclaration:
1899            case SyntaxKind.ObjectLiteralExpression:
1900            case SyntaxKind.TypeLiteral:
1901            case SyntaxKind.JSDocTypeLiteral:
1902            case SyntaxKind.JsxAttributes:
1903                return ContainerFlags.IsContainer;
1904
1905            case SyntaxKind.InterfaceDeclaration:
1906                return ContainerFlags.IsContainer | ContainerFlags.IsInterface;
1907
1908            case SyntaxKind.ModuleDeclaration:
1909            case SyntaxKind.TypeAliasDeclaration:
1910            case SyntaxKind.MappedType:
1911            case SyntaxKind.IndexSignature:
1912                return ContainerFlags.IsContainer | ContainerFlags.HasLocals;
1913
1914            case SyntaxKind.SourceFile:
1915                return ContainerFlags.IsContainer | ContainerFlags.IsControlFlowContainer | ContainerFlags.HasLocals;
1916
1917            case SyntaxKind.GetAccessor:
1918            case SyntaxKind.SetAccessor:
1919            case SyntaxKind.MethodDeclaration:
1920                if (isObjectLiteralOrClassExpressionMethodOrAccessor(node)) {
1921                    return ContainerFlags.IsContainer | ContainerFlags.IsControlFlowContainer | ContainerFlags.HasLocals | ContainerFlags.IsFunctionLike | ContainerFlags.IsObjectLiteralOrClassExpressionMethodOrAccessor;
1922                }
1923                // falls through
1924            case SyntaxKind.Constructor:
1925            case SyntaxKind.FunctionDeclaration:
1926            case SyntaxKind.MethodSignature:
1927            case SyntaxKind.CallSignature:
1928            case SyntaxKind.JSDocSignature:
1929            case SyntaxKind.JSDocFunctionType:
1930            case SyntaxKind.FunctionType:
1931            case SyntaxKind.ConstructSignature:
1932            case SyntaxKind.ConstructorType:
1933            case SyntaxKind.ClassStaticBlockDeclaration:
1934                return ContainerFlags.IsContainer | ContainerFlags.IsControlFlowContainer | ContainerFlags.HasLocals | ContainerFlags.IsFunctionLike;
1935
1936            case SyntaxKind.FunctionExpression:
1937            case SyntaxKind.ArrowFunction:
1938                return ContainerFlags.IsContainer | ContainerFlags.IsControlFlowContainer | ContainerFlags.HasLocals | ContainerFlags.IsFunctionLike | ContainerFlags.IsFunctionExpression;
1939
1940            case SyntaxKind.ModuleBlock:
1941                return ContainerFlags.IsControlFlowContainer;
1942            case SyntaxKind.PropertyDeclaration:
1943                return (node as PropertyDeclaration).initializer ? ContainerFlags.IsControlFlowContainer : 0;
1944            case SyntaxKind.AnnotationPropertyDeclaration:
1945                return (node as AnnotationPropertyDeclaration).initializer ? ContainerFlags.IsControlFlowContainer : 0;
1946
1947
1948            case SyntaxKind.CatchClause:
1949            case SyntaxKind.ForStatement:
1950            case SyntaxKind.ForInStatement:
1951            case SyntaxKind.ForOfStatement:
1952            case SyntaxKind.CaseBlock:
1953                return ContainerFlags.IsBlockScopedContainer;
1954
1955            case SyntaxKind.Block:
1956                // do not treat blocks directly inside a function as a block-scoped-container.
1957                // Locals that reside in this block should go to the function locals. Otherwise 'x'
1958                // would not appear to be a redeclaration of a block scoped local in the following
1959                // example:
1960                //
1961                //      function foo() {
1962                //          var x;
1963                //          let x;
1964                //      }
1965                //
1966                // If we placed 'var x' into the function locals and 'let x' into the locals of
1967                // the block, then there would be no collision.
1968                //
1969                // By not creating a new block-scoped-container here, we ensure that both 'var x'
1970                // and 'let x' go into the Function-container's locals, and we do get a collision
1971                // conflict.
1972                return isFunctionLike(node.parent) || isClassStaticBlockDeclaration(node.parent) ? ContainerFlags.None : ContainerFlags.IsBlockScopedContainer;
1973        }
1974
1975        return ContainerFlags.None;
1976    }
1977
1978    function addToContainerChain(next: Node) {
1979        if (lastContainer) {
1980            lastContainer.nextContainer = next;
1981        }
1982
1983        lastContainer = next;
1984    }
1985
1986    function declareSymbolAndAddToSymbolTable(node: Declaration, symbolFlags: SymbolFlags, symbolExcludes: SymbolFlags): Symbol | undefined {
1987        switch (container.kind) {
1988            // Modules, source files, and classes need specialized handling for how their
1989            // members are declared (for example, a member of a class will go into a specific
1990            // symbol table depending on if it is static or not). We defer to specialized
1991            // handlers to take care of declaring these child members.
1992            case SyntaxKind.ModuleDeclaration:
1993                return declareModuleMember(node, symbolFlags, symbolExcludes);
1994
1995            case SyntaxKind.SourceFile:
1996                return declareSourceFileMember(node, symbolFlags, symbolExcludes);
1997
1998            case SyntaxKind.ClassExpression:
1999            case SyntaxKind.ClassDeclaration:
2000            case SyntaxKind.StructDeclaration:
2001            case SyntaxKind.AnnotationDeclaration:
2002                return declareClassMember(node, symbolFlags, symbolExcludes);
2003
2004            case SyntaxKind.EnumDeclaration:
2005                return declareSymbol(container.symbol.exports!, container.symbol, node, symbolFlags, symbolExcludes);
2006
2007            case SyntaxKind.TypeLiteral:
2008            case SyntaxKind.JSDocTypeLiteral:
2009            case SyntaxKind.ObjectLiteralExpression:
2010            case SyntaxKind.InterfaceDeclaration:
2011            case SyntaxKind.JsxAttributes:
2012                // Interface/Object-types always have their children added to the 'members' of
2013                // their container. They are only accessible through an instance of their
2014                // container, and are never in scope otherwise (even inside the body of the
2015                // object / type / interface declaring them). An exception is type parameters,
2016                // which are in scope without qualification (similar to 'locals').
2017                return declareSymbol(container.symbol.members!, container.symbol, node, symbolFlags, symbolExcludes);
2018
2019            case SyntaxKind.FunctionType:
2020            case SyntaxKind.ConstructorType:
2021            case SyntaxKind.CallSignature:
2022            case SyntaxKind.ConstructSignature:
2023            case SyntaxKind.JSDocSignature:
2024            case SyntaxKind.IndexSignature:
2025            case SyntaxKind.MethodDeclaration:
2026            case SyntaxKind.MethodSignature:
2027            case SyntaxKind.Constructor:
2028            case SyntaxKind.GetAccessor:
2029            case SyntaxKind.SetAccessor:
2030            case SyntaxKind.FunctionDeclaration:
2031            case SyntaxKind.FunctionExpression:
2032            case SyntaxKind.ArrowFunction:
2033            case SyntaxKind.JSDocFunctionType:
2034            case SyntaxKind.JSDocTypedefTag:
2035            case SyntaxKind.JSDocCallbackTag:
2036            case SyntaxKind.ClassStaticBlockDeclaration:
2037            case SyntaxKind.TypeAliasDeclaration:
2038            case SyntaxKind.MappedType:
2039                // All the children of these container types are never visible through another
2040                // symbol (i.e. through another symbol's 'exports' or 'members').  Instead,
2041                // they're only accessed 'lexically' (i.e. from code that exists underneath
2042                // their container in the tree). To accomplish this, we simply add their declared
2043                // symbol to the 'locals' of the container.  These symbols can then be found as
2044                // the type checker walks up the containers, checking them for matching names.
2045                return declareSymbol(container.locals!, /*parent*/ undefined, node, symbolFlags, symbolExcludes);
2046        }
2047    }
2048
2049    function declareClassMember(node: Declaration, symbolFlags: SymbolFlags, symbolExcludes: SymbolFlags) {
2050        return isStatic(node)
2051            ? declareSymbol(container.symbol.exports!, container.symbol, node, symbolFlags, symbolExcludes)
2052            : declareSymbol(container.symbol.members!, container.symbol, node, symbolFlags, symbolExcludes);
2053    }
2054
2055    function declareSourceFileMember(node: Declaration, symbolFlags: SymbolFlags, symbolExcludes: SymbolFlags) {
2056        return isExternalModule(file)
2057            ? declareModuleMember(node, symbolFlags, symbolExcludes)
2058            : declareSymbol(file.locals!, /*parent*/ undefined, node, symbolFlags, symbolExcludes);
2059    }
2060
2061    function hasExportDeclarations(node: ModuleDeclaration | SourceFile): boolean {
2062        const body = isSourceFile(node) ? node : tryCast(node.body, isModuleBlock);
2063        return !!body && body.statements.some(s => isExportDeclaration(s) || isExportAssignment(s));
2064    }
2065
2066    function setExportContextFlag(node: Mutable<ModuleDeclaration | SourceFile>) {
2067        // A declaration source file or ambient module declaration that contains no export declarations (but possibly regular
2068        // declarations with export modifiers) is an export context in which declarations are implicitly exported.
2069        if (node.flags & NodeFlags.Ambient && !hasExportDeclarations(node)) {
2070            node.flags |= NodeFlags.ExportContext;
2071        }
2072        else {
2073            node.flags &= ~NodeFlags.ExportContext;
2074        }
2075    }
2076
2077    function bindModuleDeclaration(node: ModuleDeclaration) {
2078        setExportContextFlag(node);
2079        if (isAmbientModule(node)) {
2080            if (hasSyntacticModifier(node, ModifierFlags.Export)) {
2081                errorOnFirstToken(node, Diagnostics.export_modifier_cannot_be_applied_to_ambient_modules_and_module_augmentations_since_they_are_always_visible);
2082            }
2083            if (isModuleAugmentationExternal(node)) {
2084                declareModuleSymbol(node);
2085            }
2086            else {
2087                let pattern: string | Pattern | undefined;
2088                if (node.name.kind === SyntaxKind.StringLiteral) {
2089                    const { text } = node.name;
2090                    pattern = tryParsePattern(text);
2091                    if (pattern === undefined) {
2092                        errorOnFirstToken(node.name, Diagnostics.Pattern_0_can_have_at_most_one_Asterisk_character, text);
2093                    }
2094                }
2095
2096                const symbol = declareSymbolAndAddToSymbolTable(node, SymbolFlags.ValueModule, SymbolFlags.ValueModuleExcludes)!;
2097                file.patternAmbientModules = append<PatternAmbientModule>(file.patternAmbientModules, pattern && !isString(pattern) ? { pattern, symbol } : undefined);
2098            }
2099        }
2100        else {
2101            const state = declareModuleSymbol(node);
2102            if (state !== ModuleInstanceState.NonInstantiated) {
2103                const { symbol } = node;
2104                // if module was already merged with some function, class or non-const enum, treat it as non-const-enum-only
2105                symbol.constEnumOnlyModule = (!(symbol.flags & (SymbolFlags.Function | SymbolFlags.Class | SymbolFlags.RegularEnum)))
2106                    // Current must be `const enum` only
2107                    && state === ModuleInstanceState.ConstEnumOnly
2108                    // Can't have been set to 'false' in a previous merged symbol. ('undefined' OK)
2109                    && symbol.constEnumOnlyModule !== false;
2110            }
2111        }
2112    }
2113
2114    function declareModuleSymbol(node: ModuleDeclaration): ModuleInstanceState {
2115        const state = getModuleInstanceState(node);
2116        const instantiated = state !== ModuleInstanceState.NonInstantiated;
2117        declareSymbolAndAddToSymbolTable(node,
2118            instantiated ? SymbolFlags.ValueModule : SymbolFlags.NamespaceModule,
2119            instantiated ? SymbolFlags.ValueModuleExcludes : SymbolFlags.NamespaceModuleExcludes);
2120        return state;
2121    }
2122
2123    function bindFunctionOrConstructorType(node: SignatureDeclaration | JSDocSignature): void {
2124        // For a given function symbol "<...>(...) => T" we want to generate a symbol identical
2125        // to the one we would get for: { <...>(...): T }
2126        //
2127        // We do that by making an anonymous type literal symbol, and then setting the function
2128        // symbol as its sole member. To the rest of the system, this symbol will be indistinguishable
2129        // from an actual type literal symbol you would have gotten had you used the long form.
2130        const symbol = createSymbol(SymbolFlags.Signature, getDeclarationName(node)!); // TODO: GH#18217
2131        addDeclarationToSymbol(symbol, node, SymbolFlags.Signature);
2132
2133        const typeLiteralSymbol = createSymbol(SymbolFlags.TypeLiteral, InternalSymbolName.Type);
2134        addDeclarationToSymbol(typeLiteralSymbol, node, SymbolFlags.TypeLiteral);
2135        typeLiteralSymbol.members = createSymbolTable();
2136        typeLiteralSymbol.members.set(symbol.escapedName, symbol);
2137    }
2138
2139    function bindObjectLiteralExpression(node: ObjectLiteralExpression) {
2140        return bindAnonymousDeclaration(node, SymbolFlags.ObjectLiteral, InternalSymbolName.Object);
2141    }
2142
2143    function bindJsxAttributes(node: JsxAttributes) {
2144        return bindAnonymousDeclaration(node, SymbolFlags.ObjectLiteral, InternalSymbolName.JSXAttributes);
2145    }
2146
2147    function bindJsxAttribute(node: JsxAttribute, symbolFlags: SymbolFlags, symbolExcludes: SymbolFlags) {
2148        return declareSymbolAndAddToSymbolTable(node, symbolFlags, symbolExcludes);
2149    }
2150
2151    function bindAnonymousDeclaration(node: Declaration, symbolFlags: SymbolFlags, name: __String) {
2152        const symbol = createSymbol(symbolFlags, name);
2153        if (symbolFlags & (SymbolFlags.EnumMember | SymbolFlags.ClassMember)) {
2154            symbol.parent = container.symbol;
2155        }
2156        addDeclarationToSymbol(symbol, node, symbolFlags);
2157        return symbol;
2158    }
2159
2160    function bindBlockScopedDeclaration(node: Declaration, symbolFlags: SymbolFlags, symbolExcludes: SymbolFlags) {
2161        switch (blockScopeContainer.kind) {
2162            case SyntaxKind.ModuleDeclaration:
2163                declareModuleMember(node, symbolFlags, symbolExcludes);
2164                break;
2165            case SyntaxKind.SourceFile:
2166                if (isExternalOrCommonJsModule(container as SourceFile)) {
2167                    declareModuleMember(node, symbolFlags, symbolExcludes);
2168                    break;
2169                }
2170                // falls through
2171            default:
2172                if (!blockScopeContainer.locals) {
2173                    blockScopeContainer.locals = createSymbolTable();
2174                    addToContainerChain(blockScopeContainer);
2175                }
2176                declareSymbol(blockScopeContainer.locals, /*parent*/ undefined, node, symbolFlags, symbolExcludes);
2177        }
2178    }
2179
2180    function delayedBindJSDocTypedefTag() {
2181        if (!delayedTypeAliases) {
2182            return;
2183        }
2184        const saveContainer = container;
2185        const saveLastContainer = lastContainer;
2186        const saveBlockScopeContainer = blockScopeContainer;
2187        const saveParent = parent;
2188        const saveCurrentFlow = currentFlow;
2189        for (const typeAlias of delayedTypeAliases) {
2190            const host = typeAlias.parent.parent;
2191            container = findAncestor(host.parent, n => !!(getContainerFlags(n) & ContainerFlags.IsContainer)) || file;
2192            blockScopeContainer = getEnclosingBlockScopeContainer(host) || file;
2193            currentFlow = initFlowNode({ flags: FlowFlags.Start });
2194            parent = typeAlias;
2195            bind(typeAlias.typeExpression);
2196            const declName = getNameOfDeclaration(typeAlias);
2197            if ((isJSDocEnumTag(typeAlias) || !typeAlias.fullName) && declName && isPropertyAccessEntityNameExpression(declName.parent)) {
2198                // typedef anchored to an A.B.C assignment - we need to bind into B's namespace under name C
2199                const isTopLevel = isTopLevelNamespaceAssignment(declName.parent);
2200                if (isTopLevel) {
2201                    bindPotentiallyMissingNamespaces(file.symbol, declName.parent, isTopLevel,
2202                        !!findAncestor(declName, d => isPropertyAccessExpression(d) && d.name.escapedText === "prototype"), /*containerIsClass*/ false);
2203                    const oldContainer = container;
2204                    switch (getAssignmentDeclarationPropertyAccessKind(declName.parent)) {
2205                        case AssignmentDeclarationKind.ExportsProperty:
2206                        case AssignmentDeclarationKind.ModuleExports:
2207                            if (!isExternalOrCommonJsModule(file)) {
2208                                container = undefined!;
2209                            }
2210                            else {
2211                                container = file;
2212                            }
2213                            break;
2214                        case AssignmentDeclarationKind.ThisProperty:
2215                            container = declName.parent.expression;
2216                            break;
2217                        case AssignmentDeclarationKind.PrototypeProperty:
2218                            container = (declName.parent.expression as PropertyAccessExpression).name;
2219                            break;
2220                        case AssignmentDeclarationKind.Property:
2221                            container = isExportsOrModuleExportsOrAlias(file, declName.parent.expression) ? file
2222                                : isPropertyAccessExpression(declName.parent.expression) ? declName.parent.expression.name
2223                                : declName.parent.expression;
2224                            break;
2225                        case AssignmentDeclarationKind.None:
2226                            return Debug.fail("Shouldn't have detected typedef or enum on non-assignment declaration");
2227                    }
2228                    if (container) {
2229                        declareModuleMember(typeAlias, SymbolFlags.TypeAlias, SymbolFlags.TypeAliasExcludes);
2230                    }
2231                    container = oldContainer;
2232                }
2233            }
2234            else if (isJSDocEnumTag(typeAlias) || !typeAlias.fullName || typeAlias.fullName.kind === SyntaxKind.Identifier) {
2235                parent = typeAlias.parent;
2236                bindBlockScopedDeclaration(typeAlias, SymbolFlags.TypeAlias, SymbolFlags.TypeAliasExcludes);
2237            }
2238            else {
2239                bind(typeAlias.fullName);
2240            }
2241        }
2242        container = saveContainer;
2243        lastContainer = saveLastContainer;
2244        blockScopeContainer = saveBlockScopeContainer;
2245        parent = saveParent;
2246        currentFlow = saveCurrentFlow;
2247    }
2248
2249    // The binder visits every node in the syntax tree so it is a convenient place to perform a single localized
2250    // check for reserved words used as identifiers in strict mode code, as well as `yield` or `await` in
2251    // [Yield] or [Await] contexts, respectively.
2252    function checkContextualIdentifier(node: Identifier) {
2253        // Report error only if there are no parse errors in file
2254        if (!file.parseDiagnostics.length &&
2255            !(node.flags & NodeFlags.Ambient) &&
2256            !(node.flags & NodeFlags.JSDoc) &&
2257            !isIdentifierName(node)) {
2258
2259            // strict mode identifiers
2260            if (inStrictMode &&
2261                node.originalKeywordKind! >= SyntaxKind.FirstFutureReservedWord &&
2262                node.originalKeywordKind! <= SyntaxKind.LastFutureReservedWord) {
2263                file.bindDiagnostics.push(createDiagnosticForNode(node,
2264                    getStrictModeIdentifierMessage(node), declarationNameToString(node)));
2265            }
2266            else if (node.originalKeywordKind === SyntaxKind.AwaitKeyword) {
2267                if (isExternalModule(file) && isInTopLevelContext(node)) {
2268                    file.bindDiagnostics.push(createDiagnosticForNode(node,
2269                        Diagnostics.Identifier_expected_0_is_a_reserved_word_at_the_top_level_of_a_module,
2270                        declarationNameToString(node)));
2271                }
2272                else if (node.flags & NodeFlags.AwaitContext) {
2273                    file.bindDiagnostics.push(createDiagnosticForNode(node,
2274                        Diagnostics.Identifier_expected_0_is_a_reserved_word_that_cannot_be_used_here,
2275                        declarationNameToString(node)));
2276                }
2277            }
2278            else if (node.originalKeywordKind === SyntaxKind.YieldKeyword && node.flags & NodeFlags.YieldContext) {
2279                file.bindDiagnostics.push(createDiagnosticForNode(node,
2280                    Diagnostics.Identifier_expected_0_is_a_reserved_word_that_cannot_be_used_here,
2281                    declarationNameToString(node)));
2282            }
2283        }
2284    }
2285
2286    function getStrictModeIdentifierMessage(node: Node) {
2287        // Provide specialized messages to help the user understand why we think they're in
2288        // strict mode.
2289        if (getContainingClass(node)) {
2290            return Diagnostics.Identifier_expected_0_is_a_reserved_word_in_strict_mode_Class_definitions_are_automatically_in_strict_mode;
2291        }
2292
2293        if (file.externalModuleIndicator) {
2294            return Diagnostics.Identifier_expected_0_is_a_reserved_word_in_strict_mode_Modules_are_automatically_in_strict_mode;
2295        }
2296
2297        return Diagnostics.Identifier_expected_0_is_a_reserved_word_in_strict_mode;
2298    }
2299
2300    // The binder visits every node, so this is a good place to check for
2301    // the reserved private name (there is only one)
2302    function checkPrivateIdentifier(node: PrivateIdentifier) {
2303        if (node.escapedText === "#constructor") {
2304            // Report error only if there are no parse errors in file
2305            if (!file.parseDiagnostics.length) {
2306                file.bindDiagnostics.push(createDiagnosticForNode(node,
2307                    Diagnostics.constructor_is_a_reserved_word, declarationNameToString(node)));
2308            }
2309        }
2310    }
2311
2312    function checkStrictModeBinaryExpression(node: BinaryExpression) {
2313        if (inStrictMode && isLeftHandSideExpression(node.left) && isAssignmentOperator(node.operatorToken.kind)) {
2314            // ECMA 262 (Annex C) The identifier eval or arguments may not appear as the LeftHandSideExpression of an
2315            // Assignment operator(11.13) or of a PostfixExpression(11.3)
2316            checkStrictModeEvalOrArguments(node, node.left as Identifier);
2317        }
2318    }
2319
2320    function checkStrictModeCatchClause(node: CatchClause) {
2321        // It is a SyntaxError if a TryStatement with a Catch occurs within strict code and the Identifier of the
2322        // Catch production is eval or arguments
2323        if (inStrictMode && node.variableDeclaration) {
2324            checkStrictModeEvalOrArguments(node, node.variableDeclaration.name);
2325        }
2326    }
2327
2328    function checkStrictModeDeleteExpression(node: DeleteExpression) {
2329        // Grammar checking
2330        if (inStrictMode && node.expression.kind === SyntaxKind.Identifier) {
2331            // When a delete operator occurs within strict mode code, a SyntaxError is thrown if its
2332            // UnaryExpression is a direct reference to a variable, function argument, or function name
2333            const span = getErrorSpanForNode(file, node.expression);
2334            file.bindDiagnostics.push(createFileDiagnostic(file, span.start, span.length, Diagnostics.delete_cannot_be_called_on_an_identifier_in_strict_mode));
2335        }
2336    }
2337
2338    function isEvalOrArgumentsIdentifier(node: Node): boolean {
2339        return isIdentifier(node) && (node.escapedText === "eval" || node.escapedText === "arguments");
2340    }
2341
2342    function checkStrictModeEvalOrArguments(contextNode: Node, name: Node | undefined) {
2343        if (name && name.kind === SyntaxKind.Identifier) {
2344            const identifier = name as Identifier;
2345            if (isEvalOrArgumentsIdentifier(identifier)) {
2346                // We check first if the name is inside class declaration or class expression; if so give explicit message
2347                // otherwise report generic error message.
2348                const span = getErrorSpanForNode(file, name);
2349                file.bindDiagnostics.push(createFileDiagnostic(file, span.start, span.length,
2350                    getStrictModeEvalOrArgumentsMessage(contextNode), idText(identifier)));
2351            }
2352        }
2353    }
2354
2355    function getStrictModeEvalOrArgumentsMessage(node: Node) {
2356        // Provide specialized messages to help the user understand why we think they're in
2357        // strict mode.
2358        if (getContainingClass(node)) {
2359            return Diagnostics.Code_contained_in_a_class_is_evaluated_in_JavaScript_s_strict_mode_which_does_not_allow_this_use_of_0_For_more_information_see_https_Colon_Slash_Slashdeveloper_mozilla_org_Slashen_US_Slashdocs_SlashWeb_SlashJavaScript_SlashReference_SlashStrict_mode;
2360        }
2361
2362        if (file.externalModuleIndicator) {
2363            return Diagnostics.Invalid_use_of_0_Modules_are_automatically_in_strict_mode;
2364        }
2365
2366        return Diagnostics.Invalid_use_of_0_in_strict_mode;
2367    }
2368
2369    function checkStrictModeFunctionName(node: FunctionLikeDeclaration) {
2370        if (inStrictMode) {
2371            // It is a SyntaxError if the identifier eval or arguments appears within a FormalParameterList of a strict mode FunctionDeclaration or FunctionExpression (13.1))
2372            checkStrictModeEvalOrArguments(node, node.name);
2373        }
2374    }
2375
2376    function getStrictModeBlockScopeFunctionDeclarationMessage(node: Node) {
2377        // Provide specialized messages to help the user understand why we think they're in
2378        // strict mode.
2379        if (getContainingClass(node)) {
2380            return Diagnostics.Function_declarations_are_not_allowed_inside_blocks_in_strict_mode_when_targeting_ES3_or_ES5_Class_definitions_are_automatically_in_strict_mode;
2381        }
2382
2383        if (file.externalModuleIndicator) {
2384            return Diagnostics.Function_declarations_are_not_allowed_inside_blocks_in_strict_mode_when_targeting_ES3_or_ES5_Modules_are_automatically_in_strict_mode;
2385        }
2386
2387        return Diagnostics.Function_declarations_are_not_allowed_inside_blocks_in_strict_mode_when_targeting_ES3_or_ES5;
2388    }
2389
2390    function checkStrictModeFunctionDeclaration(node: FunctionDeclaration) {
2391        if (languageVersion < ScriptTarget.ES2015) {
2392            // Report error if function is not top level function declaration
2393            if (blockScopeContainer.kind !== SyntaxKind.SourceFile &&
2394                blockScopeContainer.kind !== SyntaxKind.ModuleDeclaration &&
2395                !isFunctionLikeOrClassStaticBlockDeclaration(blockScopeContainer)) {
2396                // We check first if the name is inside class declaration or class expression; if so give explicit message
2397                // otherwise report generic error message.
2398                const errorSpan = getErrorSpanForNode(file, node);
2399                file.bindDiagnostics.push(createFileDiagnostic(file, errorSpan.start, errorSpan.length,
2400                    getStrictModeBlockScopeFunctionDeclarationMessage(node)));
2401            }
2402        }
2403    }
2404
2405    function checkStrictModeNumericLiteral(node: NumericLiteral) {
2406        if (languageVersion < ScriptTarget.ES5 && inStrictMode && node.numericLiteralFlags & TokenFlags.Octal) {
2407            file.bindDiagnostics.push(createDiagnosticForNode(node, Diagnostics.Octal_literals_are_not_allowed_in_strict_mode));
2408        }
2409    }
2410
2411    function checkStrictModePostfixUnaryExpression(node: PostfixUnaryExpression) {
2412        // Grammar checking
2413        // The identifier eval or arguments may not appear as the LeftHandSideExpression of an
2414        // Assignment operator(11.13) or of a PostfixExpression(11.3) or as the UnaryExpression
2415        // operated upon by a Prefix Increment(11.4.4) or a Prefix Decrement(11.4.5) operator.
2416        if (inStrictMode) {
2417            checkStrictModeEvalOrArguments(node, node.operand as Identifier);
2418        }
2419    }
2420
2421    function checkStrictModePrefixUnaryExpression(node: PrefixUnaryExpression) {
2422        // Grammar checking
2423        if (inStrictMode) {
2424            if (node.operator === SyntaxKind.PlusPlusToken || node.operator === SyntaxKind.MinusMinusToken) {
2425                checkStrictModeEvalOrArguments(node, node.operand as Identifier);
2426            }
2427        }
2428    }
2429
2430    function checkStrictModeWithStatement(node: WithStatement) {
2431        // Grammar checking for withStatement
2432        if (inStrictMode) {
2433            errorOnFirstToken(node, Diagnostics.with_statements_are_not_allowed_in_strict_mode);
2434        }
2435    }
2436
2437    function checkStrictModeLabeledStatement(node: LabeledStatement) {
2438        // Grammar checking for labeledStatement
2439        if (inStrictMode && getEmitScriptTarget(options) >= ScriptTarget.ES2015) {
2440            if (isDeclarationStatement(node.statement) || isVariableStatement(node.statement)) {
2441                errorOnFirstToken(node.label, Diagnostics.A_label_is_not_allowed_here);
2442            }
2443        }
2444    }
2445
2446    function errorOnFirstToken(node: Node, message: DiagnosticMessage, arg0?: any, arg1?: any, arg2?: any) {
2447        const span = getSpanOfTokenAtPosition(file, node.pos);
2448        file.bindDiagnostics.push(createFileDiagnostic(file, span.start, span.length, message, arg0, arg1, arg2));
2449    }
2450
2451    function errorOrSuggestionOnNode(isError: boolean, node: Node, message: DiagnosticMessage): void {
2452        errorOrSuggestionOnRange(isError, node, node, message);
2453    }
2454
2455    function errorOrSuggestionOnRange(isError: boolean, startNode: Node, endNode: Node, message: DiagnosticMessage): void {
2456        addErrorOrSuggestionDiagnostic(isError, { pos: getTokenPosOfNode(startNode, file), end: endNode.end }, message);
2457    }
2458
2459    function addErrorOrSuggestionDiagnostic(isError: boolean, range: TextRange, message: DiagnosticMessage): void {
2460        const diag = createFileDiagnostic(file, range.pos, range.end - range.pos, message);
2461        if (isError) {
2462            file.bindDiagnostics.push(diag);
2463        }
2464        else {
2465            file.bindSuggestionDiagnostics = append(file.bindSuggestionDiagnostics, { ...diag, category: DiagnosticCategory.Suggestion });
2466        }
2467    }
2468
2469    function bind(node: Node | undefined): void {
2470        if (!node) {
2471            return;
2472        }
2473        setParent(node, parent);
2474        if (tracing) (node as TracingNode).tracingPath = file.path;
2475        const saveInStrictMode = inStrictMode;
2476
2477        // Even though in the AST the jsdoc @typedef node belongs to the current node,
2478        // its symbol might be in the same scope with the current node's symbol. Consider:
2479        //
2480        //     /** @typedef {string | number} MyType */
2481        //     function foo();
2482        //
2483        // Here the current node is "foo", which is a container, but the scope of "MyType" should
2484        // not be inside "foo". Therefore we always bind @typedef before bind the parent node,
2485        // and skip binding this tag later when binding all the other jsdoc tags.
2486
2487        // First we bind declaration nodes to a symbol if possible. We'll both create a symbol
2488        // and then potentially add the symbol to an appropriate symbol table. Possible
2489        // destination symbol tables are:
2490        //
2491        //  1) The 'exports' table of the current container's symbol.
2492        //  2) The 'members' table of the current container's symbol.
2493        //  3) The 'locals' table of the current container.
2494        //
2495        // However, not all symbols will end up in any of these tables. 'Anonymous' symbols
2496        // (like TypeLiterals for example) will not be put in any table.
2497        bindWorker(node);
2498        // Then we recurse into the children of the node to bind them as well. For certain
2499        // symbols we do specialized work when we recurse. For example, we'll keep track of
2500        // the current 'container' node when it changes. This helps us know which symbol table
2501        // a local should go into for example. Since terminal nodes are known not to have
2502        // children, as an optimization we don't process those.
2503        if (node.kind > SyntaxKind.LastToken) {
2504            const saveParent = parent;
2505            parent = node;
2506            const containerFlags = getContainerFlags(node);
2507            if (containerFlags === ContainerFlags.None) {
2508                bindChildren(node);
2509            }
2510            else {
2511                bindContainer(node, containerFlags);
2512            }
2513            parent = saveParent;
2514        }
2515        else {
2516            const saveParent = parent;
2517            if (node.kind === SyntaxKind.EndOfFileToken) parent = node;
2518            bindJSDoc(node);
2519            parent = saveParent;
2520        }
2521        inStrictMode = saveInStrictMode;
2522    }
2523
2524    function bindJSDoc(node: Node) {
2525        if (hasJSDocNodes(node)) {
2526            if (isInJSFile(node)) {
2527                for (const j of node.jsDoc!) {
2528                    bind(j);
2529                }
2530            }
2531            else {
2532                for (const j of node.jsDoc!) {
2533                    setParent(j, node);
2534                    setParentRecursive(j, /*incremental*/ false);
2535                }
2536            }
2537        }
2538    }
2539
2540    function updateStrictModeStatementList(statements: NodeArray<Statement>) {
2541        if (!inStrictMode) {
2542            for (const statement of statements) {
2543                if (!isPrologueDirective(statement)) {
2544                    return;
2545                }
2546
2547                if (isUseStrictPrologueDirective(statement as ExpressionStatement)) {
2548                    inStrictMode = true;
2549                    return;
2550                }
2551            }
2552        }
2553    }
2554
2555    /// Should be called only on prologue directives (isPrologueDirective(node) should be true)
2556    function isUseStrictPrologueDirective(node: ExpressionStatement): boolean {
2557        const nodeText = getSourceTextOfNodeFromSourceFile(file, node.expression);
2558
2559        // Note: the node text must be exactly "use strict" or 'use strict'.  It is not ok for the
2560        // string to contain unicode escapes (as per ES5).
2561        return nodeText === '"use strict"' || nodeText === "'use strict'";
2562    }
2563
2564    function bindWorker(node: Node) {
2565        switch (node.kind) {
2566            /* Strict mode checks */
2567            case SyntaxKind.Identifier:
2568                // for typedef type names with namespaces, bind the new jsdoc type symbol here
2569                // because it requires all containing namespaces to be in effect, namely the
2570                // current "blockScopeContainer" needs to be set to its immediate namespace parent.
2571                if ((node as Identifier).isInJSDocNamespace) {
2572                    let parentNode = node.parent;
2573                    while (parentNode && !isJSDocTypeAlias(parentNode)) {
2574                        parentNode = parentNode.parent;
2575                    }
2576                    bindBlockScopedDeclaration(parentNode as Declaration, SymbolFlags.TypeAlias, SymbolFlags.TypeAliasExcludes);
2577                    break;
2578                }
2579                // falls through
2580            case SyntaxKind.ThisKeyword:
2581                if (currentFlow && (isExpression(node) || parent.kind === SyntaxKind.ShorthandPropertyAssignment)) {
2582                    node.flowNode = currentFlow;
2583                }
2584                return checkContextualIdentifier(node as Identifier);
2585            case SyntaxKind.QualifiedName:
2586                if (currentFlow && isPartOfTypeQuery(node)) {
2587                    node.flowNode = currentFlow;
2588                }
2589                break;
2590            case SyntaxKind.MetaProperty:
2591            case SyntaxKind.SuperKeyword:
2592                node.flowNode = currentFlow;
2593                break;
2594            case SyntaxKind.PrivateIdentifier:
2595                return checkPrivateIdentifier(node as PrivateIdentifier);
2596            case SyntaxKind.PropertyAccessExpression:
2597            case SyntaxKind.ElementAccessExpression:
2598                const expr = node as PropertyAccessExpression | ElementAccessExpression;
2599                if (currentFlow && isNarrowableReference(expr)) {
2600                    expr.flowNode = currentFlow;
2601                }
2602                if (isSpecialPropertyDeclaration(expr)) {
2603                    bindSpecialPropertyDeclaration(expr);
2604                }
2605                if (isInJSFile(expr) &&
2606                    file.commonJsModuleIndicator &&
2607                    isModuleExportsAccessExpression(expr) &&
2608                    !lookupSymbolForName(blockScopeContainer, "module" as __String)) {
2609                    declareSymbol(file.locals!, /*parent*/ undefined, expr.expression,
2610                        SymbolFlags.FunctionScopedVariable | SymbolFlags.ModuleExports, SymbolFlags.FunctionScopedVariableExcludes);
2611                }
2612                break;
2613            case SyntaxKind.BinaryExpression:
2614                const specialKind = getAssignmentDeclarationKind(node as BinaryExpression);
2615                switch (specialKind) {
2616                    case AssignmentDeclarationKind.ExportsProperty:
2617                        bindExportsPropertyAssignment(node as BindableStaticPropertyAssignmentExpression);
2618                        break;
2619                    case AssignmentDeclarationKind.ModuleExports:
2620                        bindModuleExportsAssignment(node as BindablePropertyAssignmentExpression);
2621                        break;
2622                    case AssignmentDeclarationKind.PrototypeProperty:
2623                        bindPrototypePropertyAssignment((node as BindableStaticPropertyAssignmentExpression).left, node);
2624                        break;
2625                    case AssignmentDeclarationKind.Prototype:
2626                        bindPrototypeAssignment(node as BindableStaticPropertyAssignmentExpression);
2627                        break;
2628                    case AssignmentDeclarationKind.ThisProperty:
2629                        bindThisPropertyAssignment(node as BindablePropertyAssignmentExpression);
2630                        break;
2631                    case AssignmentDeclarationKind.Property:
2632                        const expression = ((node as BinaryExpression).left as AccessExpression).expression;
2633                        if (isInJSFile(node) && isIdentifier(expression)) {
2634                            const symbol = lookupSymbolForName(blockScopeContainer, expression.escapedText);
2635                            if (isThisInitializedDeclaration(symbol?.valueDeclaration)) {
2636                                bindThisPropertyAssignment(node as BindablePropertyAssignmentExpression);
2637                                break;
2638                            }
2639                        }
2640                        bindSpecialPropertyAssignment(node as BindablePropertyAssignmentExpression);
2641                        break;
2642                    case AssignmentDeclarationKind.None:
2643                        // Nothing to do
2644                        break;
2645                    default:
2646                        Debug.fail("Unknown binary expression special property assignment kind");
2647                }
2648                return checkStrictModeBinaryExpression(node as BinaryExpression);
2649            case SyntaxKind.CatchClause:
2650                return checkStrictModeCatchClause(node as CatchClause);
2651            case SyntaxKind.DeleteExpression:
2652                return checkStrictModeDeleteExpression(node as DeleteExpression);
2653            case SyntaxKind.NumericLiteral:
2654                return checkStrictModeNumericLiteral(node as NumericLiteral);
2655            case SyntaxKind.PostfixUnaryExpression:
2656                return checkStrictModePostfixUnaryExpression(node as PostfixUnaryExpression);
2657            case SyntaxKind.PrefixUnaryExpression:
2658                return checkStrictModePrefixUnaryExpression(node as PrefixUnaryExpression);
2659            case SyntaxKind.WithStatement:
2660                return checkStrictModeWithStatement(node as WithStatement);
2661            case SyntaxKind.LabeledStatement:
2662                return checkStrictModeLabeledStatement(node as LabeledStatement);
2663            case SyntaxKind.ThisType:
2664                seenThisKeyword = true;
2665                return;
2666            case SyntaxKind.TypePredicate:
2667                break; // Binding the children will handle everything
2668            case SyntaxKind.TypeParameter:
2669                return bindTypeParameter(node as TypeParameterDeclaration);
2670            case SyntaxKind.Parameter:
2671                return bindParameter(node as ParameterDeclaration);
2672            case SyntaxKind.VariableDeclaration:
2673                return bindVariableDeclarationOrBindingElement(node as VariableDeclaration);
2674            case SyntaxKind.BindingElement:
2675                node.flowNode = currentFlow;
2676                return bindVariableDeclarationOrBindingElement(node as BindingElement);
2677            case SyntaxKind.PropertyDeclaration:
2678            case SyntaxKind.AnnotationPropertyDeclaration:
2679            case SyntaxKind.PropertySignature:
2680                return bindPropertyWorker(node as PropertyDeclaration | PropertySignature | AnnotationPropertyDeclaration);
2681            case SyntaxKind.PropertyAssignment:
2682            case SyntaxKind.ShorthandPropertyAssignment:
2683                return bindPropertyOrMethodOrAccessor(node as Declaration, SymbolFlags.Property, SymbolFlags.PropertyExcludes);
2684            case SyntaxKind.EnumMember:
2685                return bindPropertyOrMethodOrAccessor(node as Declaration, SymbolFlags.EnumMember, SymbolFlags.EnumMemberExcludes);
2686
2687            case SyntaxKind.CallSignature:
2688            case SyntaxKind.ConstructSignature:
2689            case SyntaxKind.IndexSignature:
2690                return declareSymbolAndAddToSymbolTable(node as Declaration, SymbolFlags.Signature, SymbolFlags.None);
2691            case SyntaxKind.MethodDeclaration:
2692            case SyntaxKind.MethodSignature:
2693                // If this is an ObjectLiteralExpression method, then it sits in the same space
2694                // as other properties in the object literal.  So we use SymbolFlags.PropertyExcludes
2695                // so that it will conflict with any other object literal members with the same
2696                // name.
2697                return bindPropertyOrMethodOrAccessor(node as Declaration, SymbolFlags.Method | ((node as MethodDeclaration).questionToken ? SymbolFlags.Optional : SymbolFlags.None),
2698                    isObjectLiteralMethod(node) ? SymbolFlags.PropertyExcludes : SymbolFlags.MethodExcludes);
2699            case SyntaxKind.FunctionDeclaration:
2700                return bindFunctionDeclaration(node as FunctionDeclaration);
2701            case SyntaxKind.Constructor:
2702                return declareSymbolAndAddToSymbolTable(node as Declaration, SymbolFlags.Constructor, /*symbolExcludes:*/ SymbolFlags.None);
2703            case SyntaxKind.GetAccessor:
2704                return bindPropertyOrMethodOrAccessor(node as Declaration, SymbolFlags.GetAccessor, SymbolFlags.GetAccessorExcludes);
2705            case SyntaxKind.SetAccessor:
2706                return bindPropertyOrMethodOrAccessor(node as Declaration, SymbolFlags.SetAccessor, SymbolFlags.SetAccessorExcludes);
2707            case SyntaxKind.FunctionType:
2708            case SyntaxKind.JSDocFunctionType:
2709            case SyntaxKind.JSDocSignature:
2710            case SyntaxKind.ConstructorType:
2711                return bindFunctionOrConstructorType(node as SignatureDeclaration | JSDocSignature);
2712            case SyntaxKind.TypeLiteral:
2713            case SyntaxKind.JSDocTypeLiteral:
2714            case SyntaxKind.MappedType:
2715                return bindAnonymousTypeWorker(node as TypeLiteralNode | MappedTypeNode | JSDocTypeLiteral);
2716            case SyntaxKind.JSDocClassTag:
2717                return bindJSDocClassTag(node as JSDocClassTag);
2718            case SyntaxKind.ObjectLiteralExpression:
2719                return bindObjectLiteralExpression(node as ObjectLiteralExpression);
2720            case SyntaxKind.FunctionExpression:
2721            case SyntaxKind.ArrowFunction:
2722                return bindFunctionExpression(node as FunctionExpression);
2723
2724            case SyntaxKind.CallExpression:
2725                const assignmentKind = getAssignmentDeclarationKind(node as CallExpression);
2726                switch (assignmentKind) {
2727                    case AssignmentDeclarationKind.ObjectDefinePropertyValue:
2728                        return bindObjectDefinePropertyAssignment(node as BindableObjectDefinePropertyCall);
2729                    case AssignmentDeclarationKind.ObjectDefinePropertyExports:
2730                        return bindObjectDefinePropertyExport(node as BindableObjectDefinePropertyCall);
2731                    case AssignmentDeclarationKind.ObjectDefinePrototypeProperty:
2732                        return bindObjectDefinePrototypeProperty(node as BindableObjectDefinePropertyCall);
2733                    case AssignmentDeclarationKind.None:
2734                        break; // Nothing to do
2735                    default:
2736                        return Debug.fail("Unknown call expression assignment declaration kind");
2737                }
2738                if (isInJSFile(node)) {
2739                    bindCallExpression(node as CallExpression);
2740                }
2741                break;
2742
2743            // Members of classes, interfaces, and modules
2744            case SyntaxKind.ClassExpression:
2745            case SyntaxKind.ClassDeclaration:
2746            case SyntaxKind.StructDeclaration:
2747                // All classes are automatically in strict mode in ES6.
2748                inStrictMode = true;
2749                return bindClassLikeDeclaration(node as ClassLikeDeclaration);
2750            case SyntaxKind.AnnotationDeclaration:
2751                return bindAnnotationDeclaration(node as AnnotationDeclaration);
2752            case SyntaxKind.InterfaceDeclaration:
2753                return bindBlockScopedDeclaration(node as Declaration, SymbolFlags.Interface, SymbolFlags.InterfaceExcludes);
2754            case SyntaxKind.TypeAliasDeclaration:
2755                return bindBlockScopedDeclaration(node as Declaration, SymbolFlags.TypeAlias, SymbolFlags.TypeAliasExcludes);
2756            case SyntaxKind.EnumDeclaration:
2757                return bindEnumDeclaration(node as EnumDeclaration);
2758            case SyntaxKind.ModuleDeclaration:
2759                return bindModuleDeclaration(node as ModuleDeclaration);
2760            // Jsx-attributes
2761            case SyntaxKind.JsxAttributes:
2762                return bindJsxAttributes(node as JsxAttributes);
2763            case SyntaxKind.JsxAttribute:
2764                return bindJsxAttribute(node as JsxAttribute, SymbolFlags.Property, SymbolFlags.PropertyExcludes);
2765
2766            // Imports and exports
2767            case SyntaxKind.ImportEqualsDeclaration:
2768            case SyntaxKind.NamespaceImport:
2769            case SyntaxKind.ImportSpecifier:
2770            case SyntaxKind.ExportSpecifier:
2771                return declareSymbolAndAddToSymbolTable(node as Declaration, SymbolFlags.Alias, SymbolFlags.AliasExcludes);
2772            case SyntaxKind.NamespaceExportDeclaration:
2773                return bindNamespaceExportDeclaration(node as NamespaceExportDeclaration);
2774            case SyntaxKind.ImportClause:
2775                return bindImportClause(node as ImportClause);
2776            case SyntaxKind.ExportDeclaration:
2777                return bindExportDeclaration(node as ExportDeclaration);
2778            case SyntaxKind.ExportAssignment:
2779                return bindExportAssignment(node as ExportAssignment);
2780            case SyntaxKind.SourceFile:
2781                updateStrictModeStatementList((node as SourceFile).statements);
2782                return bindSourceFileIfExternalModule();
2783            case SyntaxKind.Block:
2784                if (!isFunctionLikeOrClassStaticBlockDeclaration(node.parent)) {
2785                    return;
2786                }
2787                // falls through
2788            case SyntaxKind.ModuleBlock:
2789                return updateStrictModeStatementList((node as Block | ModuleBlock).statements);
2790
2791            case SyntaxKind.JSDocParameterTag:
2792                if (node.parent.kind === SyntaxKind.JSDocSignature) {
2793                    return bindParameter(node as JSDocParameterTag);
2794                }
2795                if (node.parent.kind !== SyntaxKind.JSDocTypeLiteral) {
2796                    break;
2797                }
2798                // falls through
2799            case SyntaxKind.JSDocPropertyTag:
2800                const propTag = node as JSDocPropertyLikeTag;
2801                const flags = propTag.isBracketed || propTag.typeExpression && propTag.typeExpression.type.kind === SyntaxKind.JSDocOptionalType ?
2802                    SymbolFlags.Property | SymbolFlags.Optional :
2803                    SymbolFlags.Property;
2804                return declareSymbolAndAddToSymbolTable(propTag, flags, SymbolFlags.PropertyExcludes);
2805            case SyntaxKind.JSDocTypedefTag:
2806            case SyntaxKind.JSDocCallbackTag:
2807            case SyntaxKind.JSDocEnumTag:
2808                return (delayedTypeAliases || (delayedTypeAliases = [])).push(node as JSDocTypedefTag | JSDocCallbackTag | JSDocEnumTag);
2809        }
2810    }
2811
2812    function bindPropertyWorker(node: PropertyDeclaration | PropertySignature | AnnotationPropertyDeclaration) {
2813        const isAutoAccessor = isAutoAccessorPropertyDeclaration(node);
2814        const includes = isAutoAccessor ? SymbolFlags.Accessor : SymbolFlags.Property;
2815        const excludes = isAutoAccessor ? SymbolFlags.AccessorExcludes : SymbolFlags.PropertyExcludes;
2816        const isOptional = (!isAnnotationPropertyDeclaration(node) && node.questionToken ? SymbolFlags.Optional : SymbolFlags.None);
2817        const annotationPropHasDefaultValue = (isAnnotationPropertyDeclaration(node) && node.initializer !== undefined) ?
2818            SymbolFlags.Optional : SymbolFlags.None;
2819        return bindPropertyOrMethodOrAccessor(node, includes | isOptional | annotationPropHasDefaultValue, excludes);
2820    }
2821
2822    function bindAnonymousTypeWorker(node: TypeLiteralNode | MappedTypeNode | JSDocTypeLiteral) {
2823        return bindAnonymousDeclaration(node as Declaration, SymbolFlags.TypeLiteral, InternalSymbolName.Type);
2824    }
2825
2826    function bindSourceFileIfExternalModule() {
2827        setExportContextFlag(file);
2828        if (isExternalModule(file)) {
2829            bindSourceFileAsExternalModule();
2830        }
2831        else if (isJsonSourceFile(file)) {
2832            bindSourceFileAsExternalModule();
2833            // Create symbol equivalent for the module.exports = {}
2834            const originalSymbol = file.symbol;
2835            declareSymbol(file.symbol.exports!, file.symbol, file, SymbolFlags.Property, SymbolFlags.All);
2836            file.symbol = originalSymbol;
2837        }
2838    }
2839
2840    function bindSourceFileAsExternalModule() {
2841        bindAnonymousDeclaration(file, SymbolFlags.ValueModule, `"${removeFileExtension(file.fileName)}"` as __String);
2842    }
2843
2844    function bindExportAssignment(node: ExportAssignment) {
2845        if (!container.symbol || !container.symbol.exports) {
2846            // Incorrect export assignment in some sort of block construct
2847            bindAnonymousDeclaration(node, SymbolFlags.Value, getDeclarationName(node)!);
2848        }
2849        else {
2850            const flags = exportAssignmentIsAlias(node)
2851                // An export default clause with an EntityNameExpression or a class expression exports all meanings of that identifier or expression;
2852                ? SymbolFlags.Alias
2853                // An export default clause with any other expression exports a value
2854                : SymbolFlags.Property;
2855            // If there is an `export default x;` alias declaration, can't `export default` anything else.
2856            // (In contrast, you can still have `export default function f() {}` and `export default interface I {}`.)
2857            const symbol = declareSymbol(container.symbol.exports, container.symbol, node, flags, SymbolFlags.All);
2858
2859            if (node.isExportEquals) {
2860                // Will be an error later, since the module already has other exports. Just make sure this has a valueDeclaration set.
2861                setValueDeclaration(symbol, node);
2862            }
2863        }
2864    }
2865
2866    function bindNamespaceExportDeclaration(node: NamespaceExportDeclaration) {
2867        if (some(node.modifiers)) {
2868            file.bindDiagnostics.push(createDiagnosticForNode(node, Diagnostics.Modifiers_cannot_appear_here));
2869        }
2870        const diag = !isSourceFile(node.parent) ? Diagnostics.Global_module_exports_may_only_appear_at_top_level
2871            : !isExternalModule(node.parent) ? Diagnostics.Global_module_exports_may_only_appear_in_module_files
2872            : !node.parent.isDeclarationFile ? Diagnostics.Global_module_exports_may_only_appear_in_declaration_files
2873            : undefined;
2874        if (diag) {
2875            file.bindDiagnostics.push(createDiagnosticForNode(node, diag));
2876        }
2877        else {
2878            file.symbol.globalExports = file.symbol.globalExports || createSymbolTable();
2879            declareSymbol(file.symbol.globalExports, file.symbol, node, SymbolFlags.Alias, SymbolFlags.AliasExcludes);
2880        }
2881    }
2882
2883    function bindExportDeclaration(node: ExportDeclaration) {
2884        if (!container.symbol || !container.symbol.exports) {
2885            // Export * in some sort of block construct
2886            bindAnonymousDeclaration(node, SymbolFlags.ExportStar, getDeclarationName(node)!);
2887        }
2888        else if (!node.exportClause) {
2889            // All export * declarations are collected in an __export symbol
2890            declareSymbol(container.symbol.exports, container.symbol, node, SymbolFlags.ExportStar, SymbolFlags.None);
2891        }
2892        else if (isNamespaceExport(node.exportClause)) {
2893            // declareSymbol walks up parents to find name text, parent _must_ be set
2894            // but won't be set by the normal binder walk until `bindChildren` later on.
2895            setParent(node.exportClause, node);
2896            declareSymbol(container.symbol.exports, container.symbol, node.exportClause, SymbolFlags.Alias, SymbolFlags.AliasExcludes);
2897        }
2898    }
2899
2900    function bindImportClause(node: ImportClause) {
2901        if (node.name) {
2902            declareSymbolAndAddToSymbolTable(node, SymbolFlags.Alias, SymbolFlags.AliasExcludes);
2903        }
2904    }
2905
2906    function setCommonJsModuleIndicator(node: Node) {
2907        if (file.externalModuleIndicator && file.externalModuleIndicator !== true) {
2908            return false;
2909        }
2910        if (!file.commonJsModuleIndicator) {
2911            file.commonJsModuleIndicator = node;
2912            if (!file.externalModuleIndicator) {
2913                bindSourceFileAsExternalModule();
2914            }
2915        }
2916        return true;
2917    }
2918
2919    function bindObjectDefinePropertyExport(node: BindableObjectDefinePropertyCall) {
2920        if (!setCommonJsModuleIndicator(node)) {
2921            return;
2922        }
2923        const symbol = forEachIdentifierInEntityName(node.arguments[0], /*parent*/ undefined, (id, symbol) => {
2924            if (symbol) {
2925                addDeclarationToSymbol(symbol, id, SymbolFlags.Module | SymbolFlags.Assignment);
2926            }
2927            return symbol;
2928        });
2929        if (symbol) {
2930            const flags = SymbolFlags.Property | SymbolFlags.ExportValue;
2931            declareSymbol(symbol.exports!, symbol, node, flags, SymbolFlags.None);
2932        }
2933    }
2934
2935    function bindExportsPropertyAssignment(node: BindableStaticPropertyAssignmentExpression) {
2936        // When we create a property via 'exports.foo = bar', the 'exports.foo' property access
2937        // expression is the declaration
2938        if (!setCommonJsModuleIndicator(node)) {
2939            return;
2940        }
2941        const symbol = forEachIdentifierInEntityName(node.left.expression, /*parent*/ undefined, (id, symbol) => {
2942            if (symbol) {
2943                addDeclarationToSymbol(symbol, id, SymbolFlags.Module | SymbolFlags.Assignment);
2944            }
2945            return symbol;
2946        });
2947        if (symbol) {
2948            const isAlias = isAliasableExpression(node.right) && (isExportsIdentifier(node.left.expression) || isModuleExportsAccessExpression(node.left.expression));
2949            const flags = isAlias ? SymbolFlags.Alias : SymbolFlags.Property | SymbolFlags.ExportValue;
2950            setParent(node.left, node);
2951            declareSymbol(symbol.exports!, symbol, node.left, flags, SymbolFlags.None);
2952        }
2953    }
2954
2955    function bindModuleExportsAssignment(node: BindablePropertyAssignmentExpression) {
2956        // A common practice in node modules is to set 'export = module.exports = {}', this ensures that 'exports'
2957        // is still pointing to 'module.exports'.
2958        // We do not want to consider this as 'export=' since a module can have only one of these.
2959        // Similarly we do not want to treat 'module.exports = exports' as an 'export='.
2960        if (!setCommonJsModuleIndicator(node)) {
2961            return;
2962        }
2963        const assignedExpression = getRightMostAssignedExpression(node.right);
2964        if (isEmptyObjectLiteral(assignedExpression) || container === file && isExportsOrModuleExportsOrAlias(file, assignedExpression)) {
2965            return;
2966        }
2967
2968        if (isObjectLiteralExpression(assignedExpression) && every(assignedExpression.properties, isShorthandPropertyAssignment)) {
2969            forEach(assignedExpression.properties, bindExportAssignedObjectMemberAlias);
2970            return;
2971        }
2972
2973        // 'module.exports = expr' assignment
2974        const flags = exportAssignmentIsAlias(node)
2975            ? SymbolFlags.Alias // An export= with an EntityNameExpression or a ClassExpression exports all meanings of that identifier or class
2976            : SymbolFlags.Property | SymbolFlags.ExportValue | SymbolFlags.ValueModule;
2977        const symbol = declareSymbol(file.symbol.exports!, file.symbol, node, flags | SymbolFlags.Assignment, SymbolFlags.None);
2978        setValueDeclaration(symbol, node);
2979    }
2980
2981    function bindExportAssignedObjectMemberAlias(node: ShorthandPropertyAssignment) {
2982        declareSymbol(file.symbol.exports!, file.symbol, node, SymbolFlags.Alias | SymbolFlags.Assignment, SymbolFlags.None);
2983    }
2984
2985    function bindThisPropertyAssignment(node: BindablePropertyAssignmentExpression | PropertyAccessExpression | LiteralLikeElementAccessExpression) {
2986        Debug.assert(isInJSFile(node));
2987        // private identifiers *must* be declared (even in JS files)
2988        const hasPrivateIdentifier = (isBinaryExpression(node) && isPropertyAccessExpression(node.left) && isPrivateIdentifier(node.left.name))
2989            || (isPropertyAccessExpression(node) && isPrivateIdentifier(node.name));
2990        if (hasPrivateIdentifier) {
2991            return;
2992        }
2993        const thisContainer = getThisContainer(node, /*includeArrowFunctions*/ false);
2994        switch (thisContainer.kind) {
2995            case SyntaxKind.FunctionDeclaration:
2996            case SyntaxKind.FunctionExpression:
2997                let constructorSymbol: Symbol | undefined = thisContainer.symbol;
2998                // For `f.prototype.m = function() { this.x = 0; }`, `this.x = 0` should modify `f`'s members, not the function expression.
2999                if (isBinaryExpression(thisContainer.parent) && thisContainer.parent.operatorToken.kind === SyntaxKind.EqualsToken) {
3000                    const l = thisContainer.parent.left;
3001                    if (isBindableStaticAccessExpression(l) && isPrototypeAccess(l.expression)) {
3002                        constructorSymbol = lookupSymbolForPropertyAccess(l.expression.expression, thisParentContainer);
3003                    }
3004                }
3005
3006                if (constructorSymbol && constructorSymbol.valueDeclaration) {
3007                    // Declare a 'member' if the container is an ES5 class or ES6 constructor
3008                    constructorSymbol.members = constructorSymbol.members || createSymbolTable();
3009                    // It's acceptable for multiple 'this' assignments of the same identifier to occur
3010                    if (hasDynamicName(node)) {
3011                        bindDynamicallyNamedThisPropertyAssignment(node, constructorSymbol, constructorSymbol.members);
3012                    }
3013                    else {
3014                        declareSymbol(constructorSymbol.members, constructorSymbol, node, SymbolFlags.Property | SymbolFlags.Assignment, SymbolFlags.PropertyExcludes & ~SymbolFlags.Property);
3015                    }
3016                    addDeclarationToSymbol(constructorSymbol, constructorSymbol.valueDeclaration, SymbolFlags.Class);
3017                }
3018                break;
3019
3020            case SyntaxKind.Constructor:
3021            case SyntaxKind.PropertyDeclaration:
3022            case SyntaxKind.AnnotationPropertyDeclaration:
3023            case SyntaxKind.MethodDeclaration:
3024            case SyntaxKind.GetAccessor:
3025            case SyntaxKind.SetAccessor:
3026            case SyntaxKind.ClassStaticBlockDeclaration:
3027                // this.foo assignment in a JavaScript class
3028                // Bind this property to the containing class
3029                const containingClass = thisContainer.parent;
3030                const symbolTable = isStatic(thisContainer) ? containingClass.symbol.exports! : containingClass.symbol.members!;
3031                if (hasDynamicName(node)) {
3032                    bindDynamicallyNamedThisPropertyAssignment(node, containingClass.symbol, symbolTable);
3033                }
3034                else {
3035                    declareSymbol(symbolTable, containingClass.symbol, node, SymbolFlags.Property | SymbolFlags.Assignment, SymbolFlags.None, /*isReplaceableByMethod*/ true);
3036                }
3037                break;
3038            case SyntaxKind.SourceFile:
3039                // this.property = assignment in a source file -- declare symbol in exports for a module, in locals for a script
3040                if (hasDynamicName(node)) {
3041                    break;
3042                }
3043                else if ((thisContainer as SourceFile).commonJsModuleIndicator) {
3044                    declareSymbol(thisContainer.symbol.exports!, thisContainer.symbol, node, SymbolFlags.Property | SymbolFlags.ExportValue, SymbolFlags.None);
3045                }
3046                else {
3047                    declareSymbolAndAddToSymbolTable(node, SymbolFlags.FunctionScopedVariable, SymbolFlags.FunctionScopedVariableExcludes);
3048                }
3049                break;
3050
3051            default:
3052                Debug.failBadSyntaxKind(thisContainer);
3053        }
3054    }
3055
3056    function bindDynamicallyNamedThisPropertyAssignment(node: BinaryExpression | DynamicNamedDeclaration, symbol: Symbol, symbolTable: SymbolTable) {
3057        declareSymbol(symbolTable, symbol, node, SymbolFlags.Property, SymbolFlags.None, /*isReplaceableByMethod*/ true, /*isComputedName*/ true);
3058        addLateBoundAssignmentDeclarationToSymbol(node, symbol);
3059    }
3060
3061    function addLateBoundAssignmentDeclarationToSymbol(node: BinaryExpression | DynamicNamedDeclaration, symbol: Symbol | undefined) {
3062        if (symbol) {
3063            (symbol.assignmentDeclarationMembers || (symbol.assignmentDeclarationMembers = new Map())).set(getNodeId(node), node);
3064        }
3065    }
3066
3067    function bindSpecialPropertyDeclaration(node: PropertyAccessExpression | LiteralLikeElementAccessExpression) {
3068        if (node.expression.kind === SyntaxKind.ThisKeyword) {
3069            bindThisPropertyAssignment(node);
3070        }
3071        else if (isBindableStaticAccessExpression(node) && node.parent.parent.kind === SyntaxKind.SourceFile) {
3072            if (isPrototypeAccess(node.expression)) {
3073                bindPrototypePropertyAssignment(node, node.parent);
3074            }
3075            else {
3076                bindStaticPropertyAssignment(node);
3077            }
3078        }
3079    }
3080
3081    /** For `x.prototype = { p, ... }`, declare members p,... if `x` is function/class/{}, or not declared. */
3082    function bindPrototypeAssignment(node: BindableStaticPropertyAssignmentExpression) {
3083        setParent(node.left, node);
3084        setParent(node.right, node);
3085        bindPropertyAssignment(node.left.expression, node.left, /*isPrototypeProperty*/ false, /*containerIsClass*/ true);
3086    }
3087
3088    function bindObjectDefinePrototypeProperty(node: BindableObjectDefinePropertyCall) {
3089        const namespaceSymbol = lookupSymbolForPropertyAccess((node.arguments[0] as PropertyAccessExpression).expression as EntityNameExpression);
3090        if (namespaceSymbol && namespaceSymbol.valueDeclaration) {
3091            // Ensure the namespace symbol becomes class-like
3092            addDeclarationToSymbol(namespaceSymbol, namespaceSymbol.valueDeclaration, SymbolFlags.Class);
3093        }
3094        bindPotentiallyNewExpandoMemberToNamespace(node, namespaceSymbol, /*isPrototypeProperty*/ true);
3095    }
3096
3097    /**
3098     * For `x.prototype.y = z`, declare a member `y` on `x` if `x` is a function or class, or not declared.
3099     * Note that jsdoc preceding an ExpressionStatement like `x.prototype.y;` is also treated as a declaration.
3100     */
3101    function bindPrototypePropertyAssignment(lhs: BindableStaticAccessExpression, parent: Node) {
3102        // Look up the function in the local scope, since prototype assignments should
3103        // follow the function declaration
3104        const classPrototype = lhs.expression as BindableStaticAccessExpression;
3105        const constructorFunction = classPrototype.expression;
3106
3107        // Fix up parent pointers since we're going to use these nodes before we bind into them
3108        setParent(constructorFunction, classPrototype);
3109        setParent(classPrototype, lhs);
3110        setParent(lhs, parent);
3111
3112        bindPropertyAssignment(constructorFunction, lhs, /*isPrototypeProperty*/ true, /*containerIsClass*/ true);
3113    }
3114
3115    function bindObjectDefinePropertyAssignment(node: BindableObjectDefinePropertyCall) {
3116        let namespaceSymbol = lookupSymbolForPropertyAccess(node.arguments[0]);
3117        const isToplevel = node.parent.parent.kind === SyntaxKind.SourceFile;
3118        namespaceSymbol = bindPotentiallyMissingNamespaces(namespaceSymbol, node.arguments[0], isToplevel, /*isPrototypeProperty*/ false, /*containerIsClass*/ false);
3119        bindPotentiallyNewExpandoMemberToNamespace(node, namespaceSymbol, /*isPrototypeProperty*/ false);
3120    }
3121
3122    function bindSpecialPropertyAssignment(node: BindablePropertyAssignmentExpression) {
3123        // Class declarations in Typescript do not allow property declarations
3124        const parentSymbol = lookupSymbolForPropertyAccess(node.left.expression, container) || lookupSymbolForPropertyAccess(node.left.expression, blockScopeContainer) ;
3125        if (!isInJSFile(node) && !isFunctionSymbol(parentSymbol)) {
3126            return;
3127        }
3128        const rootExpr = getLeftmostAccessExpression(node.left);
3129        if (isIdentifier(rootExpr) && lookupSymbolForName(container, rootExpr.escapedText)?.flags! & SymbolFlags.Alias) {
3130            return;
3131        }
3132        // Fix up parent pointers since we're going to use these nodes before we bind into them
3133        setParent(node.left, node);
3134        setParent(node.right, node);
3135        if (isIdentifier(node.left.expression) && container === file && isExportsOrModuleExportsOrAlias(file, node.left.expression)) {
3136            // This can be an alias for the 'exports' or 'module.exports' names, e.g.
3137            //    var util = module.exports;
3138            //    util.property = function ...
3139            bindExportsPropertyAssignment(node as BindableStaticPropertyAssignmentExpression);
3140        }
3141        else if (hasDynamicName(node)) {
3142            bindAnonymousDeclaration(node, SymbolFlags.Property | SymbolFlags.Assignment, InternalSymbolName.Computed);
3143            const sym = bindPotentiallyMissingNamespaces(parentSymbol, node.left.expression, isTopLevelNamespaceAssignment(node.left), /*isPrototype*/ false, /*containerIsClass*/ false);
3144            addLateBoundAssignmentDeclarationToSymbol(node, sym);
3145        }
3146        else {
3147            bindStaticPropertyAssignment(cast(node.left, isBindableStaticNameExpression));
3148        }
3149    }
3150
3151    /**
3152     * For nodes like `x.y = z`, declare a member 'y' on 'x' if x is a function (or IIFE) or class or {}, or not declared.
3153     * Also works for expression statements preceded by JSDoc, like / ** @type number * / x.y;
3154     */
3155    function bindStaticPropertyAssignment(node: BindableStaticNameExpression) {
3156        Debug.assert(!isIdentifier(node));
3157        setParent(node.expression, node);
3158        bindPropertyAssignment(node.expression, node, /*isPrototypeProperty*/ false, /*containerIsClass*/ false);
3159    }
3160
3161    function bindPotentiallyMissingNamespaces(namespaceSymbol: Symbol | undefined, entityName: BindableStaticNameExpression, isToplevel: boolean, isPrototypeProperty: boolean, containerIsClass: boolean) {
3162        if (namespaceSymbol?.flags! & SymbolFlags.Alias) {
3163            return namespaceSymbol;
3164        }
3165        if (isToplevel && !isPrototypeProperty) {
3166            // make symbols or add declarations for intermediate containers
3167            const flags = SymbolFlags.Module | SymbolFlags.Assignment;
3168            const excludeFlags = SymbolFlags.ValueModuleExcludes & ~SymbolFlags.Assignment;
3169            namespaceSymbol = forEachIdentifierInEntityName(entityName, namespaceSymbol, (id, symbol, parent) => {
3170                if (symbol) {
3171                    addDeclarationToSymbol(symbol, id, flags);
3172                    return symbol;
3173                }
3174                else {
3175                    const table = parent ? parent.exports! :
3176                        file.jsGlobalAugmentations || (file.jsGlobalAugmentations = createSymbolTable());
3177                    return declareSymbol(table, parent, id, flags, excludeFlags);
3178                }
3179            });
3180        }
3181        if (containerIsClass && namespaceSymbol && namespaceSymbol.valueDeclaration) {
3182            addDeclarationToSymbol(namespaceSymbol, namespaceSymbol.valueDeclaration, SymbolFlags.Class);
3183        }
3184        return namespaceSymbol;
3185    }
3186
3187    function bindPotentiallyNewExpandoMemberToNamespace(declaration: BindableStaticAccessExpression | CallExpression, namespaceSymbol: Symbol | undefined, isPrototypeProperty: boolean) {
3188        if (!namespaceSymbol || !isExpandoSymbol(namespaceSymbol)) {
3189            return;
3190        }
3191
3192        // Set up the members collection if it doesn't exist already
3193        const symbolTable = isPrototypeProperty ?
3194            (namespaceSymbol.members || (namespaceSymbol.members = createSymbolTable())) :
3195            (namespaceSymbol.exports || (namespaceSymbol.exports = createSymbolTable()));
3196
3197        let includes = SymbolFlags.None;
3198        let excludes = SymbolFlags.None;
3199        // Method-like
3200        if (isFunctionLikeDeclaration(getAssignedExpandoInitializer(declaration)!)) {
3201            includes = SymbolFlags.Method;
3202            excludes = SymbolFlags.MethodExcludes;
3203        }
3204        // Maybe accessor-like
3205        else if (isCallExpression(declaration) && isBindableObjectDefinePropertyCall(declaration)) {
3206            if (some(declaration.arguments[2].properties, p => {
3207                const id = getNameOfDeclaration(p);
3208                return !!id && isIdentifier(id) && idText(id) === "set";
3209            })) {
3210                // We mix in `SymbolFLags.Property` so in the checker `getTypeOfVariableParameterOrProperty` is used for this
3211                // symbol, instead of `getTypeOfAccessor` (which will assert as there is no real accessor declaration)
3212                includes |= SymbolFlags.SetAccessor | SymbolFlags.Property;
3213                excludes |= SymbolFlags.SetAccessorExcludes;
3214            }
3215            if (some(declaration.arguments[2].properties, p => {
3216                const id = getNameOfDeclaration(p);
3217                return !!id && isIdentifier(id) && idText(id) === "get";
3218            })) {
3219                includes |= SymbolFlags.GetAccessor | SymbolFlags.Property;
3220                excludes |= SymbolFlags.GetAccessorExcludes;
3221            }
3222        }
3223
3224        if (includes === SymbolFlags.None) {
3225            includes = SymbolFlags.Property;
3226            excludes = SymbolFlags.PropertyExcludes;
3227        }
3228
3229        declareSymbol(symbolTable, namespaceSymbol, declaration, includes | SymbolFlags.Assignment, excludes & ~SymbolFlags.Assignment);
3230    }
3231
3232    function isTopLevelNamespaceAssignment(propertyAccess: BindableAccessExpression) {
3233        return isBinaryExpression(propertyAccess.parent)
3234            ? getParentOfBinaryExpression(propertyAccess.parent).parent.kind === SyntaxKind.SourceFile
3235            : propertyAccess.parent.parent.kind === SyntaxKind.SourceFile;
3236    }
3237
3238    function bindPropertyAssignment(name: BindableStaticNameExpression, propertyAccess: BindableStaticAccessExpression, isPrototypeProperty: boolean, containerIsClass: boolean) {
3239        let namespaceSymbol = lookupSymbolForPropertyAccess(name, container) || lookupSymbolForPropertyAccess(name, blockScopeContainer);
3240        const isToplevel = isTopLevelNamespaceAssignment(propertyAccess);
3241        namespaceSymbol = bindPotentiallyMissingNamespaces(namespaceSymbol, propertyAccess.expression, isToplevel, isPrototypeProperty, containerIsClass);
3242        bindPotentiallyNewExpandoMemberToNamespace(propertyAccess, namespaceSymbol, isPrototypeProperty);
3243    }
3244
3245    /**
3246     * Javascript expando values are:
3247     * - Functions
3248     * - classes
3249     * - namespaces
3250     * - variables initialized with function expressions
3251     * -                       with class expressions
3252     * -                       with empty object literals
3253     * -                       with non-empty object literals if assigned to the prototype property
3254     */
3255    function isExpandoSymbol(symbol: Symbol): boolean {
3256        if (symbol.flags & (SymbolFlags.Function | SymbolFlags.Class | SymbolFlags.NamespaceModule)) {
3257            return true;
3258        }
3259        const node = symbol.valueDeclaration;
3260        if (node && isCallExpression(node)) {
3261            return !!getAssignedExpandoInitializer(node);
3262        }
3263        let init = !node ? undefined :
3264            isVariableDeclaration(node) ? node.initializer :
3265            isBinaryExpression(node) ? node.right :
3266            isPropertyAccessExpression(node) && isBinaryExpression(node.parent) ? node.parent.right :
3267            undefined;
3268        init = init && getRightMostAssignedExpression(init);
3269        if (init) {
3270            const isPrototypeAssignment = isPrototypeAccess(isVariableDeclaration(node!) ? node.name : isBinaryExpression(node!) ? node.left : node!);
3271            return !!getExpandoInitializer(isBinaryExpression(init) && (init.operatorToken.kind === SyntaxKind.BarBarToken || init.operatorToken.kind === SyntaxKind.QuestionQuestionToken) ? init.right : init, isPrototypeAssignment);
3272        }
3273        return false;
3274    }
3275
3276    function getParentOfBinaryExpression(expr: Node) {
3277        while (isBinaryExpression(expr.parent)) {
3278            expr = expr.parent;
3279        }
3280        return expr.parent;
3281    }
3282
3283    function lookupSymbolForPropertyAccess(node: BindableStaticNameExpression, lookupContainer: Node = container): Symbol | undefined {
3284        if (isIdentifier(node)) {
3285            return lookupSymbolForName(lookupContainer, node.escapedText);
3286        }
3287        else {
3288            const symbol = lookupSymbolForPropertyAccess(node.expression);
3289            return symbol && symbol.exports && symbol.exports.get(getElementOrPropertyAccessName(node));
3290        }
3291    }
3292
3293    function forEachIdentifierInEntityName(e: BindableStaticNameExpression, parent: Symbol | undefined, action: (e: Declaration, symbol: Symbol | undefined, parent: Symbol | undefined) => Symbol | undefined): Symbol | undefined {
3294        if (isExportsOrModuleExportsOrAlias(file, e)) {
3295            return file.symbol;
3296        }
3297        else if (isIdentifier(e)) {
3298            return action(e, lookupSymbolForPropertyAccess(e), parent);
3299        }
3300        else {
3301            const s = forEachIdentifierInEntityName(e.expression, parent, action);
3302            const name = getNameOrArgument(e);
3303            // unreachable
3304            if (isPrivateIdentifier(name)) {
3305                Debug.fail("unexpected PrivateIdentifier");
3306            }
3307            return action(name, s && s.exports && s.exports.get(getElementOrPropertyAccessName(e)), s);
3308        }
3309    }
3310
3311    function bindCallExpression(node: CallExpression) {
3312        // We're only inspecting call expressions to detect CommonJS modules, so we can skip
3313        // this check if we've already seen the module indicator
3314        if (!file.commonJsModuleIndicator && isRequireCall(node, /*checkArgumentIsStringLiteralLike*/ false)) {
3315            setCommonJsModuleIndicator(node);
3316        }
3317    }
3318
3319    function bindClassLikeDeclaration(node: ClassLikeDeclaration) {
3320        if (node.kind === SyntaxKind.ClassDeclaration || node.kind === SyntaxKind.StructDeclaration) {
3321            bindBlockScopedDeclaration(node, SymbolFlags.Class, SymbolFlags.ClassExcludes);
3322        }
3323        else {
3324            const bindingName = node.name ? node.name.escapedText : InternalSymbolName.Class;
3325            bindAnonymousDeclaration(node, SymbolFlags.Class, bindingName);
3326            // Add name of class expression into the map for semantic classifier
3327            if (node.name) {
3328                classifiableNames.add(node.name.escapedText);
3329            }
3330        }
3331
3332        const { symbol } = node;
3333
3334        // TypeScript 1.0 spec (April 2014): 8.4
3335        // Every class automatically contains a static property member named 'prototype', the
3336        // type of which is an instantiation of the class type with type Any supplied as a type
3337        // argument for each type parameter. It is an error to explicitly declare a static
3338        // property member with the name 'prototype'.
3339        //
3340        // Note: we check for this here because this class may be merging into a module.  The
3341        // module might have an exported variable called 'prototype'.  We can't allow that as
3342        // that would clash with the built-in 'prototype' for the class.
3343        const prototypeSymbol = createSymbol(SymbolFlags.Property | SymbolFlags.Prototype, "prototype" as __String);
3344        const symbolExport = symbol.exports!.get(prototypeSymbol.escapedName);
3345        if (symbolExport) {
3346            if (node.name) {
3347                setParent(node.name, node);
3348            }
3349            file.bindDiagnostics.push(createDiagnosticForNode(symbolExport.declarations![0], Diagnostics.Duplicate_identifier_0, symbolName(prototypeSymbol)));
3350        }
3351        symbol.exports!.set(prototypeSymbol.escapedName, prototypeSymbol);
3352        prototypeSymbol.parent = symbol;
3353    }
3354
3355    function bindAnnotationDeclaration(node: AnnotationDeclaration): void {
3356        Debug.assert(node.kind === SyntaxKind.AnnotationDeclaration);
3357
3358        bindBlockScopedDeclaration(node, SymbolFlags.Class | SymbolFlags.Annotation, SymbolFlags.ClassExcludes);
3359        const { symbol } = node;
3360        const prototypeSymbol = createSymbol(SymbolFlags.Property | SymbolFlags.Prototype, "prototype" as __String);
3361        const symbolExport = symbol.exports!.get(prototypeSymbol.escapedName);
3362        if (symbolExport) {
3363            if (node.name) {
3364                setParent(node.name, node);
3365            }
3366            file.bindDiagnostics.push(createDiagnosticForNode(symbolExport.declarations![0], Diagnostics.Duplicate_identifier_0, symbolName(prototypeSymbol)));
3367        }
3368        symbol.exports!.set(prototypeSymbol.escapedName, prototypeSymbol);
3369        prototypeSymbol.parent = symbol;
3370    }
3371
3372    function bindEnumDeclaration(node: EnumDeclaration) {
3373        return isEnumConst(node)
3374            ? bindBlockScopedDeclaration(node, SymbolFlags.ConstEnum, SymbolFlags.ConstEnumExcludes)
3375            : bindBlockScopedDeclaration(node, SymbolFlags.RegularEnum, SymbolFlags.RegularEnumExcludes);
3376    }
3377
3378    function bindVariableDeclarationOrBindingElement(node: VariableDeclaration | BindingElement) {
3379        if (inStrictMode) {
3380            checkStrictModeEvalOrArguments(node, node.name);
3381        }
3382
3383        if (!isBindingPattern(node.name)) {
3384            const possibleVariableDecl = node.kind === SyntaxKind.VariableDeclaration ? node : node.parent.parent;
3385            if (isInJSFile(node) &&
3386                isVariableDeclarationInitializedToBareOrAccessedRequire(possibleVariableDecl) &&
3387                !getJSDocTypeTag(node) &&
3388                !(getCombinedModifierFlags(node) & ModifierFlags.Export)
3389            ) {
3390                declareSymbolAndAddToSymbolTable(node as Declaration, SymbolFlags.Alias, SymbolFlags.AliasExcludes);
3391            }
3392            else if (isBlockOrCatchScoped(node)) {
3393                bindBlockScopedDeclaration(node, SymbolFlags.BlockScopedVariable, SymbolFlags.BlockScopedVariableExcludes);
3394            }
3395            else if (isParameterDeclaration(node)) {
3396                // It is safe to walk up parent chain to find whether the node is a destructuring parameter declaration
3397                // because its parent chain has already been set up, since parents are set before descending into children.
3398                //
3399                // If node is a binding element in parameter declaration, we need to use ParameterExcludes.
3400                // Using ParameterExcludes flag allows the compiler to report an error on duplicate identifiers in Parameter Declaration
3401                // For example:
3402                //      function foo([a,a]) {} // Duplicate Identifier error
3403                //      function bar(a,a) {}   // Duplicate Identifier error, parameter declaration in this case is handled in bindParameter
3404                //                             // which correctly set excluded symbols
3405                declareSymbolAndAddToSymbolTable(node, SymbolFlags.FunctionScopedVariable, SymbolFlags.ParameterExcludes);
3406            }
3407            else {
3408                declareSymbolAndAddToSymbolTable(node, SymbolFlags.FunctionScopedVariable, SymbolFlags.FunctionScopedVariableExcludes);
3409            }
3410        }
3411    }
3412
3413    function bindParameter(node: ParameterDeclaration | JSDocParameterTag) {
3414        if (node.kind === SyntaxKind.JSDocParameterTag && container.kind !== SyntaxKind.JSDocSignature) {
3415            return;
3416        }
3417        if (inStrictMode && !(node.flags & NodeFlags.Ambient)) {
3418            // It is a SyntaxError if the identifier eval or arguments appears within a FormalParameterList of a
3419            // strict mode FunctionLikeDeclaration or FunctionExpression(13.1)
3420            checkStrictModeEvalOrArguments(node, node.name);
3421        }
3422
3423        if (isBindingPattern(node.name)) {
3424            bindAnonymousDeclaration(node, SymbolFlags.FunctionScopedVariable, "__" + (node as ParameterDeclaration).parent.parameters.indexOf(node as ParameterDeclaration) as __String);
3425        }
3426        else {
3427            declareSymbolAndAddToSymbolTable(node, SymbolFlags.FunctionScopedVariable, SymbolFlags.ParameterExcludes);
3428        }
3429
3430        // If this is a property-parameter, then also declare the property symbol into the
3431        // containing class.
3432        if (isParameterPropertyDeclaration(node, node.parent)) {
3433            const classDeclaration = node.parent.parent;
3434            declareSymbol(classDeclaration.symbol.members!, classDeclaration.symbol, node, SymbolFlags.Property | (node.questionToken ? SymbolFlags.Optional : SymbolFlags.None), SymbolFlags.PropertyExcludes);
3435        }
3436    }
3437
3438    function bindFunctionDeclaration(node: FunctionDeclaration) {
3439        if (!file.isDeclarationFile && !(node.flags & NodeFlags.Ambient)) {
3440            if (isAsyncFunction(node)) {
3441                emitFlags |= NodeFlags.HasAsyncFunctions;
3442            }
3443        }
3444
3445        checkStrictModeFunctionName(node);
3446        if (inStrictMode) {
3447            checkStrictModeFunctionDeclaration(node);
3448            bindBlockScopedDeclaration(node, SymbolFlags.Function, SymbolFlags.FunctionExcludes);
3449        }
3450        else {
3451            declareSymbolAndAddToSymbolTable(node, SymbolFlags.Function, SymbolFlags.FunctionExcludes);
3452        }
3453    }
3454
3455    function bindFunctionExpression(node: FunctionExpression) {
3456        if (!file.isDeclarationFile && !(node.flags & NodeFlags.Ambient)) {
3457            if (isAsyncFunction(node)) {
3458                emitFlags |= NodeFlags.HasAsyncFunctions;
3459            }
3460        }
3461        if (currentFlow) {
3462            node.flowNode = currentFlow;
3463        }
3464        checkStrictModeFunctionName(node);
3465        const bindingName = node.name ? node.name.escapedText : InternalSymbolName.Function;
3466        return bindAnonymousDeclaration(node, SymbolFlags.Function, bindingName);
3467    }
3468
3469    function bindPropertyOrMethodOrAccessor(node: Declaration, symbolFlags: SymbolFlags, symbolExcludes: SymbolFlags) {
3470        if (!file.isDeclarationFile && !(node.flags & NodeFlags.Ambient) && isAsyncFunction(node)) {
3471            emitFlags |= NodeFlags.HasAsyncFunctions;
3472        }
3473
3474        if (currentFlow && isObjectLiteralOrClassExpressionMethodOrAccessor(node)) {
3475            node.flowNode = currentFlow;
3476        }
3477
3478        return hasDynamicName(node)
3479            ? bindAnonymousDeclaration(node, symbolFlags, InternalSymbolName.Computed)
3480            : declareSymbolAndAddToSymbolTable(node, symbolFlags, symbolExcludes);
3481    }
3482
3483    function getInferTypeContainer(node: Node): ConditionalTypeNode | undefined {
3484        const extendsType = findAncestor(node, n => n.parent && isConditionalTypeNode(n.parent) && n.parent.extendsType === n);
3485        return extendsType && extendsType.parent as ConditionalTypeNode;
3486    }
3487
3488    function bindTypeParameter(node: TypeParameterDeclaration) {
3489        if (isJSDocTemplateTag(node.parent)) {
3490            const container = getEffectiveContainerForJSDocTemplateTag(node.parent);
3491            if (container) {
3492                if (!container.locals) {
3493                    container.locals = createSymbolTable();
3494                }
3495                declareSymbol(container.locals, /*parent*/ undefined, node, SymbolFlags.TypeParameter, SymbolFlags.TypeParameterExcludes);
3496            }
3497            else {
3498                declareSymbolAndAddToSymbolTable(node, SymbolFlags.TypeParameter, SymbolFlags.TypeParameterExcludes);
3499            }
3500        }
3501        else if (node.parent.kind === SyntaxKind.InferType) {
3502            const container = getInferTypeContainer(node.parent);
3503            if (container) {
3504                if (!container.locals) {
3505                    container.locals = createSymbolTable();
3506                }
3507                declareSymbol(container.locals, /*parent*/ undefined, node, SymbolFlags.TypeParameter, SymbolFlags.TypeParameterExcludes);
3508            }
3509            else {
3510                bindAnonymousDeclaration(node, SymbolFlags.TypeParameter, getDeclarationName(node)!); // TODO: GH#18217
3511            }
3512        }
3513        else {
3514            declareSymbolAndAddToSymbolTable(node, SymbolFlags.TypeParameter, SymbolFlags.TypeParameterExcludes);
3515        }
3516    }
3517
3518    // reachability checks
3519
3520    function shouldReportErrorOnModuleDeclaration(node: ModuleDeclaration): boolean {
3521        const instanceState = getModuleInstanceState(node);
3522        return instanceState === ModuleInstanceState.Instantiated || (instanceState === ModuleInstanceState.ConstEnumOnly && shouldPreserveConstEnums(options));
3523    }
3524
3525    function checkUnreachable(node: Node): boolean {
3526        if (!(currentFlow.flags & FlowFlags.Unreachable)) {
3527            return false;
3528        }
3529        if (currentFlow === unreachableFlow) {
3530            const reportError =
3531                // report error on all statements except empty ones
3532                (isStatementButNotDeclaration(node) && node.kind !== SyntaxKind.EmptyStatement) ||
3533                // report error on class declarations
3534                node.kind === SyntaxKind.ClassDeclaration ||
3535                // report error on instantiated modules or const-enums only modules if preserveConstEnums is set
3536                (node.kind === SyntaxKind.ModuleDeclaration && shouldReportErrorOnModuleDeclaration(node as ModuleDeclaration));
3537
3538            if (reportError) {
3539                currentFlow = reportedUnreachableFlow;
3540
3541                if (!options.allowUnreachableCode) {
3542                    // unreachable code is reported if
3543                    // - user has explicitly asked about it AND
3544                    // - statement is in not ambient context (statements in ambient context is already an error
3545                    //   so we should not report extras) AND
3546                    //   - node is not variable statement OR
3547                    //   - node is block scoped variable statement OR
3548                    //   - node is not block scoped variable statement and at least one variable declaration has initializer
3549                    //   Rationale: we don't want to report errors on non-initialized var's since they are hoisted
3550                    //   On the other side we do want to report errors on non-initialized 'lets' because of TDZ
3551                    const isError =
3552                        unreachableCodeIsError(options) &&
3553                        !(node.flags & NodeFlags.Ambient) &&
3554                        (
3555                            !isVariableStatement(node) ||
3556                            !!(getCombinedNodeFlags(node.declarationList) & NodeFlags.BlockScoped) ||
3557                            node.declarationList.declarations.some(d => !!d.initializer)
3558                        );
3559
3560                    eachUnreachableRange(node, (start, end) => errorOrSuggestionOnRange(isError, start, end, Diagnostics.Unreachable_code_detected));
3561                }
3562            }
3563        }
3564        return true;
3565    }
3566}
3567
3568function eachUnreachableRange(node: Node, cb: (start: Node, last: Node) => void): void {
3569    if (isStatement(node) && isExecutableStatement(node) && isBlock(node.parent)) {
3570        const { statements } = node.parent;
3571        const slice = sliceAfter(statements, node);
3572        getRangesWhere(slice, isExecutableStatement, (start, afterEnd) => cb(slice[start], slice[afterEnd - 1]));
3573    }
3574    else {
3575        cb(node, node);
3576    }
3577}
3578// As opposed to a pure declaration like an `interface`
3579function isExecutableStatement(s: Statement): boolean {
3580    // Don't remove statements that can validly be used before they appear.
3581    return !isFunctionDeclaration(s) && !isPurelyTypeDeclaration(s) && !isEnumDeclaration(s) &&
3582        // `var x;` may declare a variable used above
3583        !(isVariableStatement(s) && !(getCombinedNodeFlags(s) & (NodeFlags.Let | NodeFlags.Const)) && s.declarationList.declarations.some(d => !d.initializer));
3584}
3585
3586function isPurelyTypeDeclaration(s: Statement): boolean {
3587    switch (s.kind) {
3588        case SyntaxKind.InterfaceDeclaration:
3589        case SyntaxKind.TypeAliasDeclaration:
3590            return true;
3591        case SyntaxKind.ModuleDeclaration:
3592            return getModuleInstanceState(s as ModuleDeclaration) !== ModuleInstanceState.Instantiated;
3593        case SyntaxKind.EnumDeclaration:
3594            return hasSyntacticModifier(s, ModifierFlags.Const);
3595        default:
3596            return false;
3597    }
3598}
3599
3600/** @internal */
3601export function isExportsOrModuleExportsOrAlias(sourceFile: SourceFile, node: Expression): boolean {
3602    let i = 0;
3603    const q = createQueue<Expression>();
3604    q.enqueue(node);
3605    while (!q.isEmpty() && i < 100) {
3606        i++;
3607        node = q.dequeue();
3608        if (isExportsIdentifier(node) || isModuleExportsAccessExpression(node)) {
3609            return true;
3610        }
3611        else if (isIdentifier(node)) {
3612            const symbol = lookupSymbolForName(sourceFile, node.escapedText);
3613            if (!!symbol && !!symbol.valueDeclaration && isVariableDeclaration(symbol.valueDeclaration) && !!symbol.valueDeclaration.initializer) {
3614                const init = symbol.valueDeclaration.initializer;
3615                q.enqueue(init);
3616                if (isAssignmentExpression(init, /*excludeCompoundAssignment*/ true)) {
3617                    q.enqueue(init.left);
3618                    q.enqueue(init.right);
3619                }
3620            }
3621        }
3622    }
3623    return false;
3624}
3625
3626function lookupSymbolForName(container: Node, name: __String): Symbol | undefined {
3627    const local = container.locals && container.locals.get(name);
3628    if (local) {
3629        return local.exportSymbol || local;
3630    }
3631    if (isSourceFile(container) && container.jsGlobalAugmentations && container.jsGlobalAugmentations.has(name)) {
3632        return container.jsGlobalAugmentations.get(name);
3633    }
3634    return container.symbol && container.symbol.exports && container.symbol.exports.get(name);
3635}
3636