From d9da1e237fb812901e9e079909e63097c1695edb Mon Sep 17 00:00:00 2001 From: Andrew Casey Date: Wed, 4 May 2022 22:42:48 +0000 Subject: [PATCH 1/6] Remove unnecessary members of HostCache --- src/services/services.ts | 31 ++++--------------------------- 1 file changed, 4 insertions(+), 27 deletions(-) diff --git a/src/services/services.ts b/src/services/services.ts index ac731115bebda..f0aa6e51a170f 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -997,13 +997,12 @@ namespace ts { private fileNameToEntry: ESMap; private currentDirectory: string; - constructor(private host: LanguageServiceHost, getCanonicalFileName: GetCanonicalFileName) { + constructor(private host: LanguageServiceHost, rootFileNames: readonly string[], getCanonicalFileName: GetCanonicalFileName) { // script id => script index this.currentDirectory = host.getCurrentDirectory(); this.fileNameToEntry = new Map(); // Initialize the list with the root file names - const rootFileNames = host.getScriptFileNames(); tracing?.push(tracing.Phase.Session, "initializeHostCache", { count: rootFileNames.length }); for (const fileName of rootFileNames) { this.createEntry(fileName, toPath(fileName, this.currentDirectory, getCanonicalFileName)); @@ -1034,33 +1033,10 @@ namespace ts { return this.fileNameToEntry.get(path); } - public getHostFileInformation(path: Path): HostFileInformation | undefined { - const entry = this.fileNameToEntry.get(path); - return !isString(entry) ? entry : undefined; - } - public getOrCreateEntryByPath(fileName: string, path: Path): HostFileInformation { const info = this.getEntryByPath(path) || this.createEntry(fileName, path); return isString(info) ? undefined! : info; // TODO: GH#18217 } - - public getRootFileNames(): string[] { - const names: string[] = []; - this.fileNameToEntry.forEach(entry => { - if (isString(entry)) { - names.push(entry); - } - else { - names.push(entry.hostFileName); - } - }); - return names; - } - - public getScriptSnapshot(path: Path): IScriptSnapshot { - const file = this.getHostFileInformation(path); - return (file && file.scriptSnapshot)!; // TODO: GH#18217 - } } class SyntaxTreeCache { @@ -1366,9 +1342,10 @@ namespace ts { lastTypesRootVersion = typeRootsVersion; } + const rootFileNames = host.getScriptFileNames(); + // Get a fresh cache of the host information - let hostCache: HostCache | undefined = new HostCache(host, getCanonicalFileName); - const rootFileNames = hostCache.getRootFileNames(); + let hostCache: HostCache | undefined = new HostCache(host, rootFileNames, getCanonicalFileName); const newSettings = host.getCompilationSettings() || getDefaultCompilerOptions(); const hasInvalidatedResolution: HasInvalidatedResolution = host.hasInvalidatedResolution || returnFalse; const hasChangedAutomaticTypeDirectiveNames = maybeBind(host, host.hasChangedAutomaticTypeDirectiveNames); From fccc9c7c49de72ca2ce62cd9cead7f93f1dda598 Mon Sep 17 00:00:00 2001 From: Andrew Casey Date: Wed, 4 May 2022 16:25:37 -0700 Subject: [PATCH 2/6] Standardize on calling compiler host members in preparation for adding caching at that layer --- src/services/services.ts | 89 +++++++++++++++++++--------------------- 1 file changed, 42 insertions(+), 47 deletions(-) diff --git a/src/services/services.ts b/src/services/services.ts index f0aa6e51a170f..5dfa679bd73fd 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1351,26 +1351,6 @@ namespace ts { const hasChangedAutomaticTypeDirectiveNames = maybeBind(host, host.hasChangedAutomaticTypeDirectiveNames); const projectReferences = host.getProjectReferences?.(); let parsedCommandLines: ESMap | undefined; - const parseConfigHost: ParseConfigFileHost = { - useCaseSensitiveFileNames, - fileExists, - readFile, - readDirectory, - trace: maybeBind(host, host.trace), - getCurrentDirectory: () => currentDirectory, - onUnRecoverableConfigFileDiagnostic: noop, - }; - - // If the program is already up-to-date, we can reuse it - if (isProgramUptoDate(program, rootFileNames, newSettings, (_path, fileName) => host.getScriptVersion(fileName), fileExists, hasInvalidatedResolution, hasChangedAutomaticTypeDirectiveNames, getParsedCommandLine, projectReferences)) { - return; - } - - // IMPORTANT - It is critical from this moment onward that we do not check - // cancellation tokens. We are about to mutate source files from a previous program - // instance. If we cancel midway through, we may end up in an inconsistent state where - // the program points to old source files that have been invalidated because of - // incremental parsing. // Now create a new compiler const compilerHost: CompilerHost = { @@ -1383,8 +1363,22 @@ namespace ts { getDefaultLibFileName: options => host.getDefaultLibFileName(options), writeFile: noop, getCurrentDirectory: () => currentDirectory, - fileExists, - readFile, + fileExists: fileName => { + const path = toPath(fileName, currentDirectory, getCanonicalFileName); + const entry = hostCache && hostCache.getEntryByPath(path); + return entry ? + !isString(entry) : + (!!host.fileExists && host.fileExists(fileName)); + }, + readFile: fileName => { + // stub missing host functionality + const path = toPath(fileName, currentDirectory, getCanonicalFileName); + const entry = hostCache && hostCache.getEntryByPath(path); + if (entry) { + return isString(entry) ? undefined : getSnapshotText(entry.scriptSnapshot); + } + return host.readFile && host.readFile(fileName); + }, getSymlinkCache: maybeBind(host, host.getSymlinkCache), realpath: maybeBind(host, host.realpath), directoryExists: directoryName => { @@ -1393,12 +1387,15 @@ namespace ts { getDirectories: path => { return host.getDirectories ? host.getDirectories(path) : []; }, - readDirectory, + readDirectory: (path: string, extensions?: readonly string[], exclude?: readonly string[], include?: readonly string[], depth?: number) => { + Debug.checkDefined(host.readDirectory, "'LanguageServiceHost.readDirectory' must be implemented to correctly process 'projectReferences'"); + return host.readDirectory!(path, extensions, exclude, include, depth); + }, onReleaseOldSourceFile, onReleaseParsedCommandLine, hasInvalidatedResolution, hasChangedAutomaticTypeDirectiveNames, - trace: parseConfigHost.trace, + trace: maybeBind(host, host.trace), resolveModuleNames: maybeBind(host, host.resolveModuleNames), getModuleResolutionCache: maybeBind(host, host.getModuleResolutionCache), resolveTypeReferenceDirectives: maybeBind(host, host.resolveTypeReferenceDirectives), @@ -1407,6 +1404,27 @@ namespace ts { }; host.setCompilerHost?.(compilerHost); + const parseConfigHost: ParseConfigFileHost = { + useCaseSensitiveFileNames, + fileExists: compilerHost.fileExists, + readFile: compilerHost.readFile, + readDirectory: compilerHost.readDirectory!, + trace: compilerHost.trace, + getCurrentDirectory: compilerHost.getCurrentDirectory, + onUnRecoverableConfigFileDiagnostic: noop, + }; + + // If the program is already up-to-date, we can reuse it + if (isProgramUptoDate(program, rootFileNames, newSettings, (_path, fileName) => host.getScriptVersion(fileName), compilerHost.fileExists, hasInvalidatedResolution, hasChangedAutomaticTypeDirectiveNames, getParsedCommandLine, projectReferences)) { + return; + } + + // IMPORTANT - It is critical from this moment onward that we do not check + // cancellation tokens. We are about to mutate source files from a previous program + // instance. If we cancel midway through, we may end up in an inconsistent state where + // the program points to old source files that have been invalidated because of + // incremental parsing. + const documentRegistryBucketKey = documentRegistry.getKeyForCompilationSettings(newSettings); const options: CreateProgramOptions = { rootNames: rootFileNames, @@ -1468,29 +1486,6 @@ namespace ts { } } - function fileExists(fileName: string): boolean { - const path = toPath(fileName, currentDirectory, getCanonicalFileName); - const entry = hostCache && hostCache.getEntryByPath(path); - return entry ? - !isString(entry) : - (!!host.fileExists && host.fileExists(fileName)); - } - - function readFile(fileName: string) { - // stub missing host functionality - const path = toPath(fileName, currentDirectory, getCanonicalFileName); - const entry = hostCache && hostCache.getEntryByPath(path); - if (entry) { - return isString(entry) ? undefined : getSnapshotText(entry.scriptSnapshot); - } - return host.readFile && host.readFile(fileName); - } - - function readDirectory(path: string, extensions?: readonly string[], exclude?: readonly string[], include?: readonly string[], depth?: number) { - Debug.checkDefined(host.readDirectory, "'LanguageServiceHost.readDirectory' must be implemented to correctly process 'projectReferences'"); - return host.readDirectory!(path, extensions, exclude, include, depth); - } - // Release any files we have acquired in the old program but are // not part of the new program. function onReleaseOldSourceFile(oldSourceFile: SourceFile, oldOptions: CompilerOptions) { From deb1ef79b372a779b6fa1d0f2043f1cc0ab95b4a Mon Sep 17 00:00:00 2001 From: Andrew Casey Date: Thu, 5 May 2022 10:36:05 -0700 Subject: [PATCH 3/6] Call changeCompilerHostLikeToUseCache to cache existence checks --- src/services/services.ts | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/src/services/services.ts b/src/services/services.ts index 5dfa679bd73fd..323a3e90ea098 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1402,20 +1402,37 @@ namespace ts { useSourceOfProjectReferenceRedirect: maybeBind(host, host.useSourceOfProjectReferenceRedirect), getParsedCommandLine, }; + + const originalGetSourceFile = compilerHost.getSourceFile; + + const { + originalReadFile, + originalFileExists, + originalDirectoryExists, + originalCreateDirectory, + originalWriteFile, + getSourceFileWithCache, + } = changeCompilerHostLikeToUseCache( + compilerHost, + fileName => toPath(fileName, currentDirectory, getCanonicalFileName), + (...args) => originalGetSourceFile.call(compilerHost, ...args) + ); + compilerHost.getSourceFile = getSourceFileWithCache!; + host.setCompilerHost?.(compilerHost); const parseConfigHost: ParseConfigFileHost = { useCaseSensitiveFileNames, - fileExists: compilerHost.fileExists, - readFile: compilerHost.readFile, - readDirectory: compilerHost.readDirectory!, + fileExists: fileName => compilerHost.fileExists(fileName), + readFile: fileName => compilerHost.readFile(fileName), + readDirectory: (...args) => compilerHost.readDirectory!(...args), trace: compilerHost.trace, getCurrentDirectory: compilerHost.getCurrentDirectory, onUnRecoverableConfigFileDiagnostic: noop, }; // If the program is already up-to-date, we can reuse it - if (isProgramUptoDate(program, rootFileNames, newSettings, (_path, fileName) => host.getScriptVersion(fileName), compilerHost.fileExists, hasInvalidatedResolution, hasChangedAutomaticTypeDirectiveNames, getParsedCommandLine, projectReferences)) { + if (isProgramUptoDate(program, rootFileNames, newSettings, (_path, fileName) => host.getScriptVersion(fileName), fileName => compilerHost.fileExists(fileName), hasInvalidatedResolution, hasChangedAutomaticTypeDirectiveNames, getParsedCommandLine, projectReferences)) { return; } @@ -1438,6 +1455,12 @@ namespace ts { // hostCache is captured in the closure for 'getOrCreateSourceFile' but it should not be used past this point. // It needs to be cleared to allow all collected snapshots to be released hostCache = undefined; + compilerHost.getSourceFile = originalGetSourceFile; + compilerHost.readFile = originalReadFile; + compilerHost.fileExists = originalFileExists; + compilerHost.directoryExists = originalDirectoryExists; + compilerHost.createDirectory = originalCreateDirectory; + compilerHost.writeFile = originalWriteFile!; parsedCommandLines = undefined; // We reset this cache on structure invalidation so we don't hold on to outdated files for long; however we can't use the `compilerHost` above, From 9a961c6ea28066f309ad99f652137b704f031c50 Mon Sep 17 00:00:00 2001 From: Andrew Casey Date: Thu, 5 May 2022 16:29:34 -0700 Subject: [PATCH 4/6] Drop now-redundant HostCache --- src/services/services.ts | 101 ++++++--------------------------------- 1 file changed, 15 insertions(+), 86 deletions(-) diff --git a/src/services/services.ts b/src/services/services.ts index 323a3e90ea098..56491a393cadf 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -926,14 +926,6 @@ namespace ts { /// Language Service - // Information about a specific host file. - interface HostFileInformation { - hostFileName: string; - version: string; - scriptSnapshot: IScriptSnapshot; - scriptKind: ScriptKind; - } - /* @internal */ export interface DisplayPartsSymbolWriter extends EmitTextWriter { displayParts(): SymbolDisplayPart[]; @@ -987,58 +979,6 @@ namespace ts { return codefix.getSupportedErrorCodes(); } - // Either it will be file name if host doesnt have file or it will be the host's file information - type CachedHostFileInformation = HostFileInformation | string; - - // Cache host information about script Should be refreshed - // at each language service public entry point, since we don't know when - // the set of scripts handled by the host changes. - class HostCache { - private fileNameToEntry: ESMap; - private currentDirectory: string; - - constructor(private host: LanguageServiceHost, rootFileNames: readonly string[], getCanonicalFileName: GetCanonicalFileName) { - // script id => script index - this.currentDirectory = host.getCurrentDirectory(); - this.fileNameToEntry = new Map(); - - // Initialize the list with the root file names - tracing?.push(tracing.Phase.Session, "initializeHostCache", { count: rootFileNames.length }); - for (const fileName of rootFileNames) { - this.createEntry(fileName, toPath(fileName, this.currentDirectory, getCanonicalFileName)); - } - tracing?.pop(); - } - - private createEntry(fileName: string, path: Path) { - let entry: CachedHostFileInformation; - const scriptSnapshot = this.host.getScriptSnapshot(fileName); - if (scriptSnapshot) { - entry = { - hostFileName: fileName, - version: this.host.getScriptVersion(fileName), - scriptSnapshot, - scriptKind: getScriptKind(fileName, this.host) - }; - } - else { - entry = fileName; - } - - this.fileNameToEntry.set(path, entry); - return entry; - } - - public getEntryByPath(path: Path): CachedHostFileInformation | undefined { - return this.fileNameToEntry.get(path); - } - - public getOrCreateEntryByPath(fileName: string, path: Path): HostFileInformation { - const info = this.getEntryByPath(path) || this.createEntry(fileName, path); - return isString(info) ? undefined! : info; // TODO: GH#18217 - } - } - class SyntaxTreeCache { // For our syntactic only features, we also keep a cache of the syntax tree for the // currently edited file. @@ -1345,7 +1285,6 @@ namespace ts { const rootFileNames = host.getScriptFileNames(); // Get a fresh cache of the host information - let hostCache: HostCache | undefined = new HostCache(host, rootFileNames, getCanonicalFileName); const newSettings = host.getCompilationSettings() || getDefaultCompilerOptions(); const hasInvalidatedResolution: HasInvalidatedResolution = host.hasInvalidatedResolution || returnFalse; const hasChangedAutomaticTypeDirectiveNames = maybeBind(host, host.hasChangedAutomaticTypeDirectiveNames); @@ -1363,22 +1302,8 @@ namespace ts { getDefaultLibFileName: options => host.getDefaultLibFileName(options), writeFile: noop, getCurrentDirectory: () => currentDirectory, - fileExists: fileName => { - const path = toPath(fileName, currentDirectory, getCanonicalFileName); - const entry = hostCache && hostCache.getEntryByPath(path); - return entry ? - !isString(entry) : - (!!host.fileExists && host.fileExists(fileName)); - }, - readFile: fileName => { - // stub missing host functionality - const path = toPath(fileName, currentDirectory, getCanonicalFileName); - const entry = hostCache && hostCache.getEntryByPath(path); - if (entry) { - return isString(entry) ? undefined : getSnapshotText(entry.scriptSnapshot); - } - return host.readFile && host.readFile(fileName); - }, + fileExists: fileName => host.fileExists(fileName), + readFile: fileName => host.readFile && host.readFile(fileName), getSymlinkCache: maybeBind(host, host.getSymlinkCache), realpath: maybeBind(host, host.realpath), directoryExists: directoryName => { @@ -1420,6 +1345,7 @@ namespace ts { compilerHost.getSourceFile = getSourceFileWithCache!; host.setCompilerHost?.(compilerHost); + let cachingInEffect = true; const parseConfigHost: ParseConfigFileHost = { useCaseSensitiveFileNames, @@ -1452,9 +1378,9 @@ namespace ts { }; program = createProgram(options); - // hostCache is captured in the closure for 'getOrCreateSourceFile' but it should not be used past this point. - // It needs to be cleared to allow all collected snapshots to be released - hostCache = undefined; + // 'getOrCreateSourceFile' depends on caching but should be used past this point. + // After this point, the cache needs to be cleared to allow all collected snapshots to be released + cachingInEffect = false; compilerHost.getSourceFile = originalGetSourceFile; compilerHost.readFile = originalReadFile; compilerHost.fileExists = originalFileExists; @@ -1521,15 +1447,18 @@ namespace ts { } function getOrCreateSourceFileByPath(fileName: string, path: Path, _languageVersion: ScriptTarget, _onError?: (message: string) => void, shouldCreateNewSourceFile?: boolean): SourceFile | undefined { - Debug.assert(hostCache !== undefined, "getOrCreateSourceFileByPath called after typical CompilerHost lifetime, check the callstack something with a reference to an old host."); + Debug.assert(cachingInEffect, "getOrCreateSourceFileByPath called after typical CompilerHost lifetime, check the callstack something with a reference to an old host."); // The program is asking for this file, check first if the host can locate it. // If the host can not locate the file, then it does not exist. return undefined // to the program to allow reporting of errors for missing files. - const hostFileInformation = hostCache && hostCache.getOrCreateEntryByPath(fileName, path); - if (!hostFileInformation) { + const scriptSnapshot = host.getScriptSnapshot(fileName); + if (!scriptSnapshot) { return undefined; } + const scriptKind = getScriptKind(fileName, host); + const scriptVersion = host.getScriptVersion(fileName); + // Check if the language version has changed since we last created a program; if they are the same, // it is safe to reuse the sourceFiles; if not, then the shape of the AST can change, and the oldSourceFile // can not be reused. we have to dump all syntax trees and create new ones. @@ -1562,8 +1491,8 @@ namespace ts { // We do not support the scenario where a host can modify a registered // file's script kind, i.e. in one project some file is treated as ".ts" // and in another as ".js" - if (hostFileInformation.scriptKind === oldSourceFile.scriptKind) { - return documentRegistry.updateDocumentWithKey(fileName, path, host, documentRegistryBucketKey, hostFileInformation.scriptSnapshot, hostFileInformation.version, hostFileInformation.scriptKind); + if (scriptKind === oldSourceFile.scriptKind) { + return documentRegistry.updateDocumentWithKey(fileName, path, host, documentRegistryBucketKey, scriptSnapshot, scriptVersion, scriptKind); } else { // Release old source file and fall through to aquire new file with new script kind @@ -1575,7 +1504,7 @@ namespace ts { } // Could not find this file in the old program, create a new SourceFile for it. - return documentRegistry.acquireDocumentWithKey(fileName, path, host, documentRegistryBucketKey, hostFileInformation.scriptSnapshot, hostFileInformation.version, hostFileInformation.scriptKind); + return documentRegistry.acquireDocumentWithKey(fileName, path, host, documentRegistryBucketKey, scriptSnapshot, scriptVersion, scriptKind); } } From 8053fe8cb9d76d676252ed99c6975dadf8f99217 Mon Sep 17 00:00:00 2001 From: Andrew Casey Date: Fri, 6 May 2022 00:29:32 +0000 Subject: [PATCH 5/6] Don't make directoryExists caching contingent on createDirectory --- src/compiler/program.ts | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 2caa36f14251e..66c0494e11ffc 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -282,7 +282,7 @@ namespace ts { } // directoryExists - if (originalDirectoryExists && originalCreateDirectory) { + if (originalDirectoryExists) { host.directoryExists = directory => { const key = toPath(directory); const value = directoryExistsCache.get(key); @@ -291,11 +291,14 @@ namespace ts { directoryExistsCache.set(key, !!newValue); return newValue; }; - host.createDirectory = directory => { - const key = toPath(directory); - directoryExistsCache.delete(key); - originalCreateDirectory.call(host, directory); - }; + + if (originalCreateDirectory) { + host.createDirectory = directory => { + const key = toPath(directory); + directoryExistsCache.delete(key); + originalCreateDirectory.call(host, directory); + }; + } } return { From 748d465328fc2f65742202dc5b1db2a93d121c2f Mon Sep 17 00:00:00 2001 From: Andrew Casey Date: Mon, 16 May 2022 18:04:49 -0700 Subject: [PATCH 6/6] Clear compilerHost rather than tracking state --- src/services/services.ts | 30 ++++++++---------------------- 1 file changed, 8 insertions(+), 22 deletions(-) diff --git a/src/services/services.ts b/src/services/services.ts index 56491a393cadf..00bf4cef73c4d 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1292,7 +1292,7 @@ namespace ts { let parsedCommandLines: ESMap | undefined; // Now create a new compiler - const compilerHost: CompilerHost = { + let compilerHost: CompilerHost | undefined = { getSourceFile: getOrCreateSourceFile, getSourceFileByPath: getOrCreateSourceFileByPath, getCancellationToken: () => cancellationToken, @@ -1330,14 +1330,7 @@ namespace ts { const originalGetSourceFile = compilerHost.getSourceFile; - const { - originalReadFile, - originalFileExists, - originalDirectoryExists, - originalCreateDirectory, - originalWriteFile, - getSourceFileWithCache, - } = changeCompilerHostLikeToUseCache( + const { getSourceFileWithCache } = changeCompilerHostLikeToUseCache( compilerHost, fileName => toPath(fileName, currentDirectory, getCanonicalFileName), (...args) => originalGetSourceFile.call(compilerHost, ...args) @@ -1345,20 +1338,19 @@ namespace ts { compilerHost.getSourceFile = getSourceFileWithCache!; host.setCompilerHost?.(compilerHost); - let cachingInEffect = true; const parseConfigHost: ParseConfigFileHost = { useCaseSensitiveFileNames, - fileExists: fileName => compilerHost.fileExists(fileName), - readFile: fileName => compilerHost.readFile(fileName), - readDirectory: (...args) => compilerHost.readDirectory!(...args), + fileExists: fileName => compilerHost!.fileExists(fileName), + readFile: fileName => compilerHost!.readFile(fileName), + readDirectory: (...args) => compilerHost!.readDirectory!(...args), trace: compilerHost.trace, getCurrentDirectory: compilerHost.getCurrentDirectory, onUnRecoverableConfigFileDiagnostic: noop, }; // If the program is already up-to-date, we can reuse it - if (isProgramUptoDate(program, rootFileNames, newSettings, (_path, fileName) => host.getScriptVersion(fileName), fileName => compilerHost.fileExists(fileName), hasInvalidatedResolution, hasChangedAutomaticTypeDirectiveNames, getParsedCommandLine, projectReferences)) { + if (isProgramUptoDate(program, rootFileNames, newSettings, (_path, fileName) => host.getScriptVersion(fileName), fileName => compilerHost!.fileExists(fileName), hasInvalidatedResolution, hasChangedAutomaticTypeDirectiveNames, getParsedCommandLine, projectReferences)) { return; } @@ -1380,13 +1372,7 @@ namespace ts { // 'getOrCreateSourceFile' depends on caching but should be used past this point. // After this point, the cache needs to be cleared to allow all collected snapshots to be released - cachingInEffect = false; - compilerHost.getSourceFile = originalGetSourceFile; - compilerHost.readFile = originalReadFile; - compilerHost.fileExists = originalFileExists; - compilerHost.directoryExists = originalDirectoryExists; - compilerHost.createDirectory = originalCreateDirectory; - compilerHost.writeFile = originalWriteFile!; + compilerHost = undefined; parsedCommandLines = undefined; // We reset this cache on structure invalidation so we don't hold on to outdated files for long; however we can't use the `compilerHost` above, @@ -1447,7 +1433,7 @@ namespace ts { } function getOrCreateSourceFileByPath(fileName: string, path: Path, _languageVersion: ScriptTarget, _onError?: (message: string) => void, shouldCreateNewSourceFile?: boolean): SourceFile | undefined { - Debug.assert(cachingInEffect, "getOrCreateSourceFileByPath called after typical CompilerHost lifetime, check the callstack something with a reference to an old host."); + Debug.assert(compilerHost, "getOrCreateSourceFileByPath called after typical CompilerHost lifetime, check the callstack something with a reference to an old host."); // The program is asking for this file, check first if the host can locate it. // If the host can not locate the file, then it does not exist. return undefined // to the program to allow reporting of errors for missing files.