@@ -47502,6 +47502,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
47502
47502
}
47503
47503
47504
47504
function checkSourceElementWorker(node: Node): void {
47505
+ if (getNodeCheckFlags(node) & NodeCheckFlags.PartiallyTypeChecked) {
47506
+ return;
47507
+ }
47508
+
47505
47509
if (canHaveJSDoc(node)) {
47506
47510
forEach(node.jsDoc, ({ comment, tags }) => {
47507
47511
checkJSDocCommentWorker(comment);
@@ -47530,6 +47534,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
47530
47534
errorOrSuggestion(compilerOptions.allowUnreachableCode === false, node, Diagnostics.Unreachable_code_detected);
47531
47535
}
47532
47536
47537
+ // If editing this, keep `isSourceElement` in utilities up to date.
47533
47538
switch (kind) {
47534
47539
case SyntaxKind.TypeParameter:
47535
47540
return checkTypeParameter(node as TypeParameterDeclaration);
@@ -47894,12 +47899,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
47894
47899
tracing?.pop();
47895
47900
}
47896
47901
47897
- function checkSourceFile(node: SourceFile) {
47898
- tracing?.push(tracing.Phase.Check, "checkSourceFile", { path: node.path }, /*separateBeginAndEnd*/ true);
47899
- performance.mark("beforeCheck");
47900
- checkSourceFileWorker(node);
47901
- performance.mark("afterCheck");
47902
- performance.measure("Check", "beforeCheck", "afterCheck");
47902
+ function checkSourceFile(node: SourceFile, nodesToCheck: Node[] | undefined) {
47903
+ tracing?.push(tracing.Phase.Check, nodesToCheck ? "checkSourceFileNodes" : "checkSourceFile", { path: node.path }, /*separateBeginAndEnd*/ true);
47904
+ const beforeMark = nodesToCheck ? "beforeCheckNodes" : "beforeCheck";
47905
+ const afterMark = nodesToCheck ? "afterCheckNodes" : "afterCheck";
47906
+ performance.mark(beforeMark);
47907
+ nodesToCheck ? checkSourceFileNodesWorker(node, nodesToCheck) : checkSourceFileWorker(node);
47908
+ performance.mark(afterMark);
47909
+ performance.measure("Check", beforeMark, afterMark);
47903
47910
tracing?.pop();
47904
47911
}
47905
47912
@@ -47938,6 +47945,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
47938
47945
clear(potentialReflectCollisions);
47939
47946
clear(potentialUnusedRenamedBindingElementsInTypes);
47940
47947
47948
+ if (links.flags & NodeCheckFlags.PartiallyTypeChecked) {
47949
+ potentialThisCollisions = links.potentialThisCollisions!;
47950
+ potentialNewTargetCollisions = links.potentialNewTargetCollisions!;
47951
+ potentialWeakMapSetCollisions = links.potentialWeakMapSetCollisions!;
47952
+ potentialReflectCollisions = links.potentialReflectCollisions!;
47953
+ potentialUnusedRenamedBindingElementsInTypes = links.potentialUnusedRenamedBindingElementsInTypes!;
47954
+ }
47955
+
47941
47956
forEach(node.statements, checkSourceElement);
47942
47957
checkSourceElement(node.endOfFileToken);
47943
47958
@@ -47989,13 +48004,49 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
47989
48004
}
47990
48005
}
47991
48006
47992
- function getDiagnostics(sourceFile: SourceFile, ct: CancellationToken): Diagnostic[] {
48007
+ function checkSourceFileNodesWorker(file: SourceFile, nodes: readonly Node[]) {
48008
+ const links = getNodeLinks(file);
48009
+ if (!(links.flags & NodeCheckFlags.TypeChecked)) {
48010
+ if (skipTypeChecking(file, compilerOptions, host)) {
48011
+ return;
48012
+ }
48013
+
48014
+ // Grammar checking
48015
+ checkGrammarSourceFile(file);
48016
+
48017
+ clear(potentialThisCollisions);
48018
+ clear(potentialNewTargetCollisions);
48019
+ clear(potentialWeakMapSetCollisions);
48020
+ clear(potentialReflectCollisions);
48021
+ clear(potentialUnusedRenamedBindingElementsInTypes);
48022
+
48023
+ forEach(nodes, checkSourceElement);
48024
+
48025
+ checkDeferredNodes(file);
48026
+
48027
+ (links.potentialThisCollisions || (links.potentialThisCollisions = [])).push(...potentialThisCollisions);
48028
+ (links.potentialNewTargetCollisions || (links.potentialNewTargetCollisions = [])).push(...potentialNewTargetCollisions);
48029
+ (links.potentialWeakMapSetCollisions || (links.potentialWeakMapSetCollisions = [])).push(...potentialWeakMapSetCollisions);
48030
+ (links.potentialReflectCollisions || (links.potentialReflectCollisions = [])).push(...potentialReflectCollisions);
48031
+ (links.potentialUnusedRenamedBindingElementsInTypes || (links.potentialUnusedRenamedBindingElementsInTypes = [])).push(
48032
+ ...potentialUnusedRenamedBindingElementsInTypes,
48033
+ );
48034
+
48035
+ links.flags |= NodeCheckFlags.PartiallyTypeChecked;
48036
+ for (const node of nodes) {
48037
+ const nodeLinks = getNodeLinks(node);
48038
+ nodeLinks.flags |= NodeCheckFlags.PartiallyTypeChecked;
48039
+ }
48040
+ }
48041
+ }
48042
+
48043
+ function getDiagnostics(sourceFile: SourceFile, ct: CancellationToken, nodesToCheck?: Node[]): Diagnostic[] {
47993
48044
try {
47994
48045
// Record the cancellation token so it can be checked later on during checkSourceElement.
47995
48046
// Do this in a finally block so we can ensure that it gets reset back to nothing after
47996
48047
// this call is done.
47997
48048
cancellationToken = ct;
47998
- return getDiagnosticsWorker(sourceFile);
48049
+ return getDiagnosticsWorker(sourceFile, nodesToCheck );
47999
48050
}
48000
48051
finally {
48001
48052
cancellationToken = undefined;
@@ -48010,7 +48061,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
48010
48061
deferredDiagnosticsCallbacks = [];
48011
48062
}
48012
48063
48013
- function checkSourceFileWithEagerDiagnostics(sourceFile: SourceFile) {
48064
+ function checkSourceFileWithEagerDiagnostics(sourceFile: SourceFile, nodesToCheck?: Node[] ) {
48014
48065
ensurePendingDiagnosticWorkComplete();
48015
48066
// then setup diagnostics for immediate invocation (as we are about to collect them, and
48016
48067
// this avoids the overhead of longer-lived callbacks we don't need to allocate)
@@ -48019,11 +48070,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
48019
48070
// thus much more likely retaining the same union ordering as before we had lazy diagnostics)
48020
48071
const oldAddLazyDiagnostics = addLazyDiagnostic;
48021
48072
addLazyDiagnostic = cb => cb();
48022
- checkSourceFile(sourceFile);
48073
+ checkSourceFile(sourceFile, nodesToCheck );
48023
48074
addLazyDiagnostic = oldAddLazyDiagnostics;
48024
48075
}
48025
48076
48026
- function getDiagnosticsWorker(sourceFile: SourceFile): Diagnostic[] {
48077
+ function getDiagnosticsWorker(sourceFile: SourceFile, nodesToCheck: Node[] | undefined ): Diagnostic[] {
48027
48078
if (sourceFile) {
48028
48079
ensurePendingDiagnosticWorkComplete();
48029
48080
// Some global diagnostics are deferred until they are needed and
@@ -48032,9 +48083,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
48032
48083
const previousGlobalDiagnostics = diagnostics.getGlobalDiagnostics();
48033
48084
const previousGlobalDiagnosticsSize = previousGlobalDiagnostics.length;
48034
48085
48035
- checkSourceFileWithEagerDiagnostics(sourceFile);
48036
-
48086
+ checkSourceFileWithEagerDiagnostics(sourceFile, nodesToCheck);
48037
48087
const semanticDiagnostics = diagnostics.getDiagnostics(sourceFile.fileName);
48088
+ if (nodesToCheck) {
48089
+ // No need to get global diagnostics.
48090
+ return semanticDiagnostics;
48091
+ }
48038
48092
const currentGlobalDiagnostics = diagnostics.getGlobalDiagnostics();
48039
48093
if (currentGlobalDiagnostics !== previousGlobalDiagnostics) {
48040
48094
// If the arrays are not the same reference, new diagnostics were added.
@@ -48053,7 +48107,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
48053
48107
48054
48108
// Global diagnostics are always added when a file is not provided to
48055
48109
// getDiagnostics
48056
- forEach(host.getSourceFiles(), checkSourceFileWithEagerDiagnostics);
48110
+ forEach(host.getSourceFiles(), file => checkSourceFileWithEagerDiagnostics(file) );
48057
48111
return diagnostics.getDiagnostics();
48058
48112
}
48059
48113
0 commit comments