diff --git a/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/K2JsIrCompiler.kt b/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/K2JsIrCompiler.kt index f2b79ae2026..fdba2ce4501 100644 --- a/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/K2JsIrCompiler.kt +++ b/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/K2JsIrCompiler.kt @@ -665,18 +665,24 @@ class K2JsIrCompiler : CLICompiler() { var libIndex = 0 for ((libFile, srcFiles) in cacheUpdater.getDirtyFileLastStats()) { + val singleState = srcFiles.values.firstOrNull()?.singleOrNull()?.let { singleState -> + singleState.takeIf { srcFiles.values.all { it.singleOrNull() == singleState } } + } + val (msg, showFiles) = when { - srcFiles.values.all { it.contains(DirtyFileState.ADDED_FILE) } -> "fully rebuilt" to false - else -> "partially rebuilt" to true + singleState == DirtyFileState.NON_MODIFIED_IR -> continue + singleState == DirtyFileState.REMOVED_FILE -> "removed" to emptyMap() + singleState == DirtyFileState.ADDED_FILE -> "built clean" to emptyMap() + srcFiles.values.any { it.singleOrNull() == DirtyFileState.NON_MODIFIED_IR } -> "partially rebuilt" to srcFiles + else -> "fully rebuilt" to srcFiles } messageCollector.report(INFO, "${++libIndex}) module [${File(libFile.path).name}] was $msg") - if (showFiles) { - var fileIndex = 0 - for ((srcFile, stat) in srcFiles) { - val statStr = stat.joinToString { it.str } - // Use index, because MessageCollector ignores already reported messages - messageCollector.report(INFO, " $libIndex.${++fileIndex}) file [${File(srcFile.path).name}]: ($statStr)") - } + var fileIndex = 0 + for ((srcFile, stat) in showFiles) { + val filteredStats = stat.filter { it != DirtyFileState.NON_MODIFIED_IR } + val statStr = filteredStats.takeIf { it.isNotEmpty() }?.joinToString { it.str } ?: continue + // Use index, because MessageCollector ignores already reported messages + messageCollector.report(INFO, " $libIndex.${++fileIndex}) file [${File(srcFile.path).name}]: ($statStr)") } } diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/CacheUpdater.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/CacheUpdater.kt index 06ed9418d36..fc94441fc1f 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/CacheUpdater.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/CacheUpdater.kt @@ -18,6 +18,7 @@ import org.jetbrains.kotlin.library.KotlinLibrary import org.jetbrains.kotlin.library.resolver.TopologicalLibraryOrder import org.jetbrains.kotlin.name.FqName import java.io.File +import java.nio.file.Files import java.util.EnumSet fun interface JsIrCompilerICInterface { @@ -38,6 +39,7 @@ fun interface JsIrCompilerICInterfaceFactory { enum class DirtyFileState(val str: String) { ADDED_FILE("added file"), MODIFIED_IR("modified ir"), + NON_MODIFIED_IR("non modified ir"), UPDATED_EXPORTS("updated exports"), UPDATED_IMPORTS("updated imports"), REMOVED_INVERSE_DEPENDS("removed inverse depends"), @@ -106,14 +108,25 @@ class CacheUpdater( private val incrementalCaches = libraryDependencies.keys.associate { lib -> val libFile = KotlinLibraryFile(lib) val file = File(libFile.path) - libFile to IncrementalCache(lib, File(cacheRootDir, "${file.name}.${file.absolutePath.stringHashForIC()}")) + val libraryCacheDir = File(cacheRootDir, "${file.name}.${file.absolutePath.stringHashForIC()}") + libFile to IncrementalCache(KotlinLoadedLibraryHeader(lib), libraryCacheDir) + } + + private val removedIncrementalCaches = buildList { + if (cacheRootDir.isDirectory) { + val availableCaches = incrementalCaches.values.mapTo(HashSet(incrementalCaches.size)) { it.cacheDir } + val allDirs = Files.walk(cacheRootDir.toPath(), 1).map { it.toFile() } + allDirs.filter { it != cacheRootDir && it !in availableCaches }.forEach { removedCacheDir -> + add(IncrementalCache(KotlinRemovedLibraryHeader(removedCacheDir), removedCacheDir)) + } + } } private fun getLibIncrementalCache(libFile: KotlinLibraryFile) = incrementalCaches[libFile] ?: notFoundIcError("incremental cache", libFile) private fun addFilesWithRemovedDependencies( - modifiedFiles: KotlinSourceFileMap, + modifiedFiles: KotlinSourceFileMutableMap, removedFiles: KotlinSourceFileMap ): KotlinSourceFileMap { val extraModifiedLibFiles = KotlinSourceFileMutableMap() @@ -145,36 +158,42 @@ class CacheUpdater( addDependenciesToExtraModifiedFiles(removedFileMetadata.inverseDependencies, DirtyFileState.REMOVED_DIRECT_DEPENDS) } - if (extraModifiedLibFiles.isNotEmpty()) { - extraModifiedLibFiles.copyFilesFrom(modifiedFiles) - return extraModifiedLibFiles - } + modifiedFiles.copyFilesFrom(extraModifiedLibFiles) return modifiedFiles } fun loadModifiedFiles(): KotlinSourceFileMap { val removedFilesMetadata = hashMapOf>() - val modifiedFiles = KotlinSourceFileMap(incrementalCaches.entries.associate { (lib, cache) -> - val (dirtyFiles, removedFiles, newFiles) = cache.collectModifiedFiles() + fun collectDirtyFiles(lib: KotlinLibraryFile, cache: IncrementalCache): MutableMap { + val (addedFiles, removedFiles, modifiedFiles, nonModifiedFiles) = cache.collectModifiedFiles() val fileStats by lazy(LazyThreadSafetyMode.NONE) { dirtyFileStats.getOrPutFiles(lib) } - newFiles.forEach { fileStats.addDirtFileStat(it, DirtyFileState.ADDED_FILE) } + addedFiles.forEach { fileStats.addDirtFileStat(it, DirtyFileState.ADDED_FILE) } removedFiles.forEach { fileStats.addDirtFileStat(it.key, DirtyFileState.REMOVED_FILE) } - dirtyFiles.forEach { - if (it.key !in newFiles) { - fileStats.addDirtFileStat(it.key, DirtyFileState.MODIFIED_IR) - } - } + modifiedFiles.forEach { fileStats.addDirtFileStat(it.key, DirtyFileState.MODIFIED_IR) } + nonModifiedFiles.forEach { fileStats.addDirtFileStat(it, DirtyFileState.NON_MODIFIED_IR) } if (removedFiles.isNotEmpty()) { removedFilesMetadata[lib] = removedFiles } - lib to dirtyFiles - }) + return addedFiles.associateWithTo(modifiedFiles.toMutableMap()) { KotlinSourceFileMetadataNotExist } + } - return addFilesWithRemovedDependencies(modifiedFiles, KotlinSourceFileMap(removedFilesMetadata)) + for (cache in removedIncrementalCaches) { + val libFile = cache.libraryFileFromHeader ?: notFoundIcError("removed library name; cache dir: ${cache.cacheDir}") + val dirtyFiles = collectDirtyFiles(libFile, cache) + if (dirtyFiles.isNotEmpty()) { + icError("unexpected dirty file", libFile, dirtyFiles.keys.first()) + } + } + + val dirtyFiles = incrementalCaches.entries.associateTo(hashMapOf()) { (lib, cache) -> + lib to collectDirtyFiles(lib, cache) + } + + return addFilesWithRemovedDependencies(KotlinSourceFileMutableMap(dirtyFiles), KotlinSourceFileMap(removedFilesMetadata)) } fun collectExportedSymbolsForDirtyFiles( @@ -493,10 +512,15 @@ class CacheUpdater( } } - fun buildCacheArtifacts( + fun buildAndCommitCacheArtifacts( jsIrLinker: JsIrLinker, loadedFragments: Map ): Map { + removedIncrementalCaches.forEach { + if (!it.cacheDir.deleteRecursively()) { + icError("can not delete cache directory ${it.cacheDir.absolutePath}") + } + } return libraryDependencies.keys.associate { library -> val libFile = KotlinLibraryFile(library) val incrementalCache = getLibIncrementalCache(libFile) @@ -616,7 +640,7 @@ class CacheUpdater( updater.updateStdlibIntrinsicDependencies(loadedIr.linker, mainModuleFragment, loadedIr.loadedFragments, dirtyFiles) stopwatch.startNext("Incremental cache - building artifacts") - val incrementalCachesArtifacts = updater.buildCacheArtifacts(loadedIr.linker, loadedIr.loadedFragments) + val incrementalCachesArtifacts = updater.buildAndCommitCacheArtifacts(loadedIr.linker, loadedIr.loadedFragments) stopwatch.stop() return IrForDirtyFilesAndCompiler(incrementalCachesArtifacts, loadedIr.loadedFragments, dirtyFiles, compilerForIC) @@ -676,7 +700,7 @@ fun rebuildCacheForDirtyFiles( } val libFile = KotlinLibraryFile(library) - val dirtySrcFiles = dirtyFiles?.map { KotlinSourceFile(it) } ?: KotlinLibraryHeader(library).sourceFiles + val dirtySrcFiles = dirtyFiles?.map { KotlinSourceFile(it) } ?: KotlinLoadedLibraryHeader(library).sourceFileFingerprints.keys val modifiedFiles = mapOf(libFile to dirtySrcFiles.associateWith { emptyMetadata }) val jsIrLoader = JsIrLinkerLoader(configuration, dependencyGraph, irFactory) diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/ICUtils.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/ICUtils.kt index 494b3a83ceb..cd8384b82d6 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/ICUtils.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/ICUtils.kt @@ -48,10 +48,6 @@ internal fun notFoundIcError(what: String, libFile: KotlinLibraryFile? = null, s icError("can not find $what", libFile, srcFile) } -internal inline fun buildListUntil(to: Int, builderAction: MutableList.(Int) -> Unit): List { - return buildList(to) { repeat(to) { builderAction(it) } } -} - internal inline fun buildSetUntil(to: Int, builderAction: MutableSet.(Int) -> Unit): Set { return HashSet(to).apply { repeat(to) { builderAction(it) } } } diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/IncrementalCache.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/IncrementalCache.kt index 9a6f33b3ebd..d034e268dad 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/IncrementalCache.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/IncrementalCache.kt @@ -6,17 +6,13 @@ package org.jetbrains.kotlin.ir.backend.js.ic import org.jetbrains.kotlin.backend.common.serialization.IdSignatureDeserializer -import org.jetbrains.kotlin.ir.backend.js.jsOutputName import org.jetbrains.kotlin.ir.util.IdSignature -import org.jetbrains.kotlin.library.KotlinLibrary -import org.jetbrains.kotlin.library.impl.javaFile import org.jetbrains.kotlin.protobuf.CodedInputStream import org.jetbrains.kotlin.protobuf.CodedOutputStream import org.jetbrains.kotlin.utils.addToStdlib.ifTrue import java.io.File - -internal class IncrementalCache(private val library: KotlinLibrary, val cacheDir: File) { +internal class IncrementalCache(private val library: KotlinLibraryHeader, val cacheDir: File) { companion object { private const val CACHE_HEADER = "ic.header.bin" @@ -25,76 +21,71 @@ internal class IncrementalCache(private val library: KotlinLibrary, val cacheDir private const val METADATA_TMP_SUFFIX = "metadata.tmp.bin" } - private val signatureToIndexMappingFromMetadata = hashMapOf>() - - private val libraryFile = KotlinLibraryFile(library) - private val cacheHeaderFile = File(cacheDir, CACHE_HEADER) - private var newCacheHeader: CacheHeader? = null + private var cacheHeaderShouldBeUpdated = false private var removedSrcFiles: Collection = emptyList() - private val kotlinLibraryHeader: KotlinLibraryHeader by lazy { KotlinLibraryHeader(library) } + private val kotlinLibrarySourceFileMetadata = hashMapOf() + + private val signatureToIndexMappingFromMetadata = hashMapOf>() + + private val cacheHeaderFromDisk by lazy { + cacheHeaderFile.useCodedInputIfExists { + CacheHeader.fromProtoStream(this, library.libraryFingerprint) + } + } + + val libraryFileFromHeader by lazy { cacheHeaderFromDisk?.libraryFile } + + private class CacheHeader( + val libraryFile: KotlinLibraryFile, + private val libraryFingerprint: ICHash?, + val sourceFileFingerprints: Map? + ) { + constructor(library: KotlinLibraryHeader) : this(library.libraryFile, library.libraryFingerprint, library.sourceFileFingerprints) - private class CacheHeader(val klibFileHash: ICHash, val klibFile: KotlinLibraryFile, val fingerprints: Map?) { fun toProtoStream(out: CodedOutputStream) { - klibFile.toProtoStream(out) - klibFileHash.toProtoStream(out) + libraryFile.toProtoStream(out) - if (fingerprints == null) { - notFoundIcError("fingerprints", klibFile) - } - out.writeInt32NoTag(fingerprints.size) - for ((srcFile, fingerprint) in fingerprints) { - srcFile.toProtoStream(out) - fingerprint.toProtoStream(out) - } + libraryFingerprint?.toProtoStream(out) ?: notFoundIcError("library fingerprint", libraryFile) + + sourceFileFingerprints?.let { fingerprints -> + out.writeInt32NoTag(fingerprints.size) + for ((srcFile, fingerprint) in fingerprints) { + srcFile.toProtoStream(out) + fingerprint.toProtoStream(out) + } + } ?: notFoundIcError("source file fingerprints", libraryFile) } companion object { - fun fromProtoStream(input: CodedInputStream, newKlibFileHash: ICHash): CacheHeader { - val klibFile = KotlinLibraryFile.fromProtoStream(input) - val oldKlibFileHash = ICHash.fromProtoStream(input) + fun fromProtoStream(input: CodedInputStream, newLibraryFingerprint: ICHash?): CacheHeader { + val libraryFile = KotlinLibraryFile.fromProtoStream(input) + val oldLibraryFingerprint = ICHash.fromProtoStream(input) - val fingerprints = (oldKlibFileHash != newKlibFileHash).ifTrue { + val sourceFileFingerprints = (oldLibraryFingerprint != newLibraryFingerprint).ifTrue { buildMapUntil(input.readInt32()) { val file = KotlinSourceFile.fromProtoStream(input) put(file, ICHash.fromProtoStream(input)) } } - return CacheHeader(oldKlibFileHash, klibFile, fingerprints) + return CacheHeader(libraryFile, oldLibraryFingerprint, sourceFileFingerprints) } } } - private fun loadCacheHeader(newKlibFileHash: ICHash): CacheHeader? { - return cacheHeaderFile.useCodedInputIfExists { - val cacheHeader = CacheHeader.fromProtoStream(this, newKlibFileHash) - if (cacheHeader.klibFile != libraryFile) { - icError("broken incremental cache header $cacheHeaderFile; expected $libraryFile, got ${cacheHeader.klibFile}") - } - cacheHeader - } - } - private class KotlinSourceFileMetadataFromDisk( override val inverseDependencies: KotlinSourceFileMap>, override val directDependencies: KotlinSourceFileMap>, ) : KotlinSourceFileMetadata() - private object KotlinSourceFileMetadataNotExist : KotlinSourceFileMetadata() { - override val inverseDependencies = KotlinSourceFileMap>(emptyMap()) - override val directDependencies = KotlinSourceFileMap>(emptyMap()) - } - - private val kotlinLibrarySourceFileMetadata = hashMapOf() - private fun KotlinSourceFile.getCacheFile(suffix: String) = File(cacheDir, "${File(path).name}.${path.stringHashForIC()}.$suffix") fun buildIncrementalCacheArtifact(signatureToIndexMapping: Map>): IncrementalCacheArtifact { - newCacheHeader?.let { cacheHeader -> - cacheHeaderFile.useCodedOutput { cacheHeader.toProtoStream(this) } + if (cacheHeaderShouldBeUpdated) { + cacheHeaderFile.useCodedOutput { CacheHeader(library).toProtoStream(this) } } for (removedFile in removedSrcFiles) { @@ -102,51 +93,42 @@ internal class IncrementalCache(private val library: KotlinLibrary, val cacheDir removedFile.getCacheFile(METADATA_SUFFIX).delete() } - val fileArtifacts = kotlinLibraryHeader.sourceFiles.map { srcFile -> + val fileArtifacts = library.sourceFileFingerprints.keys.map { srcFile -> commitSourceFileMetadata(srcFile.getCacheFile(BINARY_AST_SUFFIX), srcFile, signatureToIndexMapping[srcFile] ?: emptyMap()) } return IncrementalCacheArtifact(cacheDir, removedSrcFiles.isNotEmpty(), fileArtifacts, library.jsOutputName) } data class ModifiedFiles( - val dirtyFiles: Map = emptyMap(), + val addedFiles: List = emptyList(), val removedFiles: Map = emptyMap(), - val newFiles: Set = emptySet(), + val modifiedFiles: Map = emptyMap(), + val nonModifiedFiles: List = emptyList() ) fun collectModifiedFiles(): ModifiedFiles { - val klibFileHash = library.libraryFile.javaFile().fileHashForIC() + val cachedFingerprints = cacheHeaderFromDisk?.let { it.sourceFileFingerprints ?: return ModifiedFiles() } ?: emptyMap() - val cacheHeader = loadCacheHeader(klibFileHash) + val addedFiles = mutableListOf() + val modifiedFiles = hashMapOf() + val nonModifiedFiles = mutableListOf() - val cachedFingerprints = cacheHeader?.let { it.fingerprints ?: return ModifiedFiles() } ?: emptyMap() - - val deletedFiles = HashSet(cachedFingerprints.keys) - val newFiles = mutableSetOf() - - val newFingerprints = HashMap(kotlinLibraryHeader.sourceFiles.size) - kotlinLibraryHeader.sourceFiles.forEachIndexed { index, file -> newFingerprints[file] = library.fingerprint(index) } - - val modifiedFiles = HashMap(newFingerprints.size).apply { - for ((file, fileNewFingerprint) in newFingerprints) { - val oldFingerprint = cachedFingerprints[file] - if (oldFingerprint == null) { - newFiles += file - } - if (oldFingerprint != fileNewFingerprint) { - val metadata = fetchSourceFileMetadata(file, false) - put(file, metadata) - } - deletedFiles.remove(file) + for ((file, fileNewFingerprint) in library.sourceFileFingerprints) { + when (cachedFingerprints[file]) { + fileNewFingerprint -> nonModifiedFiles.add(file) + null -> addedFiles.add(file) + else -> modifiedFiles[file] = fetchSourceFileMetadata(file, false) } } - val removedFiles = deletedFiles.associateWith { fetchSourceFileMetadata(it, false) } + val removedFiles = (cachedFingerprints.keys - library.sourceFileFingerprints.keys).associateWith { + fetchSourceFileMetadata(it, false) + } - removedSrcFiles = deletedFiles - newCacheHeader = CacheHeader(klibFileHash, libraryFile, newFingerprints) + removedSrcFiles = removedFiles.keys + cacheHeaderShouldBeUpdated = true - return ModifiedFiles(modifiedFiles, removedFiles, newFiles) + return ModifiedFiles(addedFiles, removedFiles, modifiedFiles, nonModifiedFiles) } fun fetchSourceFileFullMetadata(srcFile: KotlinSourceFile): KotlinSourceFileMetadata { @@ -161,7 +143,7 @@ internal class IncrementalCache(private val library: KotlinLibrary, val cacheDir kotlinLibrarySourceFileMetadata.getOrPut(srcFile) { val signatureToIndexMapping = signatureToIndexMappingFromMetadata.getOrPut(srcFile) { hashMapOf() } val deserializer: IdSignatureDeserializer by lazy { - kotlinLibraryHeader.signatureDeserializers[srcFile] ?: notFoundIcError("signature deserializer", libraryFile, srcFile) + library.sourceFileDeserializers[srcFile] ?: notFoundIcError("signature deserializer", library.libraryFile, srcFile) } fun CodedInputStream.deserializeIdSignatureAndSave() = readIdSignature { index -> diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/KotlinLibraryHeader.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/KotlinLibraryHeader.kt index 9f1064e90c2..0408a75e25e 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/KotlinLibraryHeader.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/KotlinLibraryHeader.kt @@ -10,23 +10,45 @@ import org.jetbrains.kotlin.backend.common.serialization.IrLibraryBytesSource import org.jetbrains.kotlin.backend.common.serialization.IrLibraryFileFromBytes import org.jetbrains.kotlin.backend.common.serialization.codedInputStream import org.jetbrains.kotlin.backend.common.serialization.proto.IrFile +import org.jetbrains.kotlin.ir.backend.js.jsOutputName import org.jetbrains.kotlin.library.KotlinLibrary import org.jetbrains.kotlin.protobuf.ExtensionRegistryLite +import java.io.File -internal class KotlinLibraryHeader(library: KotlinLibrary) { - val sourceFiles: List - val signatureDeserializers: Map +internal interface KotlinLibraryHeader { + val libraryFile: KotlinLibraryFile - init { + val libraryFingerprint: ICHash? + + val sourceFileDeserializers: Map + val sourceFileFingerprints: Map + + val jsOutputName: String? +} + +internal class KotlinLoadedLibraryHeader(private val library: KotlinLibrary) : KotlinLibraryHeader { + override val libraryFile: KotlinLibraryFile = KotlinLibraryFile(library) + + override val libraryFingerprint: ICHash by lazy { File(libraryFile.path).fileHashForIC() } + + override val sourceFileDeserializers: Map by lazy { sourceFiles.first } + override val sourceFileFingerprints: Map by lazy { sourceFiles.second } + + override val jsOutputName: String? + get() = library.jsOutputName + + private val sourceFiles by lazy { val filesCount = library.fileCount() val extReg = ExtensionRegistryLite.newInstance() - val files = buildListUntil(filesCount) { - val fileProto = IrFile.parseFrom(library.file(it).codedInputStream, extReg) - add(KotlinSourceFile(fileProto.fileEntry.name)) - } - val deserializers = buildMapUntil(filesCount) { - put(files[it], IdSignatureDeserializer(IrLibraryFileFromBytes(object : IrLibraryBytesSource() { + val deserializers = HashMap(filesCount) + val fingerprints = HashMap(filesCount) + + repeat(filesCount) { + val fileProto = IrFile.parseFrom(library.file(it).codedInputStream, extReg) + val srcFile = KotlinSourceFile(fileProto.fileEntry.name) + + deserializers[srcFile] = IdSignatureDeserializer(IrLibraryFileFromBytes(object : IrLibraryBytesSource() { private fun err(): Nothing = icError("Not supported") override fun irDeclaration(index: Int): ByteArray = err() override fun type(index: Int): ByteArray = err() @@ -34,10 +56,22 @@ internal class KotlinLibraryHeader(library: KotlinLibrary) { override fun string(index: Int): ByteArray = library.string(index, it) override fun body(index: Int): ByteArray = err() override fun debugInfo(index: Int): ByteArray? = null - }), null)) - } + }), null) - sourceFiles = files - signatureDeserializers = deserializers + fingerprints[srcFile] = library.fingerprint(it) + } + deserializers to fingerprints } } + +internal class KotlinRemovedLibraryHeader(private val libCacheDir: File) : KotlinLibraryHeader { + override val libraryFile: KotlinLibraryFile + get() = icError("removed library name is unavailable; cache dir: ${libCacheDir.absolutePath}") + + override val libraryFingerprint: ICHash? get() = null + + override val sourceFileDeserializers: Map get() = emptyMap() + override val sourceFileFingerprints: Map get() = emptyMap() + + override val jsOutputName: String? get() = null +} diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/KotlinSourceFileMetadata.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/KotlinSourceFileMetadata.kt index e310a9d53a8..430d7e8f33c 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/KotlinSourceFileMetadata.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/KotlinSourceFileMetadata.kt @@ -98,9 +98,14 @@ abstract class KotlinSourceFileExports { abstract class KotlinSourceFileMetadata : KotlinSourceFileExports() { abstract val directDependencies: KotlinSourceFileMap> + + fun isEmpty() = inverseDependencies.isEmpty() && directDependencies.isEmpty() } -fun KotlinSourceFileMetadata.isEmpty() = inverseDependencies.isEmpty() && directDependencies.isEmpty() +internal object KotlinSourceFileMetadataNotExist : KotlinSourceFileMetadata() { + override val inverseDependencies = KotlinSourceFileMap>(emptyMap()) + override val directDependencies = KotlinSourceFileMap>(emptyMap()) +} internal class DirtyFileExports( override val inverseDependencies: KotlinSourceFileMutableMap> = KotlinSourceFileMutableMap() 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 bab14adc614..99555b5d00e 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/incremental/AbstractInvalidationTest.kt +++ b/js/js.tests/test/org/jetbrains/kotlin/incremental/AbstractInvalidationTest.kt @@ -42,12 +42,12 @@ import java.util.EnumSet abstract class AbstractInvalidationTest : KotlinTestWithEnvironment() { companion object { - private val TEST_DATA_DIR_PATH = System.getProperty("kotlin.js.test.root.out.dir") ?: error("'kotlin.js.test.root.out.dir' is not set") - private const val BOX_FUNCTION_NAME = "box" - - private const val STDLIB_MODULE_NAME = "kotlin-kotlin-stdlib-js-ir" + private val OUT_DIR_PATH = System.getProperty("kotlin.js.test.root.out.dir") ?: error("'kotlin.js.test.root.out.dir' is not set") private val STDLIB_KLIB = File(System.getProperty("kotlin.js.stdlib.klib.path") ?: error("Please set stdlib path")).canonicalPath + private const val BOX_FUNCTION_NAME = "box" + private const val STDLIB_MODULE_NAME = "kotlin-kotlin-stdlib-js-ir" + private val KT_FILE_IGNORE_PATTERN = Regex("^.*\\..+\\.kt$") } @@ -125,7 +125,7 @@ abstract class AbstractInvalidationTest : KotlinTestWithEnvironment() { val expectedFileStats: Map> ) - private fun setupTestStep(projStep: ProjectInfo.ProjectBuildStep, module: String): TestStepInfo { + private fun setupTestStep(projStep: ProjectInfo.ProjectBuildStep, module: String, buildKlib: Boolean): TestStepInfo { val projStepId = projStep.id val moduleTestDir = File(testDir, module) val moduleSourceDir = File(sourceDir, module) @@ -136,17 +136,20 @@ abstract class AbstractInvalidationTest : KotlinTestWithEnvironment() { modification.execute(moduleTestDir, moduleSourceDir) { deletedFiles.add(it.name) } } - val dependencies = moduleStep.dependencies.mapTo(mutableListOf(File(STDLIB_KLIB))) { - resolveModuleArtifact(it.moduleName, buildDir) + val expectedFileStats = moduleStep.expectedFileStats.toMutableMap() + if (deletedFiles.isNotEmpty()) { + val removedFiles = expectedFileStats[DirtyFileState.REMOVED_FILE.str] ?: emptySet() + expectedFileStats[DirtyFileState.REMOVED_FILE.str] = removedFiles + deletedFiles } - val outputKlibFile = resolveModuleArtifact(module, buildDir) - val configuration = createConfiguration(module, projStep.language) - buildArtifact(configuration, module, moduleSourceDir, dependencies, outputKlibFile) - val expectedFileStats = if (deletedFiles.isEmpty()) { - moduleStep.expectedFileStats - } else { - moduleStep.expectedFileStats + (DirtyFileState.REMOVED_FILE.str to deletedFiles) + val outputKlibFile = resolveModuleArtifact(module, buildDir) + + if (buildKlib) { + val dependencies = moduleStep.dependencies.mapTo(mutableListOf(File(STDLIB_KLIB))) { + resolveModuleArtifact(it.moduleName, buildDir) + } + val configuration = createConfiguration(module, projStep.language) + buildArtifact(configuration, module, moduleSourceDir, dependencies, outputKlibFile) } return TestStepInfo( module.safeModuleName, @@ -155,9 +158,7 @@ abstract class AbstractInvalidationTest : KotlinTestWithEnvironment() { ) } - private fun verifyCacheUpdateStats( - stepId: Int, stats: KotlinSourceFileMap>, testInfo: List - ) { + private fun verifyCacheUpdateStats(stepId: Int, stats: KotlinSourceFileMap>, testInfo: List) { val gotStats = stats.filter { it.key.path != STDLIB_KLIB } val checkedLibs = mutableSetOf() @@ -170,7 +171,9 @@ abstract class AbstractInvalidationTest : KotlinTestWithEnvironment() { val got = mutableMapOf>() for ((srcFile, dirtyStats) in updateStatus) { for (dirtyStat in dirtyStats) { - got.getOrPut(dirtyStat.str) { mutableSetOf() }.add(File(srcFile.path).name) + if (dirtyStat != DirtyFileState.NON_MODIFIED_IR) { + got.getOrPut(dirtyStat.str) { mutableSetOf() }.add(File(srcFile.path).name) + } } } @@ -223,7 +226,7 @@ abstract class AbstractInvalidationTest : KotlinTestWithEnvironment() { fun execute() { for (projStep in projectInfo.steps) { - val testInfo = projStep.order.map { setupTestStep(projStep, it) } + val testInfo = projStep.order.map { setupTestStep(projStep, it, true) } val configuration = createConfiguration(projStep.order.last(), projStep.language) val cacheUpdater = CacheUpdater( @@ -238,8 +241,10 @@ abstract class AbstractInvalidationTest : KotlinTestWithEnvironment() { } ) + val removedModulesInfo = (projectInfo.modules - projStep.order.toSet()).map { setupTestStep(projStep, it, false) } + val icCaches = cacheUpdater.actualizeCaches() - verifyCacheUpdateStats(projStep.id, cacheUpdater.getDirtyFileLastStats(), testInfo) + verifyCacheUpdateStats(projStep.id, cacheUpdater.getDirtyFileLastStats(), testInfo + removedModulesInfo) val mainModuleName = icCaches.last().moduleExternalName val jsExecutableProducer = JsExecutableProducer( @@ -342,7 +347,7 @@ abstract class AbstractInvalidationTest : KotlinTestWithEnvironment() { } private fun testWorkingDir(testName: String): File { - val dir = File(File(File(TEST_DATA_DIR_PATH), "incrementalOut/invalidation"), testName) + val dir = File(File(File(OUT_DIR_PATH), "incrementalOut/invalidation"), testName) dir.invalidateDir() diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/InvalidationTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/InvalidationTestGenerated.java index 8616fb6dff4..ea8d07d9860 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/InvalidationTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/incremental/InvalidationTestGenerated.java @@ -275,11 +275,21 @@ public class InvalidationTestGenerated extends AbstractInvalidationTest { runTest("js/js.translator/testData/incremental/invalidation/renameFile/"); } + @TestMetadata("renameModule") + public void testRenameModule() throws Exception { + runTest("js/js.translator/testData/incremental/invalidation/renameModule/"); + } + @TestMetadata("simple") public void testSimple() throws Exception { runTest("js/js.translator/testData/incremental/invalidation/simple/"); } + @TestMetadata("splitJoinModule") + public void testSplitJoinModule() throws Exception { + runTest("js/js.translator/testData/incremental/invalidation/splitJoinModule/"); + } + @TestMetadata("suspendFunctions") public void testSuspendFunctions() throws Exception { runTest("js/js.translator/testData/incremental/invalidation/suspendFunctions/"); diff --git a/js/js.translator/testData/incremental/invalidation/addUpdateRemoveDependentModule/lib1/module.info b/js/js.translator/testData/incremental/invalidation/addUpdateRemoveDependentModule/lib1/module.info index c29e358ef9d..e4dfcb28c24 100644 --- a/js/js.translator/testData/incremental/invalidation/addUpdateRemoveDependentModule/lib1/module.info +++ b/js/js.translator/testData/incremental/invalidation/addUpdateRemoveDependentModule/lib1/module.info @@ -5,7 +5,9 @@ STEP 1: STEP 2: updated exports: l1a.kt STEP 3: + removed inverse depends: l1b.kt, l1a.kt STEP 4: modifications: U : l1a.4.kt -> l1a.kt modified ir: l1a.kt + updated exports: l1b.kt diff --git a/js/js.translator/testData/incremental/invalidation/genericInlineFunctions/libProxy/module.info b/js/js.translator/testData/incremental/invalidation/genericInlineFunctions/libProxy/module.info index 286ba0733cd..678e80eef6a 100644 --- a/js/js.translator/testData/incremental/invalidation/genericInlineFunctions/libProxy/module.info +++ b/js/js.translator/testData/incremental/invalidation/genericInlineFunctions/libProxy/module.info @@ -1,8 +1,4 @@ -STEP 0: - modifications: - U : proxy.0.kt -> proxy.kt - added file: proxy.kt -STEP 1..7: +STEP 0..7: STEP 8: dependencies: lib1 modifications: diff --git a/js/js.translator/testData/incremental/invalidation/genericInlineFunctions/libProxy/proxy.0.kt b/js/js.translator/testData/incremental/invalidation/genericInlineFunctions/libProxy/proxy.0.kt deleted file mode 100644 index 7922b705f56..00000000000 --- a/js/js.translator/testData/incremental/invalidation/genericInlineFunctions/libProxy/proxy.0.kt +++ /dev/null @@ -1 +0,0 @@ -fun unused_foo_proxy(s: String) = 77 diff --git a/js/js.translator/testData/incremental/invalidation/renameModule/lib1-new/l1.1.kt b/js/js.translator/testData/incremental/invalidation/renameModule/lib1-new/l1.1.kt new file mode 100644 index 00000000000..5ecbbdfc1e5 --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/renameModule/lib1-new/l1.1.kt @@ -0,0 +1 @@ +fun foo() = 1 diff --git a/js/js.translator/testData/incremental/invalidation/renameModule/lib1-new/l1.2.kt b/js/js.translator/testData/incremental/invalidation/renameModule/lib1-new/l1.2.kt new file mode 100644 index 00000000000..cd327dbd2a4 --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/renameModule/lib1-new/l1.2.kt @@ -0,0 +1 @@ +inline fun foo() = 2 diff --git a/js/js.translator/testData/incremental/invalidation/renameModule/lib1-new/module.info b/js/js.translator/testData/incremental/invalidation/renameModule/lib1-new/module.info new file mode 100644 index 00000000000..aa15d5b7cbf --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/renameModule/lib1-new/module.info @@ -0,0 +1,12 @@ +STEP 0: +STEP 1: + modifications: + U : l1.1.kt -> l1.kt + added file: l1.kt +STEP 2: + modifications: + U : l1.2.kt -> l1.kt + modified ir: l1.kt +STEP 3: + removed file: l1.kt +STEP 4..5: diff --git a/js/js.translator/testData/incremental/invalidation/renameModule/lib1/l1.0.kt b/js/js.translator/testData/incremental/invalidation/renameModule/lib1/l1.0.kt new file mode 100644 index 00000000000..22669f4d07c --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/renameModule/lib1/l1.0.kt @@ -0,0 +1 @@ +fun foo() = 0 diff --git a/js/js.translator/testData/incremental/invalidation/renameModule/lib1/l1.3.kt b/js/js.translator/testData/incremental/invalidation/renameModule/lib1/l1.3.kt new file mode 100644 index 00000000000..f515356d86c --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/renameModule/lib1/l1.3.kt @@ -0,0 +1 @@ +fun foo() = 3 diff --git a/js/js.translator/testData/incremental/invalidation/renameModule/lib1/l1.4.kt b/js/js.translator/testData/incremental/invalidation/renameModule/lib1/l1.4.kt new file mode 100644 index 00000000000..13769d4eab2 --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/renameModule/lib1/l1.4.kt @@ -0,0 +1 @@ +inline fun foo() = 4 diff --git a/js/js.translator/testData/incremental/invalidation/renameModule/lib1/l1.5.kt b/js/js.translator/testData/incremental/invalidation/renameModule/lib1/l1.5.kt new file mode 100644 index 00000000000..fbf4522241f --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/renameModule/lib1/l1.5.kt @@ -0,0 +1 @@ +inline fun foo() = 5 diff --git a/js/js.translator/testData/incremental/invalidation/renameModule/lib1/module.info b/js/js.translator/testData/incremental/invalidation/renameModule/lib1/module.info new file mode 100644 index 00000000000..62f0f2e4c94 --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/renameModule/lib1/module.info @@ -0,0 +1,19 @@ +STEP 0: + modifications: + U : l1.0.kt -> l1.kt + added file: l1.kt +STEP 1: + removed file: l1.kt +STEP 2: +STEP 3: + modifications: + U : l1.3.kt -> l1.kt + added file: l1.kt +STEP 4: + modifications: + U : l1.4.kt -> l1.kt + modified ir: l1.kt +STEP 5: + modifications: + U : l1.5.kt -> l1.kt + modified ir: l1.kt diff --git a/js/js.translator/testData/incremental/invalidation/renameModule/main/m.kt b/js/js.translator/testData/incremental/invalidation/renameModule/main/m.kt new file mode 100644 index 00000000000..f12da0dee69 --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/renameModule/main/m.kt @@ -0,0 +1,7 @@ +fun box(stepId: Int): String { + val x = foo() + if (x != stepId) { + return "Fail: $x != $stepId" + } + return "OK" +} diff --git a/js/js.translator/testData/incremental/invalidation/renameModule/main/module.info b/js/js.translator/testData/incremental/invalidation/renameModule/main/module.info new file mode 100644 index 00000000000..0f7fd2be5e4 --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/renameModule/main/module.info @@ -0,0 +1,15 @@ +STEP 0: + dependencies: lib1 + added file: m.kt +STEP 1: + dependencies: lib1-new + removed direct depends: m.kt +STEP 2: + dependencies: lib1-new + updated imports: m.kt +STEP 3: + dependencies: lib1 + removed direct depends: m.kt +STEP 4..5: + dependencies: lib1 + updated imports: m.kt diff --git a/js/js.translator/testData/incremental/invalidation/renameModule/project.info b/js/js.translator/testData/incremental/invalidation/renameModule/project.info new file mode 100644 index 00000000000..fbb4830b4cf --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/renameModule/project.info @@ -0,0 +1,11 @@ +MODULES: lib1, lib1-new, main + +STEP 0: + libs: lib1, main + dirty js: lib1, main +STEP 1..2: + libs: lib1-new, main + dirty js: lib1-new, main +STEP 3..5: + libs: lib1, main + dirty js: lib1, main diff --git a/js/js.translator/testData/incremental/invalidation/splitJoinModule/lib1-a/l1a.1.kt b/js/js.translator/testData/incremental/invalidation/splitJoinModule/lib1-a/l1a.1.kt new file mode 100644 index 00000000000..725ca0f3660 --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/splitJoinModule/lib1-a/l1a.1.kt @@ -0,0 +1 @@ +fun fooA() = 1 diff --git a/js/js.translator/testData/incremental/invalidation/splitJoinModule/lib1-a/module.info b/js/js.translator/testData/incremental/invalidation/splitJoinModule/lib1-a/module.info new file mode 100644 index 00000000000..17d94c8c632 --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/splitJoinModule/lib1-a/module.info @@ -0,0 +1,10 @@ +STEP 0: +STEP 1: + modifications: + U : l1a.1.kt -> l1a.kt + added file: l1a.kt +STEP 2..3: +STEP 4: + modifications: + D : l1a.kt +STEP 5: diff --git a/js/js.translator/testData/incremental/invalidation/splitJoinModule/lib1-b/l1b.1.kt b/js/js.translator/testData/incremental/invalidation/splitJoinModule/lib1-b/l1b.1.kt new file mode 100644 index 00000000000..9ed38d38e94 --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/splitJoinModule/lib1-b/l1b.1.kt @@ -0,0 +1 @@ +fun fooB() = 2 diff --git a/js/js.translator/testData/incremental/invalidation/splitJoinModule/lib1-b/l1b.2.kt b/js/js.translator/testData/incremental/invalidation/splitJoinModule/lib1-b/l1b.2.kt new file mode 100644 index 00000000000..a677ef5ff84 --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/splitJoinModule/lib1-b/l1b.2.kt @@ -0,0 +1 @@ +inline fun fooB() = 3 diff --git a/js/js.translator/testData/incremental/invalidation/splitJoinModule/lib1-b/l1b.3.kt b/js/js.translator/testData/incremental/invalidation/splitJoinModule/lib1-b/l1b.3.kt new file mode 100644 index 00000000000..ff2ed6a0480 --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/splitJoinModule/lib1-b/l1b.3.kt @@ -0,0 +1 @@ +inline fun fooB() = 4 diff --git a/js/js.translator/testData/incremental/invalidation/splitJoinModule/lib1-b/module.info b/js/js.translator/testData/incremental/invalidation/splitJoinModule/lib1-b/module.info new file mode 100644 index 00000000000..2c7091980d6 --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/splitJoinModule/lib1-b/module.info @@ -0,0 +1,17 @@ +STEP 0: +STEP 1: + modifications: + U : l1b.1.kt -> l1b.kt + added file: l1b.kt +STEP 2: + modifications: + U : l1b.2.kt -> l1b.kt + modified ir: l1b.kt +STEP 2: + modifications: + U : l1b.3.kt -> l1b.kt + modified ir: l1b.kt +STEP 4: + modifications: + D : l1b.kt +STEP 5: diff --git a/js/js.translator/testData/incremental/invalidation/splitJoinModule/lib1-c/l1c.1.kt b/js/js.translator/testData/incremental/invalidation/splitJoinModule/lib1-c/l1c.1.kt new file mode 100644 index 00000000000..c93f6eddd12 --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/splitJoinModule/lib1-c/l1c.1.kt @@ -0,0 +1 @@ +fun fooC() = 4 diff --git a/js/js.translator/testData/incremental/invalidation/splitJoinModule/lib1-c/module.info b/js/js.translator/testData/incremental/invalidation/splitJoinModule/lib1-c/module.info new file mode 100644 index 00000000000..9b184a117f1 --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/splitJoinModule/lib1-c/module.info @@ -0,0 +1,10 @@ +STEP 0: +STEP 1: + modifications: + U : l1c.1.kt -> l1c.kt + added file: l1c.kt +STEP 2..3: +STEP 4: + modifications: + D : l1c.kt +STEP 5: diff --git a/js/js.translator/testData/incremental/invalidation/splitJoinModule/lib1/l1.4.kt b/js/js.translator/testData/incremental/invalidation/splitJoinModule/lib1/l1.4.kt new file mode 100644 index 00000000000..f3b698e65d8 --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/splitJoinModule/lib1/l1.4.kt @@ -0,0 +1,5 @@ +fun fooA() = 3 + +fun fooB() = 3 + +fun fooC() = 4 diff --git a/js/js.translator/testData/incremental/invalidation/splitJoinModule/lib1/l1.5.kt b/js/js.translator/testData/incremental/invalidation/splitJoinModule/lib1/l1.5.kt new file mode 100644 index 00000000000..c79341f38af --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/splitJoinModule/lib1/l1.5.kt @@ -0,0 +1,5 @@ +fun fooA() = 3 + +fun fooB() = 4 + +fun fooC() = 4 diff --git a/js/js.translator/testData/incremental/invalidation/splitJoinModule/lib1/l1a.0.kt b/js/js.translator/testData/incremental/invalidation/splitJoinModule/lib1/l1a.0.kt new file mode 100644 index 00000000000..725ca0f3660 --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/splitJoinModule/lib1/l1a.0.kt @@ -0,0 +1 @@ +fun fooA() = 1 diff --git a/js/js.translator/testData/incremental/invalidation/splitJoinModule/lib1/l1b.0.kt b/js/js.translator/testData/incremental/invalidation/splitJoinModule/lib1/l1b.0.kt new file mode 100644 index 00000000000..9ed38d38e94 --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/splitJoinModule/lib1/l1b.0.kt @@ -0,0 +1 @@ +fun fooB() = 2 diff --git a/js/js.translator/testData/incremental/invalidation/splitJoinModule/lib1/l1c.0.kt b/js/js.translator/testData/incremental/invalidation/splitJoinModule/lib1/l1c.0.kt new file mode 100644 index 00000000000..2c27a5c7433 --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/splitJoinModule/lib1/l1c.0.kt @@ -0,0 +1 @@ +fun fooC() = 3 diff --git a/js/js.translator/testData/incremental/invalidation/splitJoinModule/lib1/module.info b/js/js.translator/testData/incremental/invalidation/splitJoinModule/lib1/module.info new file mode 100644 index 00000000000..5dcb4bb850a --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/splitJoinModule/lib1/module.info @@ -0,0 +1,20 @@ +STEP 0: + modifications: + U : l1a.0.kt -> l1a.kt + U : l1b.0.kt -> l1b.kt + U : l1c.0.kt -> l1c.kt + added file: l1a.kt, l1b.kt, l1c.kt +STEP 1: + modifications: + D : l1a.kt + D : l1b.kt + D : l1c.kt +STEP 2..3: +STEP 4: + modifications: + U : l1.4.kt -> l1.kt + added file: l1.kt +STEP 5: + modifications: + U : l1.5.kt -> l1.kt + modified ir: l1.kt diff --git a/js/js.translator/testData/incremental/invalidation/splitJoinModule/lib2/l2.0.kt b/js/js.translator/testData/incremental/invalidation/splitJoinModule/lib2/l2.0.kt new file mode 100644 index 00000000000..5563298a466 --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/splitJoinModule/lib2/l2.0.kt @@ -0,0 +1 @@ +fun qux() = fooA() + fooB() + fooC() - 6 diff --git a/js/js.translator/testData/incremental/invalidation/splitJoinModule/lib2/module.info b/js/js.translator/testData/incremental/invalidation/splitJoinModule/lib2/module.info new file mode 100644 index 00000000000..37df220edf2 --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/splitJoinModule/lib2/module.info @@ -0,0 +1,16 @@ +STEP 0: + dependencies: lib1 + modifications: + U : l2.0.kt -> l2.kt + added file: l2.kt +STEP 1: + dependencies: lib1-a, lib1-b, lib1-c + removed direct depends: l2.kt +STEP 2..3: + dependencies: lib1-a, lib1-b, lib1-c + updated imports: l2.kt +STEP 4: + dependencies: lib1 + removed direct depends: l2.kt +STEP 5: + dependencies: lib1 diff --git a/js/js.translator/testData/incremental/invalidation/splitJoinModule/main/m.kt b/js/js.translator/testData/incremental/invalidation/splitJoinModule/main/m.kt new file mode 100644 index 00000000000..f88180dc50d --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/splitJoinModule/main/m.kt @@ -0,0 +1,7 @@ +fun box(stepId: Int): String { + val x = qux() + if (x != stepId) { + return "Fail: $x != $stepId" + } + return "OK" +} diff --git a/js/js.translator/testData/incremental/invalidation/splitJoinModule/main/module.info b/js/js.translator/testData/incremental/invalidation/splitJoinModule/main/module.info new file mode 100644 index 00000000000..bfa04d76033 --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/splitJoinModule/main/module.info @@ -0,0 +1,7 @@ +STEP 0: + dependencies: lib1, lib2 + added file: m.kt +STEP 1..3: + dependencies: lib1-a, lib1-b, lib1-c, lib2 +STEP 4..5: + dependencies: lib1, lib2 diff --git a/js/js.translator/testData/incremental/invalidation/splitJoinModule/project.info b/js/js.translator/testData/incremental/invalidation/splitJoinModule/project.info new file mode 100644 index 00000000000..e6e487ff080 --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/splitJoinModule/project.info @@ -0,0 +1,17 @@ +MODULES: lib1, lib1-a, lib1-b, lib1-c, lib2, main + +STEP 0: + libs: lib1, lib2, main + dirty js: lib1, lib2, main +STEP 1: + libs: lib1-a, lib1-b, lib1-c, lib2, main + dirty js: lib1-a, lib1-b, lib1-c, lib2 +STEP 2..3: + libs: lib1-a, lib1-b, lib1-c, lib2, main + dirty js: lib1-b, lib2 +STEP 4: + libs: lib1, lib2, main + dirty js: lib1, lib2 +STEP 5: + libs: lib1, lib2, main + dirty js: lib1