@@ -491,7 +491,24 @@ namespace ts {
491491 return resolveModuleNamesWorker ( moduleNames , containingFile ) ;
492492 }
493493
494- // at this point we know at least one of the following hold:
494+ const oldSourceFile = oldProgramState . program && oldProgramState . program . getSourceFile ( containingFile ) ;
495+ if ( oldSourceFile !== file && file . resolvedModules ) {
496+ // `file` was created for the new program.
497+ //
498+ // We only set `file.resolvedModules` via work from the current function,
499+ // so it is defined iff we already called the current function on `file`.
500+ // That call happened no later than the creation of the `file` object,
501+ // which per above occured during the current program creation.
502+ // Since we model program creation as an atomic operation w/r/t IO,
503+ // it is safe to reuse resolutions from the earlier call.
504+ const result : ResolvedModuleFull [ ] = [ ] ;
505+ for ( const moduleName of moduleNames ) {
506+ const resolvedModule = file . resolvedModules . get ( moduleName ) ;
507+ result . push ( resolvedModule ) ;
508+ }
509+ return result ;
510+ }
511+ // At this point, we know at least one of the following hold:
495512 // - file has local declarations for ambient modules
496513 // - old program state is available
497514 // With this information, we can infer some module resolutions without performing resolution.
@@ -511,7 +528,6 @@ namespace ts {
511528 /** A transient placeholder used to mark predicted resolution in the result list. */
512529 const predictedToResolveToAmbientModuleMarker : ResolvedModuleFull = < any > { } ;
513530
514- const oldSourceFile = oldProgramState . program && oldProgramState . program . getSourceFile ( containingFile ) ;
515531
516532 for ( let i = 0 ; i < moduleNames . length ; i ++ ) {
517533 const moduleName = moduleNames [ i ] ;
@@ -620,7 +636,7 @@ namespace ts {
620636 return oldProgram . structureIsReused = StructureIsReused . Not ;
621637 }
622638
623- Debug . assert ( ! ( oldProgram . structureIsReused & ( StructureIsReused . Completely | StructureIsReused . ModulesInUneditedFiles ) ) ) ;
639+ Debug . assert ( ! ( oldProgram . structureIsReused & ( StructureIsReused . Completely | StructureIsReused . SafeModules ) ) ) ;
624640
625641 // there is an old program, check if we can reuse its structure
626642 const oldRootNames = oldProgram . getRootFileNames ( ) ;
@@ -653,32 +669,34 @@ namespace ts {
653669 filePaths . push ( newSourceFile . path ) ;
654670
655671 if ( oldSourceFile !== newSourceFile ) {
672+ // The `newSourceFile` object was created for the new program.
673+
656674 if ( oldSourceFile . hasNoDefaultLib !== newSourceFile . hasNoDefaultLib ) {
657675 // value of no-default-lib has changed
658676 // this will affect if default library is injected into the list of files
659- oldProgram . structureIsReused = StructureIsReused . ModulesInUneditedFiles ;
677+ oldProgram . structureIsReused = StructureIsReused . SafeModules ;
660678 }
661679
662680 // check tripleslash references
663681 if ( ! arrayIsEqualTo ( oldSourceFile . referencedFiles , newSourceFile . referencedFiles , fileReferenceIsEqualTo ) ) {
664682 // tripleslash references has changed
665- oldProgram . structureIsReused = StructureIsReused . ModulesInUneditedFiles ;
683+ oldProgram . structureIsReused = StructureIsReused . SafeModules ;
666684 }
667685
668686 // check imports and module augmentations
669687 collectExternalModuleReferences ( newSourceFile ) ;
670688 if ( ! arrayIsEqualTo ( oldSourceFile . imports , newSourceFile . imports , moduleNameIsEqualTo ) ) {
671689 // imports has changed
672- oldProgram . structureIsReused = StructureIsReused . ModulesInUneditedFiles ;
690+ oldProgram . structureIsReused = StructureIsReused . SafeModules ;
673691 }
674692 if ( ! arrayIsEqualTo ( oldSourceFile . moduleAugmentations , newSourceFile . moduleAugmentations , moduleNameIsEqualTo ) ) {
675693 // moduleAugmentations has changed
676- oldProgram . structureIsReused = StructureIsReused . ModulesInUneditedFiles ;
694+ oldProgram . structureIsReused = StructureIsReused . SafeModules ;
677695 }
678696
679697 if ( ! arrayIsEqualTo ( oldSourceFile . typeReferenceDirectives , newSourceFile . typeReferenceDirectives , fileReferenceIsEqualTo ) ) {
680698 // 'types' references has changed
681- oldProgram . structureIsReused = StructureIsReused . ModulesInUneditedFiles ;
699+ oldProgram . structureIsReused = StructureIsReused . SafeModules ;
682700 }
683701
684702 // tentatively approve the file
@@ -695,7 +713,7 @@ namespace ts {
695713
696714 modifiedFilePaths = modifiedSourceFiles . map ( f => f . newFile . path ) ;
697715 // try to verify results of module resolution
698- modifiedSourceFilesLoop: for ( const { oldFile : oldSourceFile , newFile : newSourceFile } of modifiedSourceFiles ) {
716+ for ( const { oldFile : oldSourceFile , newFile : newSourceFile } of modifiedSourceFiles ) {
699717 const newSourceFilePath = getNormalizedAbsolutePath ( newSourceFile . fileName , currentDirectory ) ;
700718 if ( resolveModuleNamesWorker ) {
701719 const moduleNames = map ( concatenate ( newSourceFile . imports , newSourceFile . moduleAugmentations ) , getTextOfLiteral ) ;
@@ -704,8 +722,11 @@ namespace ts {
704722 // ensure that module resolution results are still correct
705723 const resolutionsChanged = hasChangesInResolutions ( moduleNames , resolutions , oldSourceFile . resolvedModules , moduleResolutionIsEqualTo ) ;
706724 if ( resolutionsChanged ) {
707- oldProgram . structureIsReused = StructureIsReused . ModulesInUneditedFiles ;
708- continue modifiedSourceFilesLoop;
725+ oldProgram . structureIsReused = StructureIsReused . SafeModules ;
726+ newSourceFile . resolvedModules = zipToMap ( moduleNames , resolutions ) ;
727+ }
728+ else {
729+ newSourceFile . resolvedModules = oldSourceFile . resolvedModules ;
709730 }
710731 }
711732 if ( resolveTypeReferenceDirectiveNamesWorker ) {
@@ -714,13 +735,13 @@ namespace ts {
714735 // ensure that types resolutions are still correct
715736 const resolutionsChanged = hasChangesInResolutions ( typesReferenceDirectives , resolutions , oldSourceFile . resolvedTypeReferenceDirectiveNames , typeDirectiveIsEqualTo ) ;
716737 if ( resolutionsChanged ) {
717- oldProgram . structureIsReused = StructureIsReused . ModulesInUneditedFiles ;
718- continue modifiedSourceFilesLoop;
738+ oldProgram . structureIsReused = StructureIsReused . SafeModules ;
739+ newSourceFile . resolvedTypeReferenceDirectiveNames = zipToMap ( typesReferenceDirectives , resolutions ) ;
740+ }
741+ else {
742+ newSourceFile . resolvedTypeReferenceDirectiveNames = oldSourceFile . resolvedTypeReferenceDirectiveNames ;
719743 }
720744 }
721- // pass the cache of module/types resolutions from the old source file
722- newSourceFile . resolvedModules = oldSourceFile . resolvedModules ;
723- newSourceFile . resolvedTypeReferenceDirectiveNames = oldSourceFile . resolvedTypeReferenceDirectiveNames ;
724745 }
725746
726747 if ( oldProgram . structureIsReused !== StructureIsReused . Completely ) {
0 commit comments