diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/invalidation.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/invalidation.kt index cf5b8d83dde..72863850bd3 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/invalidation.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/invalidation.kt @@ -52,7 +52,7 @@ private fun invalidateCacheForModule( cacheConsumer: PersistentCacheConsumer, signatureResolver: (String, Int) -> IdSignature, fileFingerPrints: MutableMap -): Set { +): Pair, Collection> { val dirtyFiles = mutableSetOf() @@ -110,7 +110,14 @@ private fun invalidateCacheForModule( cacheConsumer.invalidateForFile(dirty) } - return dirtyFiles + val cachedFiles = cacheProvider.filePaths() + val deletedFiles = cachedFiles - libraryFiles.toSet() + + for (deleted in deletedFiles) { + cacheConsumer.invalidateForFile(deleted) + } + + return dirtyFiles to deletedFiles } private fun KotlinLibrary.filesAndSigReaders(): List> { @@ -149,6 +156,7 @@ private fun buildCacheForModule( deserializer: JsIrLinker, dependencies: Collection, dirtyFiles: Collection, + deletedFiles: Collection, cleanInlineHashes: Map, cacheConsumer: PersistentCacheConsumer, signatureDeserializers: Map>, @@ -194,7 +202,7 @@ private fun buildCacheForModule( // TODO: actual way of building a cache could change in future - cacheExecutor.execute(irModule, dependencies, deserializer, configuration, dirtyFiles, cacheConsumer, emptySet(), null) // TODO: main arguments? + cacheExecutor.execute(irModule, dependencies, deserializer, configuration, dirtyFiles, deletedFiles, cacheConsumer, emptySet(), null) // TODO: main arguments? cacheConsumer.commitLibraryPath(libraryInfo.libPath.toCanonicalPath(), libraryInfo.flatHash, libraryInfo.transHash) } @@ -299,6 +307,7 @@ fun interface CacheExecutor { deserializer: JsIrLinker, configuration: CompilerConfiguration, dirtyFiles: Collection?, // if null consider the whole module dirty + deletedFiles: Collection, cacheConsumer: PersistentCacheConsumer, exportedDeclarations: Set, mainArguments: List?, @@ -441,7 +450,9 @@ private fun actualizeCacheForModule( persistentCacheProviders[lib]?.let { provider -> val moduleReaders = depReaders[lib]!! val inlineHashes = provider.allInlineHashes { f, i -> - moduleReaders[f]!!.deserializeIdSignature(i) + val moduleReader = moduleReaders[f] + ?: error("No module reader for file $f") + moduleReader.deserializeIdSignature(i) } sigHashes.putAll(inlineHashes) } @@ -458,7 +469,7 @@ private fun actualizeCacheForModule( currentLibraryCacheProvider.inlineHashes(filePath) { s -> sigReader.deserializeIdSignature(s) } } - val dirtySet = invalidateCacheForModule( + val (dirtySet, deletedFiles) = invalidateCacheForModule( library, libraryFiles, sigHashes, @@ -513,6 +524,7 @@ private fun actualizeCacheForModule( jsIrLinker, irModules.map { it.first }, dirtySet, + deletedFiles, sigHashes, persistentCacheConsumer, deserializers, @@ -565,6 +577,7 @@ fun rebuildCacheForDirtyFiles( jsIrLinker, configuration, dirtyFiles, + emptyList(), cacheConsumer, exportedDeclarations, mainArguments @@ -578,6 +591,7 @@ fun buildCacheForModuleFiles( deserializer: JsIrLinker, configuration: CompilerConfiguration, dirtyFiles: Collection?, // if null consider the whole module dirty + deletedFiles: Collection, cacheConsumer: PersistentCacheConsumer, exportedDeclarations: Set, mainArguments: List?, diff --git a/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/ic/CacheAccessors.kt b/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/ic/CacheAccessors.kt index 63959bb567d..72cd383ffb8 100644 --- a/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/ic/CacheAccessors.kt +++ b/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/ic/CacheAccessors.kt @@ -184,7 +184,8 @@ class PersistentCacheProviderImpl(private val cachePath: String) : PersistentCac } override fun filePaths(): Iterable { - return File(cachePath).listFiles()!!.filter { it.isDirectory }.mapNotNull { f -> + val files = File(cachePath).listFiles() ?: return emptyList() + return files.filter { it.isDirectory }.mapNotNull { f -> val fileInfo = File(f, fileInfoFile) if (fileInfo.exists()) { fileInfo.readLines()[0] diff --git a/js/js.tests/test/org/jetbrains/kotlin/incremental/AbstractInvalidationTest.kt b/js/js.tests/test/org/jetbrains/kotlin/incremental/AbstractInvalidationTest.kt index 7c5d8c9ff7c..bec06bbd0d8 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/incremental/AbstractInvalidationTest.kt +++ b/js/js.tests/test/org/jetbrains/kotlin/incremental/AbstractInvalidationTest.kt @@ -53,6 +53,7 @@ abstract class AbstractInvalidationTest : KotlinTestWithEnvironment() { deserializer: JsIrLinker, configuration: CompilerConfiguration, dirtyFiles: Collection?, // if null consider the whole module dirty + deletedFiles: Collection, cacheConsumer: PersistentCacheConsumer, exportedDeclarations: Set, mainArguments: List?, @@ -147,7 +148,7 @@ abstract class AbstractInvalidationTest : KotlinTestWithEnvironment() { val moduleCacheDir = resolveModuleCache(module, buildDir) - buildCachesAndCheck(moduleStep, configuration, moduleSourceDir, outputKlibFile, moduleCacheDir, dependencies, icCaches, dirtyFiles) + buildCachesAndCheck(moduleStep, configuration, moduleSourceDir, outputKlibFile, moduleCacheDir, dependencies, icCaches, dirtyFiles, deletedFiles) } } } @@ -165,7 +166,8 @@ abstract class AbstractInvalidationTest : KotlinTestWithEnvironment() { moduleCacheDir: File, dependencies: List, icCaches: List, - expectedDirtyFiles: List + expectedDirtyFiles: List, + expectedDeletedFiles: List ) { @Suppress("UNUSED_PARAMETER") fun dirtyFilesChecker( @@ -174,6 +176,7 @@ abstract class AbstractInvalidationTest : KotlinTestWithEnvironment() { deserializer: JsIrLinker, configuration: CompilerConfiguration, invalidatedDirtyFiles: Collection?, // if null consider the whole module dirty + deletedFiles: Collection, cacheConsumer: PersistentCacheConsumer, exportedDeclarations: Set, mainArguments: List?, @@ -183,7 +186,15 @@ abstract class AbstractInvalidationTest : KotlinTestWithEnvironment() { val expectedDirtyFilesCanonical = expectedDirtyFiles.map { it.canonicalPath } JUnit4Assertions.assertSameElements(expectedDirtyFilesCanonical, actualDirtyFiles) { - "For module $moduleKlibFile at step ${moduleStep.id}" + "Mismatched DIRTY files for module $moduleKlibFile at step ${moduleStep.id}" + } + + val actualDeletedFiles = + deletedFiles.map { File(it).canonicalPath } + val expectedDeletedFilesCanonical = expectedDeletedFiles.map { it.canonicalPath } + + JUnit4Assertions.assertSameElements(expectedDeletedFilesCanonical, actualDeletedFiles) { + "Mismatched DELETED files for module $moduleKlibFile at step ${moduleStep.id}" } }