Skip to content

Commit e6d525c

Browse files
authored
Structure is reused should be on new program instead of old program (microsoft#41005)
1 parent 876e44b commit e6d525c

File tree

220 files changed

+645
-67
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

220 files changed

+645
-67
lines changed

src/compiler/program.ts

Lines changed: 31 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -824,9 +824,9 @@ namespace ts {
824824
const shouldCreateNewSourceFile = shouldProgramCreateNewSourceFiles(oldProgram, options);
825825
// We set `structuralIsReused` to `undefined` because `tryReuseStructureFromOldProgram` calls `tryReuseStructureFromOldProgram` which checks
826826
// `structuralIsReused`, which would be a TDZ violation if it was not set in advance to `undefined`.
827-
let structuralIsReused: StructureIsReused | undefined;
828-
structuralIsReused = tryReuseStructureFromOldProgram(); // eslint-disable-line prefer-const
829-
if (structuralIsReused !== StructureIsReused.Completely) {
827+
let structureIsReused: StructureIsReused;
828+
structureIsReused = tryReuseStructureFromOldProgram(); // eslint-disable-line prefer-const
829+
if (structureIsReused !== StructureIsReused.Completely) {
830830
processingDefaultLibFiles = [];
831831
processingOtherFiles = [];
832832

@@ -979,6 +979,7 @@ namespace ts {
979979
getSymlinkCache,
980980
realpath: host.realpath?.bind(host),
981981
useCaseSensitiveFileNames: () => host.useCaseSensitiveFileNames(),
982+
structureIsReused,
982983
};
983984

984985
onProgramCreateComplete();
@@ -1107,7 +1108,7 @@ namespace ts {
11071108
}
11081109

11091110
function resolveModuleNamesReusingOldState(moduleNames: string[], file: SourceFile): readonly ResolvedModuleFull[] {
1110-
if (structuralIsReused === StructureIsReused.Not && !file.ambientModuleNames.length) {
1111+
if (structureIsReused === StructureIsReused.Not && !file.ambientModuleNames.length) {
11111112
// If the old program state does not permit reusing resolutions and `file` does not contain locally defined ambient modules,
11121113
// the best we can do is fallback to the default logic.
11131114
return resolveModuleNamesWorker(moduleNames, file, /*reusedNames*/ undefined);
@@ -1278,22 +1279,22 @@ namespace ts {
12781279
// if any of these properties has changed - structure cannot be reused
12791280
const oldOptions = oldProgram.getCompilerOptions();
12801281
if (changesAffectModuleResolution(oldOptions, options)) {
1281-
return oldProgram.structureIsReused = StructureIsReused.Not;
1282+
return StructureIsReused.Not;
12821283
}
12831284

12841285
// there is an old program, check if we can reuse its structure
12851286
const oldRootNames = oldProgram.getRootFileNames();
12861287
if (!arrayIsEqualTo(oldRootNames, rootNames)) {
1287-
return oldProgram.structureIsReused = StructureIsReused.Not;
1288+
return StructureIsReused.Not;
12881289
}
12891290

12901291
if (!arrayIsEqualTo(options.types, oldOptions.types)) {
1291-
return oldProgram.structureIsReused = StructureIsReused.Not;
1292+
return StructureIsReused.Not;
12921293
}
12931294

12941295
// Check if any referenced project tsconfig files are different
12951296
if (!canReuseProjectReferences()) {
1296-
return oldProgram.structureIsReused = StructureIsReused.Not;
1297+
return StructureIsReused.Not;
12971298
}
12981299
if (projectReferences) {
12991300
resolvedProjectReferences = projectReferences.map(parseProjectReferenceConfigFile);
@@ -1302,13 +1303,13 @@ namespace ts {
13021303
// check if program source files has changed in the way that can affect structure of the program
13031304
const newSourceFiles: SourceFile[] = [];
13041305
const modifiedSourceFiles: { oldFile: SourceFile, newFile: SourceFile }[] = [];
1305-
oldProgram.structureIsReused = StructureIsReused.Completely;
1306+
structureIsReused = StructureIsReused.Completely;
13061307

13071308
// If the missing file paths are now present, it can change the progam structure,
13081309
// and hence cant reuse the structure.
13091310
// This is same as how we dont reuse the structure if one of the file from old program is now missing
13101311
if (oldProgram.getMissingFilePaths().some(missingFilePath => host.fileExists(missingFilePath))) {
1311-
return oldProgram.structureIsReused = StructureIsReused.Not;
1312+
return StructureIsReused.Not;
13121313
}
13131314

13141315
const oldSourceFiles = oldProgram.getSourceFiles();
@@ -1321,7 +1322,7 @@ namespace ts {
13211322
: host.getSourceFile(oldSourceFile.fileName, options.target!, /*onError*/ undefined, shouldCreateNewSourceFile); // TODO: GH#18217
13221323

13231324
if (!newSourceFile) {
1324-
return oldProgram.structureIsReused = StructureIsReused.Not;
1325+
return StructureIsReused.Not;
13251326
}
13261327

13271328
Debug.assert(!newSourceFile.redirectInfo, "Host should not return a redirect source file from `getSourceFile`");
@@ -1332,15 +1333,15 @@ namespace ts {
13321333
// This lets us know if the unredirected file has changed. If it has we should break the redirect.
13331334
if (newSourceFile !== oldSourceFile.redirectInfo.unredirected) {
13341335
// Underlying file has changed. Might not redirect anymore. Must rebuild program.
1335-
return oldProgram.structureIsReused = StructureIsReused.Not;
1336+
return StructureIsReused.Not;
13361337
}
13371338
fileChanged = false;
13381339
newSourceFile = oldSourceFile; // Use the redirect.
13391340
}
13401341
else if (oldProgram.redirectTargetsMap.has(oldSourceFile.path)) {
13411342
// If a redirected-to source file changes, the redirect may be broken.
13421343
if (newSourceFile !== oldSourceFile) {
1343-
return oldProgram.structureIsReused = StructureIsReused.Not;
1344+
return StructureIsReused.Not;
13441345
}
13451346
fileChanged = false;
13461347
}
@@ -1361,7 +1362,7 @@ namespace ts {
13611362
const prevKind = seenPackageNames.get(packageName);
13621363
const newKind = fileChanged ? SeenPackageName.Modified : SeenPackageName.Exists;
13631364
if ((prevKind !== undefined && newKind === SeenPackageName.Modified) || prevKind === SeenPackageName.Modified) {
1364-
return oldProgram.structureIsReused = StructureIsReused.Not;
1365+
return StructureIsReused.Not;
13651366
}
13661367
seenPackageNames.set(packageName, newKind);
13671368
}
@@ -1371,47 +1372,47 @@ namespace ts {
13711372

13721373
if (!arrayIsEqualTo(oldSourceFile.libReferenceDirectives, newSourceFile.libReferenceDirectives, fileReferenceIsEqualTo)) {
13731374
// 'lib' references has changed. Matches behavior in changesAffectModuleResolution
1374-
return oldProgram.structureIsReused = StructureIsReused.Not;
1375+
return StructureIsReused.Not;
13751376
}
13761377

13771378
if (oldSourceFile.hasNoDefaultLib !== newSourceFile.hasNoDefaultLib) {
13781379
// value of no-default-lib has changed
13791380
// this will affect if default library is injected into the list of files
1380-
oldProgram.structureIsReused = StructureIsReused.SafeModules;
1381+
structureIsReused = StructureIsReused.SafeModules;
13811382
}
13821383

13831384
// check tripleslash references
13841385
if (!arrayIsEqualTo(oldSourceFile.referencedFiles, newSourceFile.referencedFiles, fileReferenceIsEqualTo)) {
13851386
// tripleslash references has changed
1386-
oldProgram.structureIsReused = StructureIsReused.SafeModules;
1387+
structureIsReused = StructureIsReused.SafeModules;
13871388
}
13881389

13891390
// check imports and module augmentations
13901391
collectExternalModuleReferences(newSourceFile);
13911392
if (!arrayIsEqualTo(oldSourceFile.imports, newSourceFile.imports, moduleNameIsEqualTo)) {
13921393
// imports has changed
1393-
oldProgram.structureIsReused = StructureIsReused.SafeModules;
1394+
structureIsReused = StructureIsReused.SafeModules;
13941395
}
13951396
if (!arrayIsEqualTo(oldSourceFile.moduleAugmentations, newSourceFile.moduleAugmentations, moduleNameIsEqualTo)) {
13961397
// moduleAugmentations has changed
1397-
oldProgram.structureIsReused = StructureIsReused.SafeModules;
1398+
structureIsReused = StructureIsReused.SafeModules;
13981399
}
13991400
if ((oldSourceFile.flags & NodeFlags.PermanentlySetIncrementalFlags) !== (newSourceFile.flags & NodeFlags.PermanentlySetIncrementalFlags)) {
14001401
// dynamicImport has changed
1401-
oldProgram.structureIsReused = StructureIsReused.SafeModules;
1402+
structureIsReused = StructureIsReused.SafeModules;
14021403
}
14031404

14041405
if (!arrayIsEqualTo(oldSourceFile.typeReferenceDirectives, newSourceFile.typeReferenceDirectives, fileReferenceIsEqualTo)) {
14051406
// 'types' references has changed
1406-
oldProgram.structureIsReused = StructureIsReused.SafeModules;
1407+
structureIsReused = StructureIsReused.SafeModules;
14071408
}
14081409

14091410
// tentatively approve the file
14101411
modifiedSourceFiles.push({ oldFile: oldSourceFile, newFile: newSourceFile });
14111412
}
14121413
else if (hasInvalidatedResolution(oldSourceFile.path)) {
14131414
// 'module/types' references could have changed
1414-
oldProgram.structureIsReused = StructureIsReused.SafeModules;
1415+
structureIsReused = StructureIsReused.SafeModules;
14151416

14161417
// add file to the modified list so that we will resolve it later
14171418
modifiedSourceFiles.push({ oldFile: oldSourceFile, newFile: newSourceFile });
@@ -1421,8 +1422,8 @@ namespace ts {
14211422
newSourceFiles.push(newSourceFile);
14221423
}
14231424

1424-
if (oldProgram.structureIsReused !== StructureIsReused.Completely) {
1425-
return oldProgram.structureIsReused;
1425+
if (structureIsReused !== StructureIsReused.Completely) {
1426+
return structureIsReused;
14261427
}
14271428

14281429
const modifiedFiles = modifiedSourceFiles.map(f => f.oldFile);
@@ -1440,7 +1441,7 @@ namespace ts {
14401441
// ensure that module resolution results are still correct
14411442
const resolutionsChanged = hasChangesInResolutions(moduleNames, resolutions, oldSourceFile.resolvedModules, moduleResolutionIsEqualTo);
14421443
if (resolutionsChanged) {
1443-
oldProgram.structureIsReused = StructureIsReused.SafeModules;
1444+
structureIsReused = StructureIsReused.SafeModules;
14441445
newSourceFile.resolvedModules = zipToMap(moduleNames, resolutions);
14451446
}
14461447
else {
@@ -1452,20 +1453,20 @@ namespace ts {
14521453
// ensure that types resolutions are still correct
14531454
const typeReferenceEesolutionsChanged = hasChangesInResolutions(typesReferenceDirectives, typeReferenceResolutions, oldSourceFile.resolvedTypeReferenceDirectiveNames, typeDirectiveIsEqualTo);
14541455
if (typeReferenceEesolutionsChanged) {
1455-
oldProgram.structureIsReused = StructureIsReused.SafeModules;
1456+
structureIsReused = StructureIsReused.SafeModules;
14561457
newSourceFile.resolvedTypeReferenceDirectiveNames = zipToMap(typesReferenceDirectives, typeReferenceResolutions);
14571458
}
14581459
else {
14591460
newSourceFile.resolvedTypeReferenceDirectiveNames = oldSourceFile.resolvedTypeReferenceDirectiveNames;
14601461
}
14611462
}
14621463

1463-
if (oldProgram.structureIsReused !== StructureIsReused.Completely) {
1464-
return oldProgram.structureIsReused;
1464+
if (structureIsReused !== StructureIsReused.Completely) {
1465+
return structureIsReused;
14651466
}
14661467

14671468
if (host.hasChangedAutomaticTypeDirectiveNames?.()) {
1468-
return oldProgram.structureIsReused = StructureIsReused.SafeModules;
1469+
return StructureIsReused.SafeModules;
14691470
}
14701471

14711472
missingFilePaths = oldProgram.getMissingFilePaths();
@@ -1503,7 +1504,7 @@ namespace ts {
15031504
sourceFileToPackageName = oldProgram.sourceFileToPackageName;
15041505
redirectTargetsMap = oldProgram.redirectTargetsMap;
15051506

1506-
return oldProgram.structureIsReused = StructureIsReused.Completely;
1507+
return StructureIsReused.Completely;
15071508
}
15081509

15091510
function getEmitHost(writeFileCallback?: WriteFileCallback): EmitHost {

src/compiler/types.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3779,7 +3779,8 @@ namespace ts {
37793779
isSourceFileDefaultLibrary(file: SourceFile): boolean;
37803780

37813781
// For testing purposes only.
3782-
/* @internal */ structureIsReused?: StructureIsReused;
3782+
// This is set on created program to let us know how the program was created using old program
3783+
/* @internal */ readonly structureIsReused: StructureIsReused;
37833784

37843785
/* @internal */ getSourceFileFromReference(referencingFile: SourceFile | UnparsedSource, ref: FileReference): SourceFile | undefined;
37853786
/* @internal */ getLibFileFromReference(ref: FileReference): SourceFile | undefined;

src/server/project.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1086,7 +1086,7 @@ namespace ts.server {
10861086
// bump up the version if
10871087
// - oldProgram is not set - this is a first time updateGraph is called
10881088
// - newProgram is different from the old program and structure of the old program was not reused.
1089-
const hasNewProgram = this.program && (!oldProgram || (this.program !== oldProgram && !(oldProgram.structureIsReused! & StructureIsReused.Completely)));
1089+
const hasNewProgram = this.program && (!oldProgram || (this.program !== oldProgram && !(this.program.structureIsReused & StructureIsReused.Completely)));
10901090
if (hasNewProgram) {
10911091
if (oldProgram) {
10921092
for (const f of oldProgram.getSourceFiles()) {
@@ -1153,7 +1153,7 @@ namespace ts.server {
11531153
}
11541154

11551155
if (!this.importSuggestionsCache.isEmpty()) {
1156-
if (this.hasAddedorRemovedFiles || oldProgram && !oldProgram.structureIsReused) {
1156+
if (this.hasAddedorRemovedFiles || oldProgram && !this.program.structureIsReused) {
11571157
this.importSuggestionsCache.clear();
11581158
}
11591159
else if (this.dirtyFilesForSuggestions && oldProgram && this.program) {
@@ -1194,7 +1194,7 @@ namespace ts.server {
11941194
this.print(/*writeProjectFileNames*/ true);
11951195
}
11961196
else if (this.program !== oldProgram) {
1197-
this.writeLog(`Different program with same set of files:: oldProgram.structureIsReused:: ${oldProgram && oldProgram.structureIsReused}`);
1197+
this.writeLog(`Different program with same set of files:: structureIsReused:: ${this.program.structureIsReused}`);
11981198
}
11991199
return hasNewProgram;
12001200
}

src/testRunner/unittests/moduleResolution.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1387,8 +1387,8 @@ import b = require("./moduleB");
13871387
const diagnostics1 = program1.getFileProcessingDiagnostics().getDiagnostics();
13881388
assert.equal(diagnostics1.length, 1, "expected one diagnostic");
13891389

1390-
createProgram(names, {}, compilerHost, program1);
1391-
assert.isTrue(program1.structureIsReused === StructureIsReused.Completely);
1390+
const program2 = createProgram(names, {}, compilerHost, program1);
1391+
assert.isTrue(program2.structureIsReused === StructureIsReused.Completely);
13921392
const diagnostics2 = program1.getFileProcessingDiagnostics().getDiagnostics();
13931393
assert.equal(diagnostics2.length, 1, "expected one diagnostic");
13941394
assert.equal(diagnostics1[0].messageText, diagnostics2[0].messageText, "expected one diagnostic");

0 commit comments

Comments
 (0)