From cf0ddfdd616118d7441d8dae5f0e2ee335c504b8 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Wed, 26 Sep 2018 13:54:02 -0700 Subject: [PATCH] Store and check deferred nodes by containing file --- src/compiler/checker.ts | 23 +++++++++++++---------- src/compiler/types.ts | 1 + 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index a66a7edcf183d..1be721aeea0b1 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -511,7 +511,6 @@ namespace ts { let deferredGlobalImportMetaType: ObjectType; let deferredGlobalExtractSymbol: Symbol; - let deferredNodes: Map | undefined; const allPotentiallyUnusedIdentifiers = createMap(); // key is file name let flowLoopStart = 0; @@ -21161,6 +21160,7 @@ namespace ts { function checkFunctionExpressionOrObjectLiteralMethod(node: FunctionExpression | MethodDeclaration, checkMode?: CheckMode): Type { Debug.assert(node.kind !== SyntaxKind.MethodDeclaration || isObjectLiteralMethod(node)); + checkNodeDeferred(node); // The identityMapper object is used to indicate that function expressions are wildcards if (checkMode === CheckMode.SkipContextSensitive && isContextSensitive(node)) { @@ -21218,7 +21218,6 @@ namespace ts { } } checkSignatureDeclaration(node); - checkNodeDeferred(node); } } @@ -27291,14 +27290,21 @@ namespace ts { // determining the type of foo would cause foo to be given type any because of the recursive reference. // Delaying the type check of the body ensures foo has been assigned a type. function checkNodeDeferred(node: Node) { - if (deferredNodes) { + const enclosingFile = getSourceFileOfNode(node); + const links = getNodeLinks(enclosingFile); + if (!(links.flags & NodeCheckFlags.TypeChecked)) { + links.deferredNodes = links.deferredNodes || createMap(); const id = "" + getNodeId(node); - deferredNodes.set(id, node); + links.deferredNodes.set(id, node); } } - function checkDeferredNodes() { - deferredNodes!.forEach(node => { + function checkDeferredNodes(context: SourceFile) { + const links = getNodeLinks(context); + if (!links.deferredNodes) { + return; + } + links.deferredNodes.forEach(node => { switch (node.kind) { case SyntaxKind.FunctionExpression: case SyntaxKind.ArrowFunction: @@ -27359,10 +27365,9 @@ namespace ts { clear(potentialThisCollisions); clear(potentialNewTargetCollisions); - deferredNodes = createMap(); forEach(node.statements, checkSourceElement); - checkDeferredNodes(); + checkDeferredNodes(node); if (isExternalOrCommonJsModule(node)) { registerForUnusedIdentifiersCheck(node); @@ -27376,8 +27381,6 @@ namespace ts { }); } - deferredNodes = undefined; - if (isExternalOrCommonJsModule(node)) { checkExternalModuleExports(node); } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 97ef69d41e58c..5dbd9e4c06358 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3700,6 +3700,7 @@ namespace ts { switchTypes?: Type[]; // Cached array of switch case expression types jsxNamespace?: Symbol | false; // Resolved jsx namespace symbol for this node contextFreeType?: Type; // Cached context-free type used by the first pass of inference; used when a function's return is partially contextually sensitive + deferredNodes?: Map; // Set of nodes whose checking has been deferred } export const enum TypeFlags {