From d42b2b708d433b4b87e89dcd2171d8ff716c2095 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Tue, 9 Nov 2021 01:09:57 +0000 Subject: [PATCH] Try just the fetching change in checker. --- src/compiler/binder.ts | 19 ++--- src/compiler/checker.ts | 12 ++-- src/compiler/emitter.ts | 11 ++- src/compiler/factory/nodeFactory.ts | 2 +- src/compiler/transformers/classFields.ts | 36 +++++----- src/compiler/transformers/declarations.ts | 28 ++++---- src/compiler/transformers/es2017.ts | 6 +- src/compiler/transformers/es2018.ts | 6 +- src/compiler/transformers/es5.ts | 9 ++- src/compiler/transformers/generators.ts | 8 +-- src/compiler/transformers/module/module.ts | 58 +++++++-------- src/compiler/transformers/module/system.ts | 82 ++++++++++++---------- src/compiler/transformers/ts.ts | 10 +-- src/compiler/transformers/utilities.ts | 33 ++++++--- src/compiler/types.ts | 6 +- 15 files changed, 174 insertions(+), 152 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 3db8807b5b7..8ff6712ad30 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -15,7 +15,7 @@ namespace ts { referenced: boolean; } - export function getModuleInstanceState(node: ModuleDeclaration, visited?: ESMap): ModuleInstanceState { + export function getModuleInstanceState(node: ModuleDeclaration, visited?: ESMap): ModuleInstanceState { if (node.body && !node.body.parent) { // getModuleInstanceStateForAliasTarget needs to walk up the parent chain, so parent pointers must be set on this tree already setParent(node.body, node); @@ -24,17 +24,18 @@ namespace ts { return node.body ? getModuleInstanceStateCached(node.body, visited) : ModuleInstanceState.Instantiated; } - function getModuleInstanceStateCached(node: Node, visited = new Map()) { - if (visited.has(node)) { - return visited.get(node) || ModuleInstanceState.NonInstantiated; + function getModuleInstanceStateCached(node: Node, visited = new Map()) { + const nodeId = getNodeId(node); + if (visited.has(nodeId)) { + return visited.get(nodeId) || ModuleInstanceState.NonInstantiated; } - visited.set(node, undefined); + visited.set(nodeId, undefined); const result = getModuleInstanceStateWorker(node, visited); - visited.set(node, result); + visited.set(nodeId, result); return result; } - function getModuleInstanceStateWorker(node: Node, visited: ESMap): ModuleInstanceState { + function getModuleInstanceStateWorker(node: Node, visited: ESMap): ModuleInstanceState { // A module is uninstantiated if it contains only switch (node.kind) { // 1. interface declarations, type alias declarations @@ -106,7 +107,7 @@ namespace ts { return ModuleInstanceState.Instantiated; } - function getModuleInstanceStateForAliasTarget(specifier: ExportSpecifier, visited: ESMap) { + function getModuleInstanceStateForAliasTarget(specifier: ExportSpecifier, visited: ESMap) { const name = specifier.propertyName || specifier.name; let p: Node | undefined = specifier.parent; while (p) { @@ -2983,7 +2984,7 @@ namespace ts { function addLateBoundAssignmentDeclarationToSymbol(node: BinaryExpression | DynamicNamedDeclaration, symbol: Symbol | undefined) { if (symbol) { - (symbol.assignmentDeclarationMembers ||= new Set()).add(node); + (symbol.assignmentDeclarationMembers || (symbol.assignmentDeclarationMembers = new Map())).set(getNodeId(node), node); } } diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 4ce54bbcabe..f74d36a2392 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3887,9 +3887,10 @@ namespace ts { function getAlternativeContainingModules(symbol: Symbol, enclosingDeclaration: Node): Symbol[] { const containingFile = getSourceFileOfNode(enclosingDeclaration); + const id = getNodeId(containingFile); const links = getSymbolLinks(symbol); let results: Symbol[] | undefined; - if (links.extendedContainersByFile && (results = links.extendedContainersByFile.get(containingFile))) { + if (links.extendedContainersByFile && (results = links.extendedContainersByFile.get(id))) { return results; } if (containingFile && containingFile.imports) { @@ -3903,7 +3904,7 @@ namespace ts { results = append(results, resolvedModule); } if (length(results)) { - (links.extendedContainersByFile ||= new Map()).set(containingFile, results!); + (links.extendedContainersByFile || (links.extendedContainersByFile = new Map())).set(id, results!); return results!; } } @@ -33795,7 +33796,7 @@ namespace ts { const type = checkExpression(node); // If control flow analysis was required to determine the type, it is worth caching. if (flowInvocationCount !== startInvocationCount) { - const cache = (flowTypeCache ||= []); + const cache = flowTypeCache || (flowTypeCache = []); cache[getNodeId(node)] = type; setNodeFlags(node, node.flags | NodeFlags.TypeCached); } @@ -40317,8 +40318,9 @@ namespace ts { const enclosingFile = getSourceFileOfNode(node); const links = getNodeLinks(enclosingFile); if (!(links.flags & NodeCheckFlags.TypeChecked)) { - links.deferredNodes ||= new Set(); - links.deferredNodes.add(node); + links.deferredNodes = links.deferredNodes || new Map(); + const id = getNodeId(node); + links.deferredNodes.set(id, node); } } diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 3025be42a80..d4eff1e0ace 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -869,7 +869,7 @@ namespace ts { const bundledHelpers = new Map(); let currentSourceFile: SourceFile | undefined; - let nodeToGeneratedName: ESMap; // Map of generated names for specific nodes. + let nodeIdToGeneratedName: string[]; // Map of generated names for specific nodes. let autoGeneratedIdToGeneratedName: string[]; // Map of generated names for temp and loop variables. let generatedNames: Set; // Set of names generated by the NameGenerator. let tempFlagsStack: TempFlags[]; // Stack of enclosing name generation scopes. @@ -1154,7 +1154,7 @@ namespace ts { } function reset() { - nodeToGeneratedName = new Map(); + nodeIdToGeneratedName = []; autoGeneratedIdToGeneratedName = []; generatedNames = new Set(); tempFlagsStack = []; @@ -5008,11 +5008,8 @@ namespace ts { } function generateNameCached(node: Node, flags?: GeneratedIdentifierFlags) { - let result = nodeToGeneratedName.get(node); - if (result === undefined) { - nodeToGeneratedName.set(node, result = generateNameForNode(node, flags)); - } - return result; + const nodeId = getNodeId(node); + return nodeIdToGeneratedName[nodeId] || (nodeIdToGeneratedName[nodeId] = generateNameForNode(node, flags)); } /** diff --git a/src/compiler/factory/nodeFactory.ts b/src/compiler/factory/nodeFactory.ts index 63b241dc9e5..963ce75441f 100644 --- a/src/compiler/factory/nodeFactory.ts +++ b/src/compiler/factory/nodeFactory.ts @@ -5339,7 +5339,7 @@ namespace ts { } function flattenCommaElements(node: Expression): Expression | readonly Expression[] { - if (nodeIsSynthesized(node) && !isParseTreeNode(node) && !node.original && !node.emitNode) { + if (nodeIsSynthesized(node) && !isParseTreeNode(node) && !node.original && !node.emitNode && !node.id) { if (isCommaListExpression(node)) { return node.elements; } diff --git a/src/compiler/transformers/classFields.ts b/src/compiler/transformers/classFields.ts index 4cebe15215b..7d4afe2baff 100644 --- a/src/compiler/transformers/classFields.ts +++ b/src/compiler/transformers/classFields.ts @@ -147,7 +147,7 @@ namespace ts { let enabledSubstitutions: ClassPropertySubstitutionFlags; - let classAliases: ESMap; + let classAliases: Identifier[]; /** * Tracks what computed name expressions originating from elided names must be inlined @@ -162,7 +162,7 @@ namespace ts { let pendingStatements: Statement[] | undefined; const classLexicalEnvironmentStack: (ClassLexicalEnvironment | undefined)[] = []; - const classLexicalEnvironmentMap = new WeakMap(); + const classLexicalEnvironmentMap = new Map(); let currentClassLexicalEnvironment: ClassLexicalEnvironment | undefined; let currentComputedPropertyNameClassLexicalEnvironment: ClassLexicalEnvironment | undefined; let currentStaticPropertyDeclarationOrStaticBlock: PropertyDeclaration | ClassStaticBlockDeclaration | undefined; @@ -738,7 +738,7 @@ namespace ts { function transformClassStaticBlockDeclaration(node: ClassStaticBlockDeclaration) { if (shouldTransformPrivateElementsOrClassStaticBlocks) { if (currentClassLexicalEnvironment) { - classLexicalEnvironmentMap.set(getOriginalNode(node), currentClassLexicalEnvironment); + classLexicalEnvironmentMap.set(getOriginalNodeId(node), currentClassLexicalEnvironment); } startLexicalEnvironment(); @@ -1128,7 +1128,7 @@ namespace ts { enableSubstitutionForClassAliases(); const alias = factory.cloneNode(temp) as GeneratedIdentifier; alias.autoGenerateFlags &= ~GeneratedIdentifierFlags.ReservedInNestedScopes; - classAliases.set(getOriginalNode(node), alias); + classAliases[getOriginalNodeId(node)] = alias; } // To preserve the behavior of the old emitter, we explicitly indent @@ -1375,7 +1375,7 @@ namespace ts { // capture the lexical environment for the member setOriginalNode(transformed, property); addEmitFlags(transformed, EmitFlags.AdviseOnEmitNode); - classLexicalEnvironmentMap.set(getOriginalNode(transformed), currentClassLexicalEnvironment); + classLexicalEnvironmentMap.set(getOriginalNodeId(transformed), currentClassLexicalEnvironment); } currentStaticPropertyDeclarationOrStaticBlock = savedCurrentStaticPropertyDeclarationOrStaticBlock; return transformed; @@ -1453,7 +1453,7 @@ namespace ts { context.enableSubstitution(SyntaxKind.Identifier); // Keep track of class aliases. - classAliases = new Map(); + classAliases = []; } } @@ -1516,16 +1516,18 @@ namespace ts { function onEmitNode(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void) { const original = getOriginalNode(node); - const classLexicalEnvironment = classLexicalEnvironmentMap.get(original); - if (classLexicalEnvironment) { - const savedClassLexicalEnvironment = currentClassLexicalEnvironment; - const savedCurrentComputedPropertyNameClassLexicalEnvironment = currentComputedPropertyNameClassLexicalEnvironment; - currentClassLexicalEnvironment = classLexicalEnvironment; - currentComputedPropertyNameClassLexicalEnvironment = classLexicalEnvironment; - previousOnEmitNode(hint, node, emitCallback); - currentClassLexicalEnvironment = savedClassLexicalEnvironment; - currentComputedPropertyNameClassLexicalEnvironment = savedCurrentComputedPropertyNameClassLexicalEnvironment; - return; + if (original.id) { + const classLexicalEnvironment = classLexicalEnvironmentMap.get(original.id); + if (classLexicalEnvironment) { + const savedClassLexicalEnvironment = currentClassLexicalEnvironment; + const savedCurrentComputedPropertyNameClassLexicalEnvironment = currentComputedPropertyNameClassLexicalEnvironment; + currentClassLexicalEnvironment = classLexicalEnvironment; + currentComputedPropertyNameClassLexicalEnvironment = classLexicalEnvironment; + previousOnEmitNode(hint, node, emitCallback); + currentClassLexicalEnvironment = savedClassLexicalEnvironment; + currentComputedPropertyNameClassLexicalEnvironment = savedCurrentComputedPropertyNameClassLexicalEnvironment; + return; + } } switch (node.kind) { @@ -1631,7 +1633,7 @@ namespace ts { // constructor references in static property initializers. const declaration = resolver.getReferencedValueDeclaration(node); if (declaration) { - const classAlias = classAliases.get(declaration); + const classAlias = classAliases[declaration.id!]; // TODO: GH#18217 if (classAlias) { const clone = factory.cloneNode(classAlias); setSourceMapRange(clone, node); diff --git a/src/compiler/transformers/declarations.ts b/src/compiler/transformers/declarations.ts index 8ed26f1aeb5..6cea3b85055 100644 --- a/src/compiler/transformers/declarations.ts +++ b/src/compiler/transformers/declarations.ts @@ -60,7 +60,7 @@ namespace ts { let enclosingDeclaration: Node; let necessaryTypeReferences: Set | undefined; let lateMarkedStatements: LateVisibilityPaintedStatement[] | undefined; - let lateStatementReplacementMap: ESMap>; + let lateStatementReplacementMap: ESMap>; let suppressNewDiagnosticContexts: boolean; let exportedModulesFromDeclarationEmit: Symbol[] | undefined; @@ -84,7 +84,7 @@ namespace ts { let errorFallbackNode: Declaration | undefined; let currentSourceFile: SourceFile; - let refs: ESMap; + let refs: ESMap; let libs: ESMap; let emittedImports: readonly AnyImportSyntax[] | undefined; // must be declared in container so it can be `undefined` while transformer's first pass const resolver = context.getEmitResolver(); @@ -110,7 +110,7 @@ namespace ts { } // Otherwise we should emit a path-based reference const container = getSourceFileOfNode(node); - refs.set(getOriginalNode(container), container); + refs.set(getOriginalNodeId(container), container); } function handleSymbolAccessibilityError(symbolAccessibilityResult: SymbolAccessibilityResult) { @@ -426,12 +426,12 @@ namespace ts { } } - function collectReferences(sourceFile: SourceFile | UnparsedSource, ret: ESMap) { + function collectReferences(sourceFile: SourceFile | UnparsedSource, ret: ESMap) { if (noResolve || (!isUnparsedSource(sourceFile) && isSourceFileJS(sourceFile))) return ret; forEach(sourceFile.referencedFiles, f => { const elem = host.getSourceFileFromReference(sourceFile, f); if (elem) { - ret.set(getOriginalNode(elem), elem); + ret.set(getOriginalNodeId(elem), elem); } }); return ret; @@ -812,7 +812,7 @@ namespace ts { needsDeclare = i.parent && isSourceFile(i.parent) && !(isExternalModule(i.parent) && isBundledEmit); const result = transformTopLevelDeclaration(i); needsDeclare = priorNeedsDeclare; - lateStatementReplacementMap.set(getOriginalNode(i), result); + lateStatementReplacementMap.set(getOriginalNodeId(i), result); } // And lastly, we need to get the final form of all those indetermine import declarations from before and add them to the output list @@ -821,10 +821,10 @@ namespace ts { function visitLateVisibilityMarkedStatements(statement: Statement) { if (isLateVisibilityPaintedStatement(statement)) { - const originalNode = getOriginalNode(statement); - if (lateStatementReplacementMap.has(originalNode)) { - const result = lateStatementReplacementMap.get(originalNode); - lateStatementReplacementMap.delete(originalNode); + const key = getOriginalNodeId(statement); + if (lateStatementReplacementMap.has(key)) { + const result = lateStatementReplacementMap.get(key); + lateStatementReplacementMap.delete(key); if (result) { if (isArray(result) ? some(result, needsScopeMarker) : needsScopeMarker(result)) { // Top-level declarations in .d.ts files are always considered exported even without a modifier unless there's an export assignment or specifier @@ -1146,7 +1146,7 @@ namespace ts { const result = transformTopLevelDeclaration(input); // Don't actually transform yet; just leave as original node - will be elided/swapped by late pass - lateStatementReplacementMap.set(getOriginalNode(input), result); + lateStatementReplacementMap.set(getOriginalNodeId(input), result); return input; } @@ -1348,9 +1348,9 @@ namespace ts { needsDeclare = false; visitNode(inner, visitDeclarationStatements); // eagerly transform nested namespaces (the nesting doesn't need any elision or painting done) - const originalNode = getOriginalNode(inner!); // TODO: GH#18217 - const body = lateStatementReplacementMap.get(originalNode); - lateStatementReplacementMap.delete(originalNode); + const id = getOriginalNodeId(inner!); // TODO: GH#18217 + const body = lateStatementReplacementMap.get(id); + lateStatementReplacementMap.delete(id); return cleanup(factory.updateModuleDeclaration( input, /*decorators*/ undefined, diff --git a/src/compiler/transformers/es2017.ts b/src/compiler/transformers/es2017.ts index 66f10db0991..ade1d41b010 100644 --- a/src/compiler/transformers/es2017.ts +++ b/src/compiler/transformers/es2017.ts @@ -46,7 +46,7 @@ namespace ts { /** Whether the async function contains an element access on super (`super[x]`). */ let hasSuperElementAccess: boolean; /** A set of node IDs for generated super accessors (variable statements). */ - const substitutedSuperAccessors = new Set(); + const substitutedSuperAccessors: boolean[] = []; let contextFlags: ContextFlags = 0; @@ -503,7 +503,7 @@ namespace ts { enableSubstitutionForAsyncMethodsWithSuper(); if (capturedSuperProperties.size) { const variableStatement = createSuperAccessVariableStatement(factory, resolver, node, capturedSuperProperties); - substitutedSuperAccessors.add(variableStatement); + substitutedSuperAccessors[getNodeId(variableStatement)] = true; insertStatementsAfterStandardPrologue(statements, [variableStatement]); } } @@ -613,7 +613,7 @@ namespace ts { } } // Disable substitution in the generated super accessor itself. - else if (enabledSubstitutions && substitutedSuperAccessors.has(node)) { + else if (enabledSubstitutions && substitutedSuperAccessors[getNodeId(node)]) { const savedEnclosingSuperContainerFlags = enclosingSuperContainerFlags; enclosingSuperContainerFlags = 0; previousOnEmitNode(hint, node, emitCallback); diff --git a/src/compiler/transformers/es2018.ts b/src/compiler/transformers/es2018.ts index f18c0964f61..846fd992ff2 100644 --- a/src/compiler/transformers/es2018.ts +++ b/src/compiler/transformers/es2018.ts @@ -70,7 +70,7 @@ namespace ts { /** Whether the async function contains an element access on super (`super[x]`). */ let hasSuperElementAccess: boolean; /** A set of node IDs for generated super accessors. */ - const substitutedSuperAccessors = new Set(); + const substitutedSuperAccessors: boolean[] = []; return chainBundle(context, transformSourceFile); @@ -972,7 +972,7 @@ namespace ts { if (emitSuperHelpers) { enableSubstitutionForAsyncMethodsWithSuper(); const variableStatement = createSuperAccessVariableStatement(factory, resolver, node, capturedSuperProperties); - substitutedSuperAccessors.add(variableStatement); + substitutedSuperAccessors[getNodeId(variableStatement)] = true; insertStatementsAfterStandardPrologue(statements, [variableStatement]); } @@ -1087,7 +1087,7 @@ namespace ts { } } // Disable substitution in the generated super accessor itself. - else if (enabledSubstitutions && substitutedSuperAccessors.has(node)) { + else if (enabledSubstitutions && substitutedSuperAccessors[getNodeId(node)]) { const savedEnclosingSuperContainerFlags = enclosingSuperContainerFlags; enclosingSuperContainerFlags = 0 as NodeCheckFlags; previousOnEmitNode(hint, node, emitCallback); diff --git a/src/compiler/transformers/es5.ts b/src/compiler/transformers/es5.ts index 9dc69f21475..e82ba20cf5f 100644 --- a/src/compiler/transformers/es5.ts +++ b/src/compiler/transformers/es5.ts @@ -11,14 +11,14 @@ namespace ts { // enable emit notification only if using --jsx preserve or react-native let previousOnEmitNode: (hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void) => void; - let noSubstitution: Set; + let noSubstitution: boolean[]; if (compilerOptions.jsx === JsxEmit.Preserve || compilerOptions.jsx === JsxEmit.ReactNative) { previousOnEmitNode = context.onEmitNode; context.onEmitNode = onEmitNode; context.enableEmitNotification(SyntaxKind.JsxOpeningElement); context.enableEmitNotification(SyntaxKind.JsxClosingElement); context.enableEmitNotification(SyntaxKind.JsxSelfClosingElement); - noSubstitution = new Set(); + noSubstitution = []; } const previousOnSubstituteNode = context.onSubstituteNode; @@ -49,7 +49,7 @@ namespace ts { case SyntaxKind.JsxClosingElement: case SyntaxKind.JsxSelfClosingElement: const tagName = (node as JsxOpeningElement | JsxClosingElement | JsxSelfClosingElement).tagName; - noSubstitution.add(getOriginalNode(tagName)); + noSubstitution[getOriginalNodeId(tagName)] = true; break; } @@ -63,8 +63,7 @@ namespace ts { * @param node The node to substitute. */ function onSubstituteNode(hint: EmitHint, node: Node) { - // TODO: do we need to check for a Node ID here? - if (noSubstitution?.has(node)) { + if (node.id && noSubstitution && noSubstitution[node.id]) { return previousOnSubstituteNode(hint, node); } diff --git a/src/compiler/transformers/generators.ts b/src/compiler/transformers/generators.ts index 24acc78ae3c..73e35b4583d 100644 --- a/src/compiler/transformers/generators.ts +++ b/src/compiler/transformers/generators.ts @@ -245,7 +245,7 @@ namespace ts { context.onSubstituteNode = onSubstituteNode; let renamedCatchVariables: ESMap; - let renamedCatchVariableDeclarations: ESMap; + let renamedCatchVariableDeclarations: Identifier[]; let inGeneratorFunctionBody: boolean; let inStatementContainingYield: boolean; @@ -1969,7 +1969,7 @@ namespace ts { if (isIdentifier(original) && original.parent) { const declaration = resolver.getReferencedValueDeclaration(original); if (declaration) { - const name = renamedCatchVariableDeclarations.get(getOriginalNode(declaration)); + const name = renamedCatchVariableDeclarations[getOriginalNodeId(declaration)]; if (name) { // TODO(rbuckton): Does this need to be parented? const clone = setParent(setTextRange(factory.cloneNode(name), name), name.parent); @@ -2137,12 +2137,12 @@ namespace ts { name = declareLocal(text); if (!renamedCatchVariables) { renamedCatchVariables = new Map(); - renamedCatchVariableDeclarations = new Map(); + renamedCatchVariableDeclarations = []; context.enableSubstitution(SyntaxKind.Identifier); } renamedCatchVariables.set(text, true); - renamedCatchVariableDeclarations.set(getOriginalNode(variable), name); + renamedCatchVariableDeclarations[getOriginalNodeId(variable)] = name; } const exception = peekBlock() as ExceptionBlock; diff --git a/src/compiler/transformers/module/module.ts b/src/compiler/transformers/module/module.ts index 1305db0629d..9c884716409 100644 --- a/src/compiler/transformers/module/module.ts +++ b/src/compiler/transformers/module/module.ts @@ -40,12 +40,12 @@ namespace ts { context.enableSubstitution(SyntaxKind.ShorthandPropertyAssignment); // Substitutes shorthand property assignments for imported/exported symbols. context.enableEmitNotification(SyntaxKind.SourceFile); // Restore state when substituting nodes in a file. - const moduleInfoMap = new Map(); // The ExternalModuleInfo for each file. - const deferredExports = new Map();; // Exports to defer until an EndOfDeclarationMarker is found. + const moduleInfoMap: ExternalModuleInfo[] = []; // The ExternalModuleInfo for each file. + const deferredExports: (Statement[] | undefined)[] = []; // Exports to defer until an EndOfDeclarationMarker is found. let currentSourceFile: SourceFile; // The current file. let currentModuleInfo: ExternalModuleInfo; // The ExternalModuleInfo for the current file. - const noSubstitution = new Set(); // Set of nodes for which substitution rules should be ignored. + const noSubstitution: boolean[] = []; // Set of nodes for which substitution rules should be ignored. let needUMDDynamicImportHelper: boolean; return chainBundle(context, transformSourceFile); @@ -65,7 +65,7 @@ namespace ts { currentSourceFile = node; currentModuleInfo = collectExternalModuleInfo(context, node, resolver, compilerOptions); - moduleInfoMap.set(getOriginalNode(node), currentModuleInfo); + moduleInfoMap[getOriginalNodeId(node)] = currentModuleInfo; // Perform the transformation. const transformModule = getTransformModuleDelegate(moduleKind); @@ -692,13 +692,13 @@ namespace ts { } for (const exportName of exportedNames) { - noSubstitution.add(expression); + noSubstitution[getNodeId(expression)] = true; expression = createExportExpression(exportName, expression); setTextRange(expression, node); } if (temp) { - noSubstitution.add(expression); + noSubstitution[getNodeId(expression)] = true; expression = factory.createComma(expression, temp); setTextRange(expression, node); } @@ -981,8 +981,8 @@ namespace ts { if (hasAssociatedEndOfDeclarationMarker(node)) { // Defer exports until we encounter an EndOfDeclarationMarker node - const originalNode = getOriginalNode(node); - deferredExports.set(originalNode, appendExportsOfImportDeclaration(deferredExports.get(originalNode), node)); + const id = getOriginalNodeId(node); + deferredExports[id] = appendExportsOfImportDeclaration(deferredExports[id], node); } else { statements = appendExportsOfImportDeclaration(statements, node); @@ -1072,8 +1072,8 @@ namespace ts { if (hasAssociatedEndOfDeclarationMarker(node)) { // Defer exports until we encounter an EndOfDeclarationMarker node - const originalNode = getOriginalNode(node); - deferredExports.set(originalNode, appendExportsOfImportEqualsDeclaration(deferredExports.get(originalNode), node)); + const id = getOriginalNodeId(node); + deferredExports[id] = appendExportsOfImportEqualsDeclaration(deferredExports[id], node); } else { statements = appendExportsOfImportEqualsDeclaration(statements, node); @@ -1206,8 +1206,8 @@ namespace ts { const original = node.original; if (original && hasAssociatedEndOfDeclarationMarker(original)) { // Defer exports until we encounter an EndOfDeclarationMarker node - const originalNode = getOriginalNode(node); - deferredExports.set(originalNode, appendExportStatement(deferredExports.get(originalNode), factory.createIdentifier("default"), visitNode(node.expression, visitor), /*location*/ node, /*allowComments*/ true)); + const id = getOriginalNodeId(node); + deferredExports[id] = appendExportStatement(deferredExports[id], factory.createIdentifier("default"), visitNode(node.expression, visitor), /*location*/ node, /*allowComments*/ true); } else { statements = appendExportStatement(statements, factory.createIdentifier("default"), visitNode(node.expression, visitor), /*location*/ node, /*allowComments*/ true); @@ -1249,8 +1249,8 @@ namespace ts { if (hasAssociatedEndOfDeclarationMarker(node)) { // Defer exports until we encounter an EndOfDeclarationMarker node - const originalNode = getOriginalNode(node); - deferredExports.set(originalNode, appendExportsOfHoistedDeclaration(deferredExports.get(originalNode), node)); + const id = getOriginalNodeId(node); + deferredExports[id] = appendExportsOfHoistedDeclaration(deferredExports[id], node); } else { statements = appendExportsOfHoistedDeclaration(statements, node); @@ -1290,8 +1290,8 @@ namespace ts { if (hasAssociatedEndOfDeclarationMarker(node)) { // Defer exports until we encounter an EndOfDeclarationMarker node - const originalNode = getOriginalNode(node); - deferredExports.set(originalNode, appendExportsOfHoistedDeclaration(deferredExports.get(originalNode), node)); + const id = getOriginalNodeId(node); + deferredExports[id] = appendExportsOfHoistedDeclaration(deferredExports[id], node); } else { statements = appendExportsOfHoistedDeclaration(statements, node); @@ -1370,8 +1370,8 @@ namespace ts { if (hasAssociatedEndOfDeclarationMarker(node)) { // Defer exports until we encounter an EndOfDeclarationMarker node - const originalNode = getOriginalNode(node); - deferredExports.set(originalNode, appendExportsOfVariableStatement(deferredExports.get(originalNode), node)); + const id = getOriginalNodeId(node); + deferredExports[id] = appendExportsOfVariableStatement(deferredExports[id], node); } else { statements = appendExportsOfVariableStatement(statements, node); @@ -1441,8 +1441,8 @@ namespace ts { // To balance the declaration, add the exports of the elided variable // statement. if (hasAssociatedEndOfDeclarationMarker(node) && node.original!.kind === SyntaxKind.VariableStatement) { - const originalNode = getOriginalNode(node); - deferredExports.set(originalNode, appendExportsOfVariableStatement(deferredExports.get(originalNode), node.original as VariableStatement)); + const id = getOriginalNodeId(node); + deferredExports[id] = appendExportsOfVariableStatement(deferredExports[id], node.original as VariableStatement); } return node; @@ -1467,10 +1467,10 @@ namespace ts { // For some transformations we emit an `EndOfDeclarationMarker` to mark the actual // end of the transformed declaration. We use this marker to emit any deferred exports // of the declaration. - const originalNode = getOriginalNode(node); - const statements = deferredExports.get(originalNode); + const id = getOriginalNodeId(node); + const statements = deferredExports[id]; if (statements) { - deferredExports.delete(node); + delete deferredExports[id]; return append(statements, node); } @@ -1770,7 +1770,7 @@ namespace ts { function onEmitNode(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void): void { if (node.kind === SyntaxKind.SourceFile) { currentSourceFile = node as SourceFile; - currentModuleInfo = moduleInfoMap.get(getOriginalNode(currentSourceFile))!; + currentModuleInfo = moduleInfoMap[getOriginalNodeId(currentSourceFile)]; previousOnEmitNode(hint, node, emitCallback); @@ -1794,7 +1794,7 @@ namespace ts { */ function onSubstituteNode(hint: EmitHint, node: Node) { node = previousOnSubstituteNode(hint, node); - if (noSubstitution.has(node)) { + if (node.id && noSubstitution[node.id]) { return node; } @@ -1852,7 +1852,7 @@ namespace ts { function substituteCallExpression(node: CallExpression) { if (isIdentifier(node.expression)) { const expression = substituteExpressionIdentifier(node.expression); - noSubstitution.add(expression); + noSubstitution[getNodeId(expression)] = true; if (!isIdentifier(expression)) { return addEmitFlags( factory.updateCallExpression(node, @@ -1871,7 +1871,7 @@ namespace ts { function substituteTaggedTemplateExpression(node: TaggedTemplateExpression) { if (isIdentifier(node.tag)) { const tag = substituteExpressionIdentifier(node.tag); - noSubstitution.add(tag); + noSubstitution[getNodeId(tag)] = true; if (!isIdentifier(tag)) { return addEmitFlags( factory.updateTaggedTemplateExpression(node, @@ -1962,7 +1962,7 @@ namespace ts { let expression: Expression = node; for (const exportName of exportedNames) { // Mark the node to prevent triggering this rule again. - noSubstitution.add(expression); + noSubstitution[getNodeId(expression)] = true; expression = createExportExpression(exportName, expression, /*location*/ node); } @@ -1984,7 +1984,7 @@ namespace ts { || resolver.getReferencedValueDeclaration(name); if (valueDeclaration) { return currentModuleInfo - && currentModuleInfo.exportedBindings.get(getOriginalNode(valueDeclaration)); + && currentModuleInfo.exportedBindings[getOriginalNodeId(valueDeclaration)]; } } } diff --git a/src/compiler/transformers/module/system.ts b/src/compiler/transformers/module/system.ts index cf8ef6b7af3..14216e5cab6 100644 --- a/src/compiler/transformers/module/system.ts +++ b/src/compiler/transformers/module/system.ts @@ -26,11 +26,11 @@ namespace ts { context.enableSubstitution(SyntaxKind.MetaProperty); // Substitutes 'import.meta' context.enableEmitNotification(SyntaxKind.SourceFile); // Restore state when substituting nodes in a file. - const moduleInfoMap = new Map(); // The ExternalModuleInfo for each file. - const deferredExports = new Map(); // Exports to defer until an EndOfDeclarationMarker is found. - const exportFunctionsMap = new Map(); // The export function associated with a source file. - const noSubstitutionMap = new Map>(); // Set of nodes for which substitution rules should be ignored for each file. - const contextObjectMap = new Map(); // The context object associated with a source file. + const moduleInfoMap: ExternalModuleInfo[] = []; // The ExternalModuleInfo for each file. + const deferredExports: (Statement[] | undefined)[] = []; // Exports to defer until an EndOfDeclarationMarker is found. + const exportFunctionsMap: Identifier[] = []; // The export function associated with a source file. + const noSubstitutionMap: boolean[][] = []; // Set of nodes for which substitution rules should be ignored for each file. + const contextObjectMap: Identifier[] = []; // The context object associated with a source file. let currentSourceFile: SourceFile; // The current file. let moduleInfo: ExternalModuleInfo; // ExternalModuleInfo for the current file. @@ -38,7 +38,7 @@ namespace ts { let contextObject: Identifier; // The context object for the current file. let hoistedStatements: Statement[] | undefined; let enclosingBlockScopedContainer: Node; - let noSubstitution: Set | undefined; // Set of nodes for which substitution rules should be ignored. + let noSubstitution: boolean[] | undefined; // Set of nodes for which substitution rules should be ignored. return chainBundle(context, transformSourceFile); @@ -52,7 +52,7 @@ namespace ts { return node; } - const originalNode = getOriginalNode(node); + const id = getOriginalNodeId(node); currentSourceFile = node; enclosingBlockScopedContainer = node; @@ -70,13 +70,13 @@ namespace ts { // see comment to 'substitutePostfixUnaryExpression' for more details // Collect information about the external module and dependency groups. - moduleInfoMap.set(originalNode, moduleInfo = collectExternalModuleInfo(context, node, resolver, compilerOptions)); + moduleInfo = moduleInfoMap[id] = collectExternalModuleInfo(context, node, resolver, compilerOptions); // Make sure that the name of the 'exports' function does not conflict with // existing identifiers. exportFunction = factory.createUniqueName("exports"); - exportFunctionsMap.set(originalNode, exportFunction); - contextObjectMap.set(originalNode, contextObject = factory.createUniqueName("context")); + exportFunctionsMap[id] = exportFunction; + contextObject = contextObjectMap[id] = factory.createUniqueName("context"); // Add the body of the module. const dependencyGroups = collectDependencyGroups(moduleInfo.externalImports); @@ -123,7 +123,7 @@ namespace ts { } if (noSubstitution) { - noSubstitutionMap.set(originalNode, noSubstitution); + noSubstitutionMap[id] = noSubstitution; noSubstitution = undefined; } @@ -596,8 +596,8 @@ namespace ts { if (hasAssociatedEndOfDeclarationMarker(node)) { // Defer exports until we encounter an EndOfDeclarationMarker node - const originalNode = getOriginalNode(node); - deferredExports.set(originalNode, appendExportsOfImportDeclaration(deferredExports.get(originalNode), node)); + const id = getOriginalNodeId(node); + deferredExports[id] = appendExportsOfImportDeclaration(deferredExports[id], node); } else { statements = appendExportsOfImportDeclaration(statements, node); @@ -624,8 +624,8 @@ namespace ts { if (hasAssociatedEndOfDeclarationMarker(node)) { // Defer exports until we encounter an EndOfDeclarationMarker node - const originalNode = getOriginalNode(node); - deferredExports.set(originalNode, appendExportsOfImportEqualsDeclaration(deferredExports.get(originalNode), node)); + const id = getOriginalNodeId(node); + deferredExports[id] = appendExportsOfImportEqualsDeclaration(deferredExports[id], node); } else { statements = appendExportsOfImportEqualsDeclaration(statements, node); @@ -649,8 +649,8 @@ namespace ts { const original = node.original; if (original && hasAssociatedEndOfDeclarationMarker(original)) { // Defer exports until we encounter an EndOfDeclarationMarker node - const originalNode = getOriginalNode(node); - deferredExports.set(originalNode, appendExportStatement(deferredExports.get(originalNode), factory.createIdentifier("default"), expression, /*allowComments*/ true)); + const id = getOriginalNodeId(node); + deferredExports[id] = appendExportStatement(deferredExports[id], factory.createIdentifier("default"), expression, /*allowComments*/ true); } else { return createExportStatement(factory.createIdentifier("default"), expression, /*allowComments*/ true); @@ -682,8 +682,8 @@ namespace ts { if (hasAssociatedEndOfDeclarationMarker(node)) { // Defer exports until we encounter an EndOfDeclarationMarker node - const originalNode = getOriginalNode(node); - deferredExports.set(originalNode, appendExportsOfHoistedDeclaration(deferredExports.get(originalNode), node)); + const id = getOriginalNodeId(node); + deferredExports[id] = appendExportsOfHoistedDeclaration(deferredExports[id], node); } else { hoistedStatements = appendExportsOfHoistedDeclaration(hoistedStatements, node); @@ -729,8 +729,8 @@ namespace ts { if (hasAssociatedEndOfDeclarationMarker(node)) { // Defer exports until we encounter an EndOfDeclarationMarker node - const originalNode = getOriginalNode(node); - deferredExports.set(originalNode, appendExportsOfHoistedDeclaration(deferredExports.get(originalNode), node)); + const id = getOriginalNodeId(node); + deferredExports[id] = appendExportsOfHoistedDeclaration(deferredExports[id], node); } else { statements = appendExportsOfHoistedDeclaration(statements, node); @@ -769,8 +769,8 @@ namespace ts { if (isMarkedDeclaration) { // Defer exports until we encounter an EndOfDeclarationMarker node - const originalNode = getOriginalNode(node); - deferredExports.set(originalNode, appendExportsOfVariableStatement(deferredExports.get(originalNode), node, isExportedDeclaration)); + const id = getOriginalNodeId(node); + deferredExports[id] = appendExportsOfVariableStatement(deferredExports[id], node, isExportedDeclaration); } else { statements = appendExportsOfVariableStatement(statements, node, /*exportSelf*/ false); @@ -881,9 +881,9 @@ namespace ts { // To balance the declaration, we defer the exports of the elided variable // statement until we visit this declaration's `EndOfDeclarationMarker`. if (hasAssociatedEndOfDeclarationMarker(node) && node.original!.kind === SyntaxKind.VariableStatement) { - const originalNode = getOriginalNode(node); + const id = getOriginalNodeId(node); const isExportedDeclaration = hasSyntacticModifier(node.original!, ModifierFlags.Export); - deferredExports.set(originalNode, appendExportsOfVariableStatement(deferredExports.get(originalNode), node.original as VariableStatement, isExportedDeclaration)); + deferredExports[id] = appendExportsOfVariableStatement(deferredExports[id], node.original as VariableStatement, isExportedDeclaration); } return node; @@ -908,15 +908,16 @@ namespace ts { // For some transformations we emit an `EndOfDeclarationMarker` to mark the actual // end of the transformed declaration. We use this marker to emit any deferred exports // of the declaration. - const originalNode = getOriginalNode(node); - const statements = deferredExports.get(originalNode); + const id = getOriginalNodeId(node); + const statements = deferredExports[id]; if (statements) { - deferredExports.delete(originalNode); + delete deferredExports[id]; return append(statements, node); } else { - if (isModuleOrEnumDeclaration(originalNode)) { - return append(appendExportsOfDeclaration(statements, originalNode), node); + const original = getOriginalNode(node); + if (isModuleOrEnumDeclaration(original)) { + return append(appendExportsOfDeclaration(statements, original), node); } } @@ -1677,14 +1678,16 @@ namespace ts { */ function onEmitNode(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void): void { if (node.kind === SyntaxKind.SourceFile) { - const originalNode = getOriginalNode(node); + const id = getOriginalNodeId(node); currentSourceFile = node as SourceFile; - moduleInfo = moduleInfoMap.get(originalNode)!; - exportFunction = exportFunctionsMap.get(originalNode)!; - noSubstitution = noSubstitutionMap.get(originalNode)!; - contextObject = contextObjectMap.get(originalNode)!; + moduleInfo = moduleInfoMap[id]; + exportFunction = exportFunctionsMap[id]; + noSubstitution = noSubstitutionMap[id]; + contextObject = contextObjectMap[id]; - noSubstitutionMap.delete(originalNode); + if (noSubstitution) { + delete noSubstitutionMap[id]; + } previousOnEmitNode(hint, node, emitCallback); @@ -1901,7 +1904,7 @@ namespace ts { exportedNames = append(exportedNames, factory.getDeclarationName(valueDeclaration)); } - exportedNames = addRange(exportedNames, moduleInfo && moduleInfo.exportedBindings.get(getOriginalNode(valueDeclaration))); + exportedNames = addRange(exportedNames, moduleInfo && moduleInfo.exportedBindings[getOriginalNodeId(valueDeclaration)]); } } @@ -1914,7 +1917,8 @@ namespace ts { * @param node The node which should not be substituted. */ function preventSubstitution(node: T): T { - (noSubstitution ||= new Set()).add(node); + if (noSubstitution === undefined) noSubstitution = []; + noSubstitution[getNodeId(node)] = true; return node; } @@ -1924,7 +1928,7 @@ namespace ts { * @param node The node to test. */ function isSubstitutionPrevented(node: Node) { - return noSubstitution?.has(node); + return noSubstitution && node.id && noSubstitution[node.id]; } } } diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts index 6013ec97f11..8561db1c633 100644 --- a/src/compiler/transformers/ts.ts +++ b/src/compiler/transformers/ts.ts @@ -78,7 +78,7 @@ namespace ts { * A map that keeps track of aliases created for classes with decorators to avoid issues * with the double-binding behavior of classes. */ - let classAliases: ESMap; + let classAliases: Identifier[]; /** * Keeps track of whether we are within any containing namespaces when performing @@ -1237,7 +1237,7 @@ namespace ts { return undefined; } - const classAlias = classAliases?.get(getOriginalNode(node)); + const classAlias = classAliases && classAliases[getOriginalNodeId(node)]; // When we transform to ES5/3 this will be moved inside an IIFE and should reference the name // without any block-scoped variable collision handling @@ -3139,7 +3139,7 @@ namespace ts { if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.ClassWithConstructorReference) { enableSubstitutionForClassAliases(); const classAlias = factory.createUniqueName(node.name && !isGeneratedIdentifier(node.name) ? idText(node.name) : "default"); - classAliases.set(getOriginalNode(node), classAlias); + classAliases[getOriginalNodeId(node)] = classAlias; hoistVariableDeclaration(classAlias); return classAlias; } @@ -3171,7 +3171,7 @@ namespace ts { context.enableSubstitution(SyntaxKind.Identifier); // Keep track of class aliases. - classAliases = new Map(); + classAliases = []; } } @@ -3290,7 +3290,7 @@ namespace ts { // constructor references in static property initializers. const declaration = resolver.getReferencedValueDeclaration(node); if (declaration) { - const classAlias = classAliases.get(declaration); + const classAlias = classAliases[declaration.id!]; // TODO: GH#18217 if (classAlias) { const clone = factory.cloneNode(classAlias); setSourceMapRange(clone, node); diff --git a/src/compiler/transformers/utilities.ts b/src/compiler/transformers/utilities.ts index c920e96b32d..276d034c7b9 100644 --- a/src/compiler/transformers/utilities.ts +++ b/src/compiler/transformers/utilities.ts @@ -1,10 +1,15 @@ /* @internal */ namespace ts { + export function getOriginalNodeId(node: Node) { + node = getOriginalNode(node); + return node ? getNodeId(node) : 0; + } + export interface ExternalModuleInfo { externalImports: (ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration)[]; // imports of other external modules externalHelpersImportDeclaration: ImportDeclaration | undefined; // import of external helpers exportSpecifiers: ESMap; // file-local export specifiers by name (no reexports) - exportedBindings: MultiMap; // exported names of local declarations + exportedBindings: Identifier[][]; // exported names of local declarations exportedNames: Identifier[] | undefined; // all exported names in the module, both local and reexported exportEquals: ExportAssignment | undefined; // an export= declaration if one was present hasExportStarsToExportValues: boolean; // whether this module contains export* @@ -63,7 +68,7 @@ namespace ts { export function collectExternalModuleInfo(context: TransformationContext, sourceFile: SourceFile, resolver: EmitResolver, compilerOptions: CompilerOptions): ExternalModuleInfo { const externalImports: (ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration)[] = []; const exportSpecifiers = createMultiMap(); - const exportedBindings = createMultiMap(); + const exportedBindings: Identifier[][] = []; const uniqueExports = new Map(); let exportedNames: Identifier[] | undefined; let hasExportDefault = false; @@ -113,7 +118,7 @@ namespace ts { else { const name = ((node as ExportDeclaration).exportClause as NamespaceExport).name; if (!uniqueExports.get(idText(name))) { - exportedBindings.add(getOriginalNode(node), name); + multiMapSparseArrayAdd(exportedBindings, getOriginalNodeId(node), name); uniqueExports.set(idText(name), true); exportedNames = append(exportedNames, name); } @@ -148,7 +153,7 @@ namespace ts { if (hasSyntacticModifier(node, ModifierFlags.Default)) { // export default function() { } if (!hasExportDefault) { - exportedBindings.add(getOriginalNode(node), context.factory.getDeclarationName(node as FunctionDeclaration)); + multiMapSparseArrayAdd(exportedBindings, getOriginalNodeId(node), context.factory.getDeclarationName(node as FunctionDeclaration)); hasExportDefault = true; } } @@ -156,7 +161,7 @@ namespace ts { // export function x() { } const name = (node as FunctionDeclaration).name!; if (!uniqueExports.get(idText(name))) { - exportedBindings.add(getOriginalNode(node), name); + multiMapSparseArrayAdd(exportedBindings, getOriginalNodeId(node), name); uniqueExports.set(idText(name), true); exportedNames = append(exportedNames, name); } @@ -169,7 +174,7 @@ namespace ts { if (hasSyntacticModifier(node, ModifierFlags.Default)) { // export default class { } if (!hasExportDefault) { - exportedBindings.add(getOriginalNode(node), context.factory.getDeclarationName(node as ClassDeclaration)); + multiMapSparseArrayAdd(exportedBindings, getOriginalNodeId(node), context.factory.getDeclarationName(node as ClassDeclaration)); hasExportDefault = true; } } @@ -177,7 +182,7 @@ namespace ts { // export class x { } const name = (node as ClassDeclaration).name; if (name && !uniqueExports.get(idText(name))) { - exportedBindings.add(getOriginalNode(node), name); + multiMapSparseArrayAdd(exportedBindings, getOriginalNodeId(node), name); uniqueExports.set(idText(name), true); exportedNames = append(exportedNames, name); } @@ -206,7 +211,7 @@ namespace ts { || resolver.getReferencedValueDeclaration(name); if (decl) { - exportedBindings.add(getOriginalNode(decl), specifier.name); + multiMapSparseArrayAdd(exportedBindings, getOriginalNodeId(decl), specifier.name); } uniqueExports.set(idText(specifier.name), true); @@ -234,6 +239,18 @@ namespace ts { return exportedNames; } + /** Use a sparse array as a multi-map. */ + function multiMapSparseArrayAdd(map: V[][], key: number, value: V): V[] { + let values = map[key]; + if (values) { + values.push(value); + } + else { + map[key] = values = [value]; + } + return values; + } + /** * Used in the module transformer to check if an expression is reasonably without sideeffect, * and thus better to copy into multiple places rather than to cache in a temporary variable diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 35e5d68d9b8..170c65b1271 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -4908,7 +4908,7 @@ namespace ts { /* @internal */ isReferenced?: SymbolFlags; // True if the symbol is referenced elsewhere. Keeps track of the meaning of a reference in case a symbol is both a type parameter and parameter. /* @internal */ isReplaceableByMethod?: boolean; // Can this Javascript class property be replaced by a method symbol? /* @internal */ isAssigned?: boolean; // True if the symbol is a parameter with assignments - /* @internal */ assignmentDeclarationMembers?: Set; // detected late-bound assignment declarations associated with the symbol + /* @internal */ assignmentDeclarationMembers?: ESMap; // detected late-bound assignment declarations associated with the symbol } /* @internal */ @@ -4946,7 +4946,7 @@ namespace ts { lateSymbol?: Symbol; // Late-bound symbol for a computed property specifierCache?: ESMap; // For symbols corresponding to external modules, a cache of incoming path -> module specifier name mappings extendedContainers?: Symbol[]; // Containers (other than the parent) which this symbol is aliased in - extendedContainersByFile?: ESMap; // Containers (other than the parent) which this symbol is aliased in + extendedContainersByFile?: ESMap; // Containers (other than the parent) which this symbol is aliased in variances?: VarianceFlags[]; // Alias symbol type argument variance cache deferralConstituents?: Type[]; // Calculated list of constituents for a deferred type deferralParent?: Type; // Source union/intersection of a deferred type @@ -5106,7 +5106,7 @@ namespace ts { jsxNamespace?: Symbol | false; // Resolved jsx namespace symbol for this node jsxImplicitImportContainer?: Symbol | false; // Resolved module symbol the implicit jsx import of this file should refer to contextFreeType?: Type; // Cached context-free type used by the first pass of inference; used when a function's return is partially contextually sensitive - deferredNodes?: Set; // Set of nodes whose checking has been deferred + deferredNodes?: ESMap; // Set of nodes whose checking has been deferred capturedBlockScopeBindings?: Symbol[]; // Block-scoped bindings captured beneath this part of an IterationStatement outerTypeParameters?: TypeParameter[]; // Outer type parameters of anonymous object type isExhaustive?: boolean; // Is node an exhaustive switch statement