Skip to content

Commit

Permalink
Merge diagnosticsProducing and nonDiagnosticsProducing checkers into …
Browse files Browse the repository at this point in the history
…a single checker supporting lazy diagnostics (#36747)

* Merge diagnosticsProducing and nonDiagnosticsProducing checkers into a single checker supporting lazy diagnostics

* Fix lint
  • Loading branch information
weswigham authored Mar 23, 2022
1 parent 26c701c commit b5a3a05
Show file tree
Hide file tree
Showing 14 changed files with 595 additions and 517 deletions.
915 changes: 497 additions & 418 deletions src/compiler/checker.ts

Large diffs are not rendered by default.

47 changes: 14 additions & 33 deletions src/compiler/program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1025,8 +1025,7 @@ namespace ts {
let files: SourceFile[];
let symlinks: SymlinkCache | undefined;
let commonSourceDirectory: string;
let diagnosticsProducingTypeChecker: TypeChecker;
let noDiagnosticsTypeChecker: TypeChecker;
let typeChecker: TypeChecker;
let classifiableNames: Set<__String>;
const ambientModuleNameToUnmodifiedFileName = new Map<string, string>();
let fileReasons = createMultiMap<Path, FileIncludeReason>();
Expand Down Expand Up @@ -1304,21 +1303,19 @@ namespace ts {
getProgramDiagnostics,
getTypeChecker,
getClassifiableNames,
getDiagnosticsProducingTypeChecker,
getCommonSourceDirectory,
emit,
getCurrentDirectory: () => currentDirectory,
getNodeCount: () => getDiagnosticsProducingTypeChecker().getNodeCount(),
getIdentifierCount: () => getDiagnosticsProducingTypeChecker().getIdentifierCount(),
getSymbolCount: () => getDiagnosticsProducingTypeChecker().getSymbolCount(),
getTypeCount: () => getDiagnosticsProducingTypeChecker().getTypeCount(),
getInstantiationCount: () => getDiagnosticsProducingTypeChecker().getInstantiationCount(),
getRelationCacheSizes: () => getDiagnosticsProducingTypeChecker().getRelationCacheSizes(),
getNodeCount: () => getTypeChecker().getNodeCount(),
getIdentifierCount: () => getTypeChecker().getIdentifierCount(),
getSymbolCount: () => getTypeChecker().getSymbolCount(),
getTypeCount: () => getTypeChecker().getTypeCount(),
getInstantiationCount: () => getTypeChecker().getInstantiationCount(),
getRelationCacheSizes: () => getTypeChecker().getRelationCacheSizes(),
getFileProcessingDiagnostics: () => fileProcessingDiagnostics,
getResolvedTypeReferenceDirectives: () => resolvedTypeReferenceDirectives,
isSourceFileFromExternalLibrary,
isSourceFileDefaultLibrary,
dropDiagnosticsProducingTypeChecker,
getSourceFileFromReference,
getLibFileFromReference,
sourceFileToPackageName,
Expand Down Expand Up @@ -1980,16 +1977,8 @@ namespace ts {
}
}

function getDiagnosticsProducingTypeChecker() {
return diagnosticsProducingTypeChecker || (diagnosticsProducingTypeChecker = createTypeChecker(program, /*produceDiagnostics:*/ true));
}

function dropDiagnosticsProducingTypeChecker() {
diagnosticsProducingTypeChecker = undefined!;
}

function getTypeChecker() {
return noDiagnosticsTypeChecker || (noDiagnosticsTypeChecker = createTypeChecker(program, /*produceDiagnostics:*/ false));
return typeChecker || (typeChecker = createTypeChecker(program));
}

function emit(sourceFile?: SourceFile, writeFileCallback?: WriteFileCallback, cancellationToken?: CancellationToken, emitOnlyDtsFiles?: boolean, transformers?: CustomTransformers, forceDtsEmit?: boolean): EmitResult {
Expand Down Expand Up @@ -2017,7 +2006,7 @@ namespace ts {
// This is because in the -out scenario all files need to be emitted, and therefore all
// files need to be type checked. And the way to specify that all files need to be type
// checked is to not pass the file to getEmitResolver.
const emitResolver = getDiagnosticsProducingTypeChecker().getEmitResolver(outFile(options) ? undefined : sourceFile, cancellationToken);
const emitResolver = getTypeChecker().getEmitResolver(outFile(options) ? undefined : sourceFile, cancellationToken);

performance.mark("beforeEmit");

Expand Down Expand Up @@ -2121,15 +2110,7 @@ namespace ts {
if (e instanceof OperationCanceledException) {
// We were canceled while performing the operation. Because our type checker
// might be a bad state, we need to throw it away.
//
// Note: we are overly aggressive here. We do not actually *have* to throw away
// the "noDiagnosticsTypeChecker". However, for simplicity, i'd like to keep
// the lifetimes of these two TypeCheckers the same. Also, we generally only
// cancel when the user has made a change anyways. And, in that case, we (the
// program instance) will get thrown away anyways. So trying to keep one of
// these type checkers alive doesn't serve much purpose.
noDiagnosticsTypeChecker = undefined!;
diagnosticsProducingTypeChecker = undefined!;
typeChecker = undefined!;
}

throw e;
Expand All @@ -2153,7 +2134,7 @@ namespace ts {
return emptyArray;
}

const typeChecker = getDiagnosticsProducingTypeChecker();
const typeChecker = getTypeChecker();

Debug.assert(!!sourceFile.bindDiagnostics);

Expand Down Expand Up @@ -2209,7 +2190,7 @@ namespace ts {

function getSuggestionDiagnostics(sourceFile: SourceFile, cancellationToken: CancellationToken): readonly DiagnosticWithLocation[] {
return runWithCancellationToken(() => {
return getDiagnosticsProducingTypeChecker().getSuggestionDiagnostics(sourceFile, cancellationToken);
return getTypeChecker().getSuggestionDiagnostics(sourceFile, cancellationToken);
});
}

Expand Down Expand Up @@ -2446,7 +2427,7 @@ namespace ts {

function getDeclarationDiagnosticsForFileNoCache(sourceFile: SourceFile | undefined, cancellationToken: CancellationToken | undefined): readonly DiagnosticWithLocation[] {
return runWithCancellationToken(() => {
const resolver = getDiagnosticsProducingTypeChecker().getEmitResolver(sourceFile, cancellationToken);
const resolver = getTypeChecker().getEmitResolver(sourceFile, cancellationToken);
// Don't actually write any files since we're just getting diagnostics.
return ts.getDeclarationDiagnostics(getEmitHost(noop), resolver, sourceFile) || emptyArray;
});
Expand Down Expand Up @@ -2497,7 +2478,7 @@ namespace ts {
}

function getGlobalDiagnostics(): SortedReadonlyArray<Diagnostic> {
return rootNames.length ? sortAndDeduplicateDiagnostics(getDiagnosticsProducingTypeChecker().getGlobalDiagnostics().slice()) : emptyArray as any as SortedReadonlyArray<Diagnostic>;
return rootNames.length ? sortAndDeduplicateDiagnostics(getTypeChecker().getGlobalDiagnostics().slice()) : emptyArray as any as SortedReadonlyArray<Diagnostic>;
}

function getConfigFileParsingDiagnostics(): readonly Diagnostic[] {
Expand Down
5 changes: 0 additions & 5 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4016,11 +4016,6 @@ namespace ts {

/* @internal */ getCommonSourceDirectory(): string;

// For testing purposes only. Should not be used by any other consumers (including the
// language service).
/* @internal */ getDiagnosticsProducingTypeChecker(): TypeChecker;
/* @internal */ dropDiagnosticsProducingTypeChecker(): void;

/* @internal */ getCachedSemanticDiagnostics(sourceFile?: SourceFile): readonly Diagnostic[] | undefined;

/* @internal */ getClassifiableNames(): Set<__String>;
Expand Down
2 changes: 1 addition & 1 deletion src/harness/harnessIO.ts
Original file line number Diff line number Diff line change
Expand Up @@ -717,7 +717,7 @@ namespace Harness {
// These types are equivalent, but depend on what order the compiler observed
// certain parts of the program.

const fullWalker = new TypeWriterWalker(program, /*fullTypeCheck*/ true, !!hasErrorBaseline);
const fullWalker = new TypeWriterWalker(program, !!hasErrorBaseline);

// Produce baselines. The first gives the types for all expressions.
// The second gives symbols for all identifiers.
Expand Down
6 changes: 2 additions & 4 deletions src/harness/typeWriter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,10 @@ namespace Harness {

private checker: ts.TypeChecker;

constructor(private program: ts.Program, fullTypeCheck: boolean, private hadErrorBaseline: boolean) {
constructor(private program: ts.Program, private hadErrorBaseline: boolean) {
// Consider getting both the diagnostics checker and the non-diagnostics checker to verify
// they are consistent.
this.checker = fullTypeCheck
? program.getDiagnosticsProducingTypeChecker()
: program.getTypeChecker();
this.checker = program.getTypeChecker();
}

public *getSymbols(fileName: string): IterableIterator<TypeWriterSymbolResult> {
Expand Down
2 changes: 1 addition & 1 deletion src/services/codefixes/addMissingAsync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ namespace ts.codefix {
errorCodes,
getCodeActions: function getCodeActionsToAddMissingAsync(context) {
const { sourceFile, errorCode, cancellationToken, program, span } = context;
const diagnostic = find(program.getDiagnosticsProducingTypeChecker().getDiagnostics(sourceFile, cancellationToken), getIsMatchingAsyncError(span, errorCode));
const diagnostic = find(program.getTypeChecker().getDiagnostics(sourceFile, cancellationToken), getIsMatchingAsyncError(span, errorCode));
const directSpan = diagnostic && diagnostic.relatedInformation && find(diagnostic.relatedInformation, r => r.code === Diagnostics.Did_you_mean_to_mark_this_function_as_async.code) as TextSpan | undefined;

const decl = getFixableErrorSpanDeclaration(sourceFile, directSpan);
Expand Down
2 changes: 1 addition & 1 deletion src/services/codefixes/addMissingAwait.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ namespace ts.codefix {
}

function isMissingAwaitError(sourceFile: SourceFile, errorCode: number, span: TextSpan, cancellationToken: CancellationToken, program: Program) {
const checker = program.getDiagnosticsProducingTypeChecker();
const checker = program.getTypeChecker();
const diagnostics = checker.getDiagnostics(sourceFile, cancellationToken);
return some(diagnostics, ({ start, length, relatedInformation, code }) =>
isNumber(start) && isNumber(length) && textSpansEqual({ start, length }, span) &&
Expand Down
Loading

0 comments on commit b5a3a05

Please sign in to comment.