From 7b2c1257542751972980583e24a5fecea485ba51 Mon Sep 17 00:00:00 2001 From: Alexander Korepanov Date: Wed, 12 Oct 2022 22:14:15 +0000 Subject: [PATCH] [JS IR] Update IC depends graph after intrinsics loading - Remove unused params from compilerWithIC wrapper. - Move JsIrBackendContext creation logic into separate function - Introduce and use compiler interface for IC infrastructure On dirty rebuild we may reload IR from stdlib, such reloading may affect files with intrinsics and builtins. As soon as we load only exported symbols, we must track dependencies for files with intrinsics or builtins as for others. This patch implements the logic which updates dependencies for the stdlib files after loading of intrinsics and builtins. ^KT-54323 Fixed --- .../jetbrains/kotlin/cli/js/K2JsIrCompiler.kt | 2 +- .../kotlin/ir/backend/js/compilerWithIC.kt | 95 +++---- .../kotlin/ir/backend/js/ic/CacheUpdater.kt | 260 ++++++++++++------ .../ir/backend/js/ic/JsIrLinkerLoader.kt | 11 +- .../backend/js/ic/KotlinSourceFileMetadata.kt | 3 + .../incremental/AbstractInvalidationTest.kt | 22 +- .../InvalidationTestGenerated.java | 15 + .../companionFunction/lib1/l1.0.kt | 15 + .../companionFunction/lib1/l1.1.kt | 15 + .../companionFunction/lib1/module.info | 8 + .../companionFunction/lib2/l2.0.kt | 15 + .../companionFunction/lib2/module.info | 7 + .../invalidation/companionFunction/main/m.kt | 10 + .../companionFunction/main/module.info | 5 + .../companionFunction/project.info | 8 + .../enumsInInlineFunctions/lib1/l1.0.kt | 13 + .../enumsInInlineFunctions/lib1/l1.1.kt | 23 ++ .../enumsInInlineFunctions/lib1/l1.2.kt | 23 ++ .../enumsInInlineFunctions/lib1/l1.4.kt | 11 + .../enumsInInlineFunctions/lib1/module.info | 18 ++ .../enumsInInlineFunctions/lib2/l2.0.kt | 12 + .../enumsInInlineFunctions/lib2/l2.3.kt | 12 + .../enumsInInlineFunctions/lib2/module.info | 19 ++ .../enumsInInlineFunctions/main/m.kt | 27 ++ .../enumsInInlineFunctions/main/module.info | 5 + .../enumsInInlineFunctions/project.info | 5 + .../exceptionsFromInlineFunction/lib1/l1.0.kt | 1 + .../exceptionsFromInlineFunction/lib1/l1.1.kt | 4 + .../lib1/l1.3.8.kt | 4 + .../exceptionsFromInlineFunction/lib1/l1.5.kt | 4 + .../exceptionsFromInlineFunction/lib1/l1.6.kt | 1 + .../lib1/module.info | 27 ++ .../exceptionsFromInlineFunction/lib2/l2.0.kt | 3 + .../exceptionsFromInlineFunction/lib2/l2.2.kt | 7 + .../exceptionsFromInlineFunction/lib2/l2.4.kt | 7 + .../exceptionsFromInlineFunction/lib2/l2.7.kt | 3 + .../lib2/module.info | 32 +++ .../exceptionsFromInlineFunction/main/m.kt | 15 + .../main/module.info | 5 + .../exceptionsFromInlineFunction/project.info | 26 ++ 40 files changed, 628 insertions(+), 170 deletions(-) create mode 100644 js/js.translator/testData/incremental/invalidation/companionFunction/lib1/l1.0.kt create mode 100644 js/js.translator/testData/incremental/invalidation/companionFunction/lib1/l1.1.kt create mode 100644 js/js.translator/testData/incremental/invalidation/companionFunction/lib1/module.info create mode 100644 js/js.translator/testData/incremental/invalidation/companionFunction/lib2/l2.0.kt create mode 100644 js/js.translator/testData/incremental/invalidation/companionFunction/lib2/module.info create mode 100644 js/js.translator/testData/incremental/invalidation/companionFunction/main/m.kt create mode 100644 js/js.translator/testData/incremental/invalidation/companionFunction/main/module.info create mode 100644 js/js.translator/testData/incremental/invalidation/companionFunction/project.info create mode 100644 js/js.translator/testData/incremental/invalidation/enumsInInlineFunctions/lib1/l1.0.kt create mode 100644 js/js.translator/testData/incremental/invalidation/enumsInInlineFunctions/lib1/l1.1.kt create mode 100644 js/js.translator/testData/incremental/invalidation/enumsInInlineFunctions/lib1/l1.2.kt create mode 100644 js/js.translator/testData/incremental/invalidation/enumsInInlineFunctions/lib1/l1.4.kt create mode 100644 js/js.translator/testData/incremental/invalidation/enumsInInlineFunctions/lib1/module.info create mode 100644 js/js.translator/testData/incremental/invalidation/enumsInInlineFunctions/lib2/l2.0.kt create mode 100644 js/js.translator/testData/incremental/invalidation/enumsInInlineFunctions/lib2/l2.3.kt create mode 100644 js/js.translator/testData/incremental/invalidation/enumsInInlineFunctions/lib2/module.info create mode 100644 js/js.translator/testData/incremental/invalidation/enumsInInlineFunctions/main/m.kt create mode 100644 js/js.translator/testData/incremental/invalidation/enumsInInlineFunctions/main/module.info create mode 100644 js/js.translator/testData/incremental/invalidation/enumsInInlineFunctions/project.info create mode 100644 js/js.translator/testData/incremental/invalidation/exceptionsFromInlineFunction/lib1/l1.0.kt create mode 100644 js/js.translator/testData/incremental/invalidation/exceptionsFromInlineFunction/lib1/l1.1.kt create mode 100644 js/js.translator/testData/incremental/invalidation/exceptionsFromInlineFunction/lib1/l1.3.8.kt create mode 100644 js/js.translator/testData/incremental/invalidation/exceptionsFromInlineFunction/lib1/l1.5.kt create mode 100644 js/js.translator/testData/incremental/invalidation/exceptionsFromInlineFunction/lib1/l1.6.kt create mode 100644 js/js.translator/testData/incremental/invalidation/exceptionsFromInlineFunction/lib1/module.info create mode 100644 js/js.translator/testData/incremental/invalidation/exceptionsFromInlineFunction/lib2/l2.0.kt create mode 100644 js/js.translator/testData/incremental/invalidation/exceptionsFromInlineFunction/lib2/l2.2.kt create mode 100644 js/js.translator/testData/incremental/invalidation/exceptionsFromInlineFunction/lib2/l2.4.kt create mode 100644 js/js.translator/testData/incremental/invalidation/exceptionsFromInlineFunction/lib2/l2.7.kt create mode 100644 js/js.translator/testData/incremental/invalidation/exceptionsFromInlineFunction/lib2/module.info create mode 100644 js/js.translator/testData/incremental/invalidation/exceptionsFromInlineFunction/main/m.kt create mode 100644 js/js.translator/testData/incremental/invalidation/exceptionsFromInlineFunction/main/module.info create mode 100644 js/js.translator/testData/incremental/invalidation/exceptionsFromInlineFunction/project.info 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 288e650888e..eb3af666cd2 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 @@ -289,7 +289,7 @@ class K2JsIrCompiler : CLICompiler() { compilerConfiguration = configurationJs, irFactory = { IrFactoryImplForJsIC(WholeWorldStageController()) }, mainArguments = mainCallArguments, - executor = ::buildCacheForModuleFiles + compilerInterfaceFactory = { mainModule, cfg -> JsIrCompilerWithIC(mainModule, cfg) } ) var tp = System.currentTimeMillis() diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compilerWithIC.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compilerWithIC.kt index f43c70f0b39..063d71b73f6 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compilerWithIC.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compilerWithIC.kt @@ -7,88 +7,65 @@ package org.jetbrains.kotlin.ir.backend.js import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig import org.jetbrains.kotlin.backend.common.phaser.PhaserState -import org.jetbrains.kotlin.backend.common.serialization.linkerissues.checkNoUnboundSymbols import org.jetbrains.kotlin.config.CompilerConfiguration import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI +import org.jetbrains.kotlin.ir.backend.js.ic.JsIrCompilerICInterface import org.jetbrains.kotlin.ir.backend.js.lower.collectNativeImplementations import org.jetbrains.kotlin.ir.backend.js.lower.generateJsTests import org.jetbrains.kotlin.ir.backend.js.lower.moveBodilessDeclarationsToSeparatePlace -import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsIrLinker import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.* import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.declarations.IrModuleFragment -import org.jetbrains.kotlin.ir.util.ExternalDependenciesGenerator -import org.jetbrains.kotlin.js.config.RuntimeDiagnostic import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.psi2ir.descriptors.IrBuiltInsOverDescriptors -@Suppress("UNUSED_PARAMETER") @OptIn(ObsoleteDescriptorBasedAPI::class) -fun compileWithIC( - mainModule: IrModuleFragment, +class JsIrCompilerWithIC( + private val mainModule: IrModuleFragment, configuration: CompilerConfiguration, - irLinker: JsIrLinker, - allModules: Collection, - filesToLower: Collection, - mainArguments: List? = null, exportedDeclarations: Set = emptySet(), - keep: Set = emptySet(), - generateFullJs: Boolean = true, - generateDceJs: Boolean = false, - dceDriven: Boolean = false, - dceRuntimeDiagnostic: RuntimeDiagnostic? = null, - es6mode: Boolean = false, - multiModule: Boolean = false, - verifySignatures: Boolean = true, - baseClassIntoMetadata: Boolean = false, - lowerPerModule: Boolean = false, - safeExternalBoolean: Boolean = false, - safeExternalBooleanDiagnostic: RuntimeDiagnostic? = null, -): List { - val irBuiltIns = mainModule.irBuiltins - val symbolTable = (irBuiltIns as IrBuiltInsOverDescriptors).symbolTable + es6mode: Boolean = false +) : JsIrCompilerICInterface { + private val context: JsIrBackendContext - val context = JsIrBackendContext( - mainModule.descriptor, - irBuiltIns, - symbolTable, - mainModule, - exportedDeclarations, - keep, - configuration, - es6mode = es6mode, - dceRuntimeDiagnostic = dceRuntimeDiagnostic, - baseClassIntoMetadata = baseClassIntoMetadata, - safeExternalBoolean = safeExternalBoolean, - safeExternalBooleanDiagnostic = safeExternalBooleanDiagnostic, - icCompatibleIr2Js = IcCompatibleIr2Js.IC_MODE, - ) + init { + val irBuiltIns = mainModule.irBuiltins + val symbolTable = (irBuiltIns as IrBuiltInsOverDescriptors).symbolTable - // Load declarations referenced during `context` initialization - val irProviders = listOf(irLinker) - ExternalDependenciesGenerator(symbolTable, irProviders).generateUnboundSymbolsAsDependencies() - - irLinker.postProcess() - irLinker.checkNoUnboundSymbols(symbolTable, "at the end of IR linkage process") - - allModules.forEach { - collectNativeImplementations(context, it) - moveBodilessDeclarationsToSeparatePlace(context, it) + context = JsIrBackendContext( + mainModule.descriptor, + irBuiltIns, + symbolTable, + mainModule, + exportedDeclarations, + keep = emptySet(), + configuration = configuration, + es6mode = es6mode, + icCompatibleIr2Js = IcCompatibleIr2Js.IC_MODE, + ) } - generateJsTests(context, mainModule) + override fun compile( + allModules: Collection, + dirtyFiles: Collection, + mainArguments: List? + ): List { + allModules.forEach { + collectNativeImplementations(context, it) + moveBodilessDeclarationsToSeparatePlace(context, it) + } - lowerPreservingTags(allModules, context, PhaseConfig(jsPhases), symbolTable.irFactory.stageController as WholeWorldStageController) + generateJsTests(context, mainModule) - val transformer = IrModuleToJsTransformerTmp(context, mainArguments) - return transformer.generateBinaryAst(filesToLower, allModules) + lowerPreservingTags(allModules, context, PhaseConfig(jsPhases), context.irFactory.stageController as WholeWorldStageController) + + val transformer = IrModuleToJsTransformerTmp(context, mainArguments) + return transformer.generateBinaryAst(dirtyFiles, allModules) + } } fun lowerPreservingTags( - modules: Iterable, - context: JsIrBackendContext, - phaseConfig: PhaseConfig, - controller: WholeWorldStageController + modules: Iterable, context: JsIrBackendContext, phaseConfig: PhaseConfig, controller: WholeWorldStageController ) { // Lower all the things controller.currentStage = 0 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 4b146387dd6..b6762ed0f5c 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 @@ -9,7 +9,6 @@ import org.jetbrains.kotlin.descriptors.DescriptorVisibilities import org.jetbrains.kotlin.ir.backend.js.* import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsIrLinker import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsIrFragmentAndBinaryAst -import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.safeModuleName import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.symbols.IrSymbol import org.jetbrains.kotlin.ir.util.* @@ -22,19 +21,21 @@ import org.jetbrains.kotlin.name.FqName import java.io.File import java.util.EnumSet - -fun interface CacheExecutor { - fun execute( - mainModule: IrModuleFragment, +fun interface JsIrCompilerICInterface { + fun compile( allModules: Collection, - irLinker: JsIrLinker, - configuration: CompilerConfiguration, dirtyFiles: Collection, - exportedDeclarations: Set, mainArguments: List? ): List } +fun interface JsIrCompilerICInterfaceFactory { + fun createCompilerForIC( + mainModule: IrModuleFragment, + configuration: CompilerConfiguration + ): JsIrCompilerICInterface +} + enum class DirtyFileState(val str: String) { ADDED_FILE("added file"), MODIFIED_CONFIG("modified config"), @@ -53,7 +54,7 @@ class CacheUpdater( private val compilerConfiguration: CompilerConfiguration, private val irFactory: () -> IrFactory, private val mainArguments: List?, - private val executor: CacheExecutor + private val compilerInterfaceFactory: JsIrCompilerICInterfaceFactory ) { private val signatureHashCalculator = IdSignatureHashCalculator() @@ -323,47 +324,84 @@ class CacheUpdater( return allSignatures } + private fun IdSignatureHashCalculator.addAllSignatureSymbols(idSignatureToFile: Map) { + for ((signature, signatureSrc) in idSignatureToFile) { + addHashForSignatureIfNotExist(signature, signatureSrc.symbol) + } + } + + private fun KotlinSourceFileMutableMap.getExportedSignaturesAndAddMetadata( + jsIrLinker: JsIrLinker, + irModule: IrModuleFragment, + libFile: KotlinLibraryFile, + dirtySrcFiles: Set + ): Map { + val idSignatureToFile = hashMapOf() + val moduleDeserializer = jsIrLinker.moduleDeserializer(irModule.descriptor) + val incrementalCache = getLibIncrementalCache(libFile) + for (fileDeserializer in moduleDeserializer.fileDeserializers()) { + val reachableSignatures = fileDeserializer.symbolDeserializer.signatureDeserializer.signatureToIndexMapping() + val maybeImportedSignatures = reachableSignatures.keys.toMutableSet() + val implementedSymbols = collectImplementedSymbol(fileDeserializer.symbolDeserializer.deserializedSymbols) + for ((signature, symbol) in implementedSymbols) { + var symbolCanBeExported = maybeImportedSignatures.remove(signature) + resolveFakeOverrideFunction(symbol)?.let { resolvedSignature -> + if (resolvedSignature !in implementedSymbols) { + maybeImportedSignatures.add(resolvedSignature) + } + symbolCanBeExported = true + } + if (symbolCanBeExported) { + idSignatureToFile[signature] = SignatureSource(libFile, KotlinSourceFile(fileDeserializer.file), symbol) + } + } + + val libSrcFile = KotlinSourceFile(fileDeserializer.file) + if (libSrcFile in dirtySrcFiles) { + val metadata = incrementalCache.fetchSourceFileFullMetadata(libSrcFile) + this[libFile, libSrcFile] = DirtyFileMetadata(maybeImportedSignatures, metadata.directDependencies) + } + } + return idSignatureToFile + } + + private fun DirtyFileMetadata.setAllDependencies( + idSignatureToFile: Map, + updatedMetadata: KotlinSourceFileMap, + libFile: KotlinLibraryFile, + srcFile: KotlinSourceFile + ) { + val allImportedSignatures = addParentSignatures(maybeImportedSignatures, idSignatureToFile, libFile, srcFile) + for (importedSignature in allImportedSignatures) { + val (dependencyLib, dependencyFile) = idSignatureToFile[importedSignature] ?: continue + signatureHashCalculator[importedSignature]?.also { signatureHash -> + addDirectDependency(dependencyLib, dependencyFile, importedSignature, signatureHash) + } ?: notFoundIcError("signature $importedSignature hash", dependencyLib, dependencyFile) + + updatedMetadata[dependencyLib, dependencyFile]?.also { dependencyMetadata -> + dependencyMetadata.addInverseDependency(libFile, srcFile, importedSignature) + } + } + } + private fun rebuildDirtySourceMetadata( jsIrLinker: JsIrLinker, loadedFragments: Map, dirtySrcFiles: KotlinSourceFileMap, ): KotlinSourceFileMap { - val idSignatureToFile = mutableMapOf() + val idSignatureToFile = hashMapOf() val updatedMetadata = KotlinSourceFileMutableMap() for ((lib, irModule) in loadedFragments) { - val moduleDeserializer = jsIrLinker.moduleDeserializer(irModule.descriptor) - val incrementalCache = getLibIncrementalCache(lib) - for (fileDeserializer in moduleDeserializer.fileDeserializers()) { - val libSrcFile = KotlinSourceFile(fileDeserializer.file) - - val reachableSignatures = fileDeserializer.symbolDeserializer.signatureDeserializer.signatureToIndexMapping() - val maybeImportedSignatures = reachableSignatures.keys.toMutableSet() - val implementedSymbols = collectImplementedSymbol(fileDeserializer.symbolDeserializer.deserializedSymbols) - for ((signature, symbol) in implementedSymbols) { - var symbolCanBeExported = maybeImportedSignatures.remove(signature) - resolveFakeOverrideFunction(symbol)?.let { resolvedSignature -> - if (resolvedSignature !in implementedSymbols) { - maybeImportedSignatures.add(resolvedSignature) - } - symbolCanBeExported = true - } - if (symbolCanBeExported) { - signatureHashCalculator.addHashForSignatureIfNotExist(signature, symbol) - idSignatureToFile[signature] = SignatureSource(lib, libSrcFile, symbol) - } - } - - if (dirtySrcFiles[lib, libSrcFile] != null) { - val metadata = incrementalCache.fetchSourceFileFullMetadata(libSrcFile) - updatedMetadata[lib, libSrcFile] = DirtyFileMetadata(maybeImportedSignatures, metadata.directDependencies) - } - } + val libDirtySrcFiles = dirtySrcFiles[lib]?.keys ?: emptySet() + idSignatureToFile += updatedMetadata.getExportedSignaturesAndAddMetadata(jsIrLinker, irModule, lib, libDirtySrcFiles) } + signatureHashCalculator.addAllSignatureSymbols(idSignatureToFile) + for ((libFile, srcFiles) in updatedMetadata) { val libDirtySrcFiles = dirtySrcFiles[libFile] ?: continue - for ((srcFile, internalHeader) in srcFiles) { + for ((srcFile, updatedHeader) in srcFiles) { val dirtySrcFile = libDirtySrcFiles[srcFile] ?: continue dirtySrcFile.inverseDependencies.forEachFile { dependentLibFile, dependentSrcFile, signatures -> signatures.forEach { signature -> @@ -376,17 +414,7 @@ class CacheUpdater( } } - val allImportedSignatures = addParentSignatures(internalHeader.maybeImportedSignatures, idSignatureToFile, libFile, srcFile) - for (importedSignature in allImportedSignatures) { - val (dependencyLib, dependencyFile) = idSignatureToFile[importedSignature] ?: continue - signatureHashCalculator[importedSignature]?.also { signatureHash -> - internalHeader.addDirectDependency(dependencyLib, dependencyFile, importedSignature, signatureHash) - } ?: notFoundIcError("signature $importedSignature hash", dependencyLib, dependencyFile) - - updatedMetadata[dependencyLib, dependencyFile]?.also { dependencyMetadata -> - dependencyMetadata.addInverseDependency(libFile, srcFile, importedSignature) - } - } + updatedHeader.setAllDependencies(idSignatureToFile, updatedMetadata, libFile, srcFile) } } @@ -561,6 +589,95 @@ class CacheUpdater( return artifacts } + private fun updateStdlibIntrinsicDependencies( + linker: JsIrLinker, + mainModule: IrModuleFragment, + loadedFragments: Map, + dirtyFileExports: KotlinSourceFileMap<*> + ) { + val stdlibDescriptor = mainModule.descriptor.builtIns.builtInsModule + val (stdlibFile, stdlibIr) = loadedFragments.entries.find { + it.value.descriptor === stdlibDescriptor + } ?: notFoundIcError("stdlib loaded fragment") + + val stdlibDirtyFiles = dirtyFileExports[stdlibFile]?.keys ?: return + + signatureHashCalculator.updateInlineFunctionTransitiveHashes(listOf(stdlibIr)) + + val updatedMetadata = KotlinSourceFileMutableMap() + val idSignatureToFile = updatedMetadata.getExportedSignaturesAndAddMetadata(linker, stdlibIr, stdlibFile, stdlibDirtyFiles) + + signatureHashCalculator.addAllSignatureSymbols(idSignatureToFile) + + updatedMetadata.forEachFile { libFile, srcFile, updatedHeader -> + updatedHeader.setAllDependencies(idSignatureToFile, updatedMetadata, libFile, srcFile) + } + + val incrementalCache = getLibIncrementalCache(stdlibFile) + updatedMetadata.forEachFile { libFile, srcFile, updatedHeader -> + if (libFile != stdlibFile) { + icError("unexpected lib while parsing stdlib dependencies", libFile, srcFile) + } + + val cachedHeader = incrementalCache.fetchSourceFileFullMetadata(srcFile) + + val needUpdate = when { + !updatedHeader.directDependencies.allFiles { lib, file, dependencies -> + cachedHeader.directDependencies[lib, file]?.keys?.containsAll(dependencies.keys) ?: dependencies.isEmpty() + } -> true + + !updatedHeader.inverseDependencies.allFiles { lib, file, invDependencies -> + cachedHeader.inverseDependencies[lib, file]?.containsAll(invDependencies) ?: invDependencies.isEmpty() + } -> true + + else -> false + } + if (needUpdate) { + cachedHeader.directDependencies.forEachFile { lib, file, dependencies -> + val updatedDependencies = updatedHeader.directDependencies[lib, file] + if (updatedDependencies != null) { + updatedDependencies += dependencies + } else { + updatedHeader.directDependencies[lib, file] = HashMap(dependencies) + } + } + cachedHeader.inverseDependencies.forEachFile { lib, file, dependencies -> + val updatedDependencies = updatedHeader.inverseDependencies[lib, file] + if (updatedDependencies != null) { + updatedDependencies += dependencies + } else { + updatedHeader.inverseDependencies[lib, file] = HashSet(dependencies) + } + } + incrementalCache.updateSourceFileMetadata(srcFile, updatedHeader) + } + } + } + + private fun compileDirtyFiles( + linker: JsIrLinker, + loadedFragments: Map, + dirtyFileExports: KotlinSourceFileMap<*> + ): List { + val mainModule = loadedFragments[mainLibraryFile] ?: notFoundIcError("main lib loaded fragment", mainLibraryFile) + val compilerForIC = compilerInterfaceFactory.createCompilerForIC(mainModule, compilerConfiguration) + + // Load declarations referenced during `context` initialization + linker.loadUnboundSymbols(true) + + updateStdlibIntrinsicDependencies(linker, mainModule, loadedFragments, dirtyFileExports) + + return compilerForIC.compile( + allModules = loadedFragments.values, + dirtyFiles = loadedFragments.flatMap { (libFile, libFragment) -> + dirtyFileExports[libFile]?.let { libDirtyFiles -> + libFragment.files.filter { file -> KotlinSourceFile(file) in libDirtyFiles } + } ?: emptyList() + }, + mainArguments = mainArguments + ) + } + fun actualizeCaches(eventCallback: (String) -> Unit = {}): List { dirtyFileStats.clear() @@ -601,19 +718,7 @@ class CacheUpdater( eventCallback("final loading of updated files") } - val rebuiltFragments = executor.execute( - mainModule = loadedIr.loadedFragments[mainLibraryFile] ?: notFoundIcError("main lib loaded fragment", mainLibraryFile), - allModules = loadedIr.loadedFragments.values, - irLinker = loadedIr.linker, - configuration = compilerConfiguration, - dirtyFiles = loadedIr.loadedFragments.flatMap { (libFile, libFragment) -> - dirtyFileExports[libFile]?.let { libDirtyFiles -> - libFragment.files.filter { file -> KotlinSourceFile(file) in libDirtyFiles } - } ?: emptyList() - }, - exportedDeclarations = emptySet(), - mainArguments = mainArguments - ) + val rebuiltFragments = compileDirtyFiles(loadedIr.linker, loadedIr.loadedFragments, dirtyFileExports) eventCallback("updated files processing (lowering)") val artifacts = buildModuleArtifactsAndCommitCache(loadedIr.linker, loadedIr.loadedFragments, rebuiltFragments) @@ -650,33 +755,14 @@ fun rebuildCacheForDirtyFiles( currentIrModule.files.filter { irFile -> irFile.fileEntry.name in files } } ?: currentIrModule.files - return currentIrModule to buildCacheForModuleFiles( - mainModule = currentIrModule, + val compilerWithIC = JsIrCompilerWithIC(currentIrModule, configuration, exportedDeclarations) + + // Load declarations referenced during `context` initialization + jsIrLinker.loadUnboundSymbols(true) + + return currentIrModule to compilerWithIC.compile( allModules = irModules.values, - irLinker = jsIrLinker, - configuration = configuration, dirtyFiles = dirtyIrFiles, - exportedDeclarations = exportedDeclarations, mainArguments = mainArguments ) } - -fun buildCacheForModuleFiles( - mainModule: IrModuleFragment, - allModules: Collection, - irLinker: JsIrLinker, - configuration: CompilerConfiguration, - dirtyFiles: Collection, - exportedDeclarations: Set, - mainArguments: List? -): List { - return compileWithIC( - mainModule = mainModule, - allModules = allModules, - filesToLower = dirtyFiles, - configuration = configuration, - irLinker = irLinker, - mainArguments = mainArguments, - exportedDeclarations = exportedDeclarations, - ) -} diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/JsIrLinkerLoader.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/JsIrLinkerLoader.kt index 053037c8c4a..9c524f32d56 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/JsIrLinkerLoader.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/JsIrLinkerLoader.kt @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.ir.backend.js.ic import org.jetbrains.kotlin.backend.common.serialization.DeserializationStrategy +import org.jetbrains.kotlin.backend.common.serialization.linkerissues.checkNoUnboundSymbols import org.jetbrains.kotlin.backend.common.serialization.signature.IdSignatureDescriptor import org.jetbrains.kotlin.config.CompilerConfiguration import org.jetbrains.kotlin.config.languageVersionSettings @@ -27,6 +28,13 @@ import org.jetbrains.kotlin.psi2ir.descriptors.IrBuiltInsOverDescriptors import org.jetbrains.kotlin.psi2ir.generators.TypeTranslatorImpl import org.jetbrains.kotlin.storage.LockBasedStorageManager +internal fun JsIrLinker.loadUnboundSymbols(checkNoUnbound: Boolean) { + ExternalDependenciesGenerator(symbolTable, listOf(this)).generateUnboundSymbolsAsDependencies() + postProcess() + if (checkNoUnbound) { + checkNoUnboundSymbols(symbolTable, "at the end of IR linkage process") + } +} internal class JsIrLinkerLoader( private val compilerConfiguration: CompilerConfiguration, @@ -109,8 +117,7 @@ internal class JsIrLinkerLoader( } } - ExternalDependenciesGenerator(jsIrLinker.symbolTable, listOf(jsIrLinker)).generateUnboundSymbolsAsDependencies() - jsIrLinker.postProcess() + jsIrLinker.loadUnboundSymbols(false) return LoadedJsIr(jsIrLinker, irModules) } } 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 f7cf83df826..4fa7b4ea119 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 @@ -46,6 +46,9 @@ open class KotlinSourceFileMap(files: Map Unit) = forEach { (lib, files) -> files.forEach { (file, data) -> f(lib, file, data) } } + inline fun allFiles(p: (KotlinLibraryFile, KotlinSourceFile, T) -> Boolean) = + entries.all { (lib, files) -> files.entries.all { (file, data) -> p(lib, file, data) } } + operator fun get(libFile: KotlinLibraryFile, sourceFile: KotlinSourceFile): T? = get(libFile)?.get(sourceFile) } 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 76880fa30e7..79947eb6848 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/incremental/AbstractInvalidationTest.kt +++ b/js/js.tests/test/org/jetbrains/kotlin/incremental/AbstractInvalidationTest.kt @@ -226,26 +226,6 @@ abstract class AbstractInvalidationTest : KotlinTestWithEnvironment() { } } - fun executorWithBoxExport( - currentModule: IrModuleFragment, - allModules: Collection, - irLinker: JsIrLinker, - configuration: CompilerConfiguration, - dirtyFiles: Collection, - exportedDeclarations: Set, - mainArguments: List? - ): List { - return buildCacheForModuleFiles( - mainModule = currentModule, - allModules = allModules, - irLinker = irLinker, - configuration = configuration, - dirtyFiles = dirtyFiles, - exportedDeclarations = exportedDeclarations + FqName(BOX_FUNCTION_NAME), - mainArguments = mainArguments, - ) - } - fun execute() { val stdlibCacheDir = resolveModuleCache(STDLIB_ALIAS, buildDir).canonicalPath for (projStep in projectInfo.steps) { @@ -259,7 +239,7 @@ abstract class AbstractInvalidationTest : KotlinTestWithEnvironment() { compilerConfiguration = configuration, irFactory = { IrFactoryImplForJsIC(WholeWorldStageController()) }, mainArguments = null, - executor = ::executorWithBoxExport + compilerInterfaceFactory = { mainModule, cfg -> JsIrCompilerWithIC(mainModule, cfg, setOf(FqName(BOX_FUNCTION_NAME))) } ) val icCaches = cacheUpdater.actualizeCaches() 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 f40d52903b0..ecce40699d1 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 @@ -60,6 +60,11 @@ public class InvalidationTestGenerated extends AbstractInvalidationTest { runTest("js/js.translator/testData/incremental/invalidation/classFunctionsAndFields/"); } + @TestMetadata("companionFunction") + public void testCompanionFunction() throws Exception { + runTest("js/js.translator/testData/incremental/invalidation/companionFunction/"); + } + @TestMetadata("companionInlineFunction") public void testCompanionInlineFunction() throws Exception { runTest("js/js.translator/testData/incremental/invalidation/companionInlineFunction/"); @@ -90,6 +95,16 @@ public class InvalidationTestGenerated extends AbstractInvalidationTest { runTest("js/js.translator/testData/incremental/invalidation/enum/"); } + @TestMetadata("enumsInInlineFunctions") + public void testEnumsInInlineFunctions() throws Exception { + runTest("js/js.translator/testData/incremental/invalidation/enumsInInlineFunctions/"); + } + + @TestMetadata("exceptionsFromInlineFunction") + public void testExceptionsFromInlineFunction() throws Exception { + runTest("js/js.translator/testData/incremental/invalidation/exceptionsFromInlineFunction/"); + } + @TestMetadata("exportsThroughInlineFunction") public void testExportsThroughInlineFunction() throws Exception { runTest("js/js.translator/testData/incremental/invalidation/exportsThroughInlineFunction/"); diff --git a/js/js.translator/testData/incremental/invalidation/companionFunction/lib1/l1.0.kt b/js/js.translator/testData/incremental/invalidation/companionFunction/lib1/l1.0.kt new file mode 100644 index 00000000000..c20460e7656 --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/companionFunction/lib1/l1.0.kt @@ -0,0 +1,15 @@ +interface MyInterface { + fun interfaceFunction(): String +} + +class MyClass1 { + companion object { + fun companionFunction() = 0 + } +} + +class MyClass2 { + companion object { + fun companionFunction() = "0" + } +} diff --git a/js/js.translator/testData/incremental/invalidation/companionFunction/lib1/l1.1.kt b/js/js.translator/testData/incremental/invalidation/companionFunction/lib1/l1.1.kt new file mode 100644 index 00000000000..b559030e0a6 --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/companionFunction/lib1/l1.1.kt @@ -0,0 +1,15 @@ +interface MyInterface { + fun interfaceFunction(): String +} + +class MyClass1 { + companion object { + fun companionFunction() = 1 + } +} + +class MyClass2 { + companion object { + fun companionFunction() = "1" + } +} diff --git a/js/js.translator/testData/incremental/invalidation/companionFunction/lib1/module.info b/js/js.translator/testData/incremental/invalidation/companionFunction/lib1/module.info new file mode 100644 index 00000000000..0c8ddc97230 --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/companionFunction/lib1/module.info @@ -0,0 +1,8 @@ +STEP 0: + modifications: + U : l1.0.kt -> l1.kt + added file: l1.kt +STEP 1: + modifications: + U : l1.1.kt -> l1.kt + modified ir: l1.kt diff --git a/js/js.translator/testData/incremental/invalidation/companionFunction/lib2/l2.0.kt b/js/js.translator/testData/incremental/invalidation/companionFunction/lib2/l2.0.kt new file mode 100644 index 00000000000..0faf1f14149 --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/companionFunction/lib2/l2.0.kt @@ -0,0 +1,15 @@ +inline fun makeMyInterfaceObject(x: Boolean): MyInterface { + return if (x) { + object : MyInterface { + override fun interfaceFunction(): String { + return MyClass1.companionFunction().toString() + } + } + } else { + object : MyInterface { + override fun interfaceFunction(): String { + return MyClass2.companionFunction() + } + } + } +} diff --git a/js/js.translator/testData/incremental/invalidation/companionFunction/lib2/module.info b/js/js.translator/testData/incremental/invalidation/companionFunction/lib2/module.info new file mode 100644 index 00000000000..5cdd3eaea20 --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/companionFunction/lib2/module.info @@ -0,0 +1,7 @@ +STEP 0: + dependencies: lib1 + modifications: + U : l2.0.kt -> l2.kt + added file: l2.kt +STEP 1: + dependencies: lib1 diff --git a/js/js.translator/testData/incremental/invalidation/companionFunction/main/m.kt b/js/js.translator/testData/incremental/invalidation/companionFunction/main/m.kt new file mode 100644 index 00000000000..74b0b894e5e --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/companionFunction/main/m.kt @@ -0,0 +1,10 @@ +fun box(stepId: Int): String { + when (stepId) { + 0, 1 -> { + if (makeMyInterfaceObject(false).interfaceFunction() != "$stepId") return "Fail x = false" + if (makeMyInterfaceObject(true).interfaceFunction() != "$stepId") return "Fail x = true" + } + else -> return "Unknown" + } + return "OK" +} diff --git a/js/js.translator/testData/incremental/invalidation/companionFunction/main/module.info b/js/js.translator/testData/incremental/invalidation/companionFunction/main/module.info new file mode 100644 index 00000000000..406ec8bd244 --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/companionFunction/main/module.info @@ -0,0 +1,5 @@ +STEP 0: + dependencies: lib1, lib2 + added file: m.kt +STEP 1: + dependencies: lib1, lib2 diff --git a/js/js.translator/testData/incremental/invalidation/companionFunction/project.info b/js/js.translator/testData/incremental/invalidation/companionFunction/project.info new file mode 100644 index 00000000000..3a84c058f4e --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/companionFunction/project.info @@ -0,0 +1,8 @@ +MODULES: lib1, lib2, main + +STEP 0: + libs: lib1, lib2, main + dirty js: lib1, lib2, main +STEP 1: + libs: lib1, lib2, main + dirty js: lib1 diff --git a/js/js.translator/testData/incremental/invalidation/enumsInInlineFunctions/lib1/l1.0.kt b/js/js.translator/testData/incremental/invalidation/enumsInInlineFunctions/lib1/l1.0.kt new file mode 100644 index 00000000000..a41d92e9f8f --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/enumsInInlineFunctions/lib1/l1.0.kt @@ -0,0 +1,13 @@ +class TestClass1 { + enum class TestEnum { + A, B + } +} + +inline fun foo1(): List> { + return TestClass1.TestEnum.values().toList() +} + +inline fun foo2(): List> { + return emptyList() +} diff --git a/js/js.translator/testData/incremental/invalidation/enumsInInlineFunctions/lib1/l1.1.kt b/js/js.translator/testData/incremental/invalidation/enumsInInlineFunctions/lib1/l1.1.kt new file mode 100644 index 00000000000..723752857fd --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/enumsInInlineFunctions/lib1/l1.1.kt @@ -0,0 +1,23 @@ +class TestClass1 { + enum class TestEnum { + A, B + } +} + +class TestClass2 { + enum class TestEnum { + A, B, C + } +} + +inline fun foo1(): List> { + return TestClass1.TestEnum.values().toList() +} + +inline fun foo2(): List> { + return TestClass2.TestEnum.values().toList() +} + +inline fun foo3(): List> { + return emptyList() +} diff --git a/js/js.translator/testData/incremental/invalidation/enumsInInlineFunctions/lib1/l1.2.kt b/js/js.translator/testData/incremental/invalidation/enumsInInlineFunctions/lib1/l1.2.kt new file mode 100644 index 00000000000..95ee3a6d8e5 --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/enumsInInlineFunctions/lib1/l1.2.kt @@ -0,0 +1,23 @@ +class TestClass1 { + enum class TestEnum { + A, B + } +} + +class TestClass3 { + enum class TestEnum { + A + } +} + +inline fun foo1(): List> { + return TestClass1.TestEnum.values().toList() +} + +inline fun foo2(): List> { + return emptyList() +} + +inline fun foo3(): List> { + return TestClass3.TestEnum.values().toList() +} diff --git a/js/js.translator/testData/incremental/invalidation/enumsInInlineFunctions/lib1/l1.4.kt b/js/js.translator/testData/incremental/invalidation/enumsInInlineFunctions/lib1/l1.4.kt new file mode 100644 index 00000000000..625c22d018b --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/enumsInInlineFunctions/lib1/l1.4.kt @@ -0,0 +1,11 @@ +inline fun foo1(): List> { + return emptyList() +} + +inline fun foo2(): List> { + return emptyList() +} + +inline fun foo3(): List> { + return emptyList() +} diff --git a/js/js.translator/testData/incremental/invalidation/enumsInInlineFunctions/lib1/module.info b/js/js.translator/testData/incremental/invalidation/enumsInInlineFunctions/lib1/module.info new file mode 100644 index 00000000000..880ff7f3d9c --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/enumsInInlineFunctions/lib1/module.info @@ -0,0 +1,18 @@ +STEP 0: + modifications: + U : l1.0.kt -> l1.kt + added file: l1.kt +STEP 1: + modifications: + U : l1.1.kt -> l1.kt + modified ir: l1.kt +STEP 2: + modifications: + U : l1.2.kt -> l1.kt + modified ir: l1.kt +STEP 3: + updated exports: l1.kt +STEP 4: + modifications: + U : l1.4.kt -> l1.kt + modified ir: l1.kt diff --git a/js/js.translator/testData/incremental/invalidation/enumsInInlineFunctions/lib2/l2.0.kt b/js/js.translator/testData/incremental/invalidation/enumsInInlineFunctions/lib2/l2.0.kt new file mode 100644 index 00000000000..757578e1750 --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/enumsInInlineFunctions/lib2/l2.0.kt @@ -0,0 +1,12 @@ +class TestClass100 { + enum class TestEnum { + A, B + } +} + +fun testEnums(): List> { + val enums1 = foo1() + val enums2 = foo2() + + return TestClass100.TestEnum.values().toList() + enums1 + enums2 +} diff --git a/js/js.translator/testData/incremental/invalidation/enumsInInlineFunctions/lib2/l2.3.kt b/js/js.translator/testData/incremental/invalidation/enumsInInlineFunctions/lib2/l2.3.kt new file mode 100644 index 00000000000..3b039ca0877 --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/enumsInInlineFunctions/lib2/l2.3.kt @@ -0,0 +1,12 @@ +class TestClass2 { + enum class TestEnum { + A, B + } +} + +fun testEnums(): List> { + val enums1 = foo1() + val enums3 = foo3() + + return TestClass2.TestEnum.values().toList() + enums1 + enums3 +} diff --git a/js/js.translator/testData/incremental/invalidation/enumsInInlineFunctions/lib2/module.info b/js/js.translator/testData/incremental/invalidation/enumsInInlineFunctions/lib2/module.info new file mode 100644 index 00000000000..f891a18ca3a --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/enumsInInlineFunctions/lib2/module.info @@ -0,0 +1,19 @@ +STEP 0: + dependencies: lib1 + modifications: + U : l2.0.kt -> l2.kt + added file: l2.kt +STEP 1: + dependencies: lib1 + updated imports: l2.kt +STEP 2: + dependencies: lib1 + updated imports: l2.kt +STEP 3: + dependencies: lib1 + modifications: + U : l2.3.kt -> l2.kt + modified ir: l2.kt +STEP 4: + dependencies: lib1 + updated imports: l2.kt diff --git a/js/js.translator/testData/incremental/invalidation/enumsInInlineFunctions/main/m.kt b/js/js.translator/testData/incremental/invalidation/enumsInInlineFunctions/main/m.kt new file mode 100644 index 00000000000..53dee83419a --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/enumsInInlineFunctions/main/m.kt @@ -0,0 +1,27 @@ +fun box(stepId: Int): String { + val enums = testEnums() + when (stepId) { + 0 -> if (enums.toString() != "[A, B, A, B]") return "Fail, got $enums" + 1 -> if (enums.toString() != "[A, B, A, B, A, B, C]") return "Fail, got $enums" + 2 -> if (enums.toString() != "[A, B, A, B]") return "Fail, got $enums" + 3 -> if (enums.toString() != "[A, B, A, B, A]") return "Fail, got $enums" + 4 -> if (enums.toString() != "[A, B]") return "Fail, got $enums" + else -> return "Unknown" + } + + for (i1 in 0..enums.size - 1) { + for (i2 in 0..enums.size - 1) { + if (i1 == i2) { + continue + } + if (enums[i1] == enums[i2]) { + return "Fail eq2" + } + if (enums[i1] === enums[i2]) { + return "Fail eq3" + } + } + } + + return "OK" +} diff --git a/js/js.translator/testData/incremental/invalidation/enumsInInlineFunctions/main/module.info b/js/js.translator/testData/incremental/invalidation/enumsInInlineFunctions/main/module.info new file mode 100644 index 00000000000..d871ce55474 --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/enumsInInlineFunctions/main/module.info @@ -0,0 +1,5 @@ +STEP 0: + dependencies: lib1, lib2 + added file: m.kt +STEP 1..4: + dependencies: lib1, lib2 diff --git a/js/js.translator/testData/incremental/invalidation/enumsInInlineFunctions/project.info b/js/js.translator/testData/incremental/invalidation/enumsInInlineFunctions/project.info new file mode 100644 index 00000000000..b6968123d1d --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/enumsInInlineFunctions/project.info @@ -0,0 +1,5 @@ +MODULES: lib1, lib2, main + +STEP 0..4: + libs: lib1, lib2, main + dirty js: lib1, lib2, main diff --git a/js/js.translator/testData/incremental/invalidation/exceptionsFromInlineFunction/lib1/l1.0.kt b/js/js.translator/testData/incremental/invalidation/exceptionsFromInlineFunction/lib1/l1.0.kt new file mode 100644 index 00000000000..e3e48e33a13 --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/exceptionsFromInlineFunction/lib1/l1.0.kt @@ -0,0 +1 @@ +inline fun foo() = 0 diff --git a/js/js.translator/testData/incremental/invalidation/exceptionsFromInlineFunction/lib1/l1.1.kt b/js/js.translator/testData/incremental/invalidation/exceptionsFromInlineFunction/lib1/l1.1.kt new file mode 100644 index 00000000000..c2fb358e3db --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/exceptionsFromInlineFunction/lib1/l1.1.kt @@ -0,0 +1,4 @@ +inline fun foo() : Int { + val x: Any? = "1" + return x as Int +} diff --git a/js/js.translator/testData/incremental/invalidation/exceptionsFromInlineFunction/lib1/l1.3.8.kt b/js/js.translator/testData/incremental/invalidation/exceptionsFromInlineFunction/lib1/l1.3.8.kt new file mode 100644 index 00000000000..41384d374ed --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/exceptionsFromInlineFunction/lib1/l1.3.8.kt @@ -0,0 +1,4 @@ +inline fun foo() : Int { + val x: Any? = null + return x!! as Int +} diff --git a/js/js.translator/testData/incremental/invalidation/exceptionsFromInlineFunction/lib1/l1.5.kt b/js/js.translator/testData/incremental/invalidation/exceptionsFromInlineFunction/lib1/l1.5.kt new file mode 100644 index 00000000000..580901fc5bc --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/exceptionsFromInlineFunction/lib1/l1.5.kt @@ -0,0 +1,4 @@ +inline fun foo() : Int { + throw NumberFormatException() + return 5 +} diff --git a/js/js.translator/testData/incremental/invalidation/exceptionsFromInlineFunction/lib1/l1.6.kt b/js/js.translator/testData/incremental/invalidation/exceptionsFromInlineFunction/lib1/l1.6.kt new file mode 100644 index 00000000000..31fd8ccd1bc --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/exceptionsFromInlineFunction/lib1/l1.6.kt @@ -0,0 +1 @@ +inline fun foo() = 6 diff --git a/js/js.translator/testData/incremental/invalidation/exceptionsFromInlineFunction/lib1/module.info b/js/js.translator/testData/incremental/invalidation/exceptionsFromInlineFunction/lib1/module.info new file mode 100644 index 00000000000..6da65c38389 --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/exceptionsFromInlineFunction/lib1/module.info @@ -0,0 +1,27 @@ +STEP 0: + modifications: + U : l1.0.kt -> l1.kt + added file: l1.kt +STEP 1: + modifications: + U : l1.1.kt -> l1.kt + modified ir: l1.kt +STEP 2: +STEP 3: + modifications: + U : l1.3.8.kt -> l1.kt + modified ir: l1.kt +STEP 4: +STEP 5: + modifications: + U : l1.5.kt -> l1.kt + modified ir: l1.kt +STEP 6: + modifications: + U : l1.6.kt -> l1.kt + modified ir: l1.kt +STEP 7: +STEP 8: + modifications: + U : l1.3.8.kt -> l1.kt + modified ir: l1.kt diff --git a/js/js.translator/testData/incremental/invalidation/exceptionsFromInlineFunction/lib2/l2.0.kt b/js/js.translator/testData/incremental/invalidation/exceptionsFromInlineFunction/lib2/l2.0.kt new file mode 100644 index 00000000000..a4edb54a3eb --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/exceptionsFromInlineFunction/lib2/l2.0.kt @@ -0,0 +1,3 @@ +fun qux(): Int { + return foo() +} diff --git a/js/js.translator/testData/incremental/invalidation/exceptionsFromInlineFunction/lib2/l2.2.kt b/js/js.translator/testData/incremental/invalidation/exceptionsFromInlineFunction/lib2/l2.2.kt new file mode 100644 index 00000000000..09b408068eb --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/exceptionsFromInlineFunction/lib2/l2.2.kt @@ -0,0 +1,7 @@ +fun qux(): Int { + try { + return foo() + } catch(ex: ClassCastException) { + return 2 + } +} diff --git a/js/js.translator/testData/incremental/invalidation/exceptionsFromInlineFunction/lib2/l2.4.kt b/js/js.translator/testData/incremental/invalidation/exceptionsFromInlineFunction/lib2/l2.4.kt new file mode 100644 index 00000000000..7e6aef794e3 --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/exceptionsFromInlineFunction/lib2/l2.4.kt @@ -0,0 +1,7 @@ +fun qux(): Int { + try { + return foo() + } catch(ex: NullPointerException) { + return 4 + } +} diff --git a/js/js.translator/testData/incremental/invalidation/exceptionsFromInlineFunction/lib2/l2.7.kt b/js/js.translator/testData/incremental/invalidation/exceptionsFromInlineFunction/lib2/l2.7.kt new file mode 100644 index 00000000000..28fc3030899 --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/exceptionsFromInlineFunction/lib2/l2.7.kt @@ -0,0 +1,3 @@ +fun qux(): Int { + return foo() + 1 +} diff --git a/js/js.translator/testData/incremental/invalidation/exceptionsFromInlineFunction/lib2/module.info b/js/js.translator/testData/incremental/invalidation/exceptionsFromInlineFunction/lib2/module.info new file mode 100644 index 00000000000..8517c97850b --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/exceptionsFromInlineFunction/lib2/module.info @@ -0,0 +1,32 @@ +STEP 0: + dependencies: lib1 + modifications: + U : l2.0.kt -> l2.kt + added file: l2.kt +STEP 1: + dependencies: lib1 + updated imports: l2.kt +STEP 2: + dependencies: lib1 + modifications: + U : l2.2.kt -> l2.kt + modified ir: l2.kt +STEP 3: + dependencies: lib1 + updated imports: l2.kt +STEP 4: + dependencies: lib1 + modifications: + U : l2.4.kt -> l2.kt + modified ir: l2.kt +STEP 5..6: + dependencies: lib1 + updated imports: l2.kt +STEP 7: + dependencies: lib1 + modifications: + U : l2.7.kt -> l2.kt + modified ir: l2.kt +STEP 8: + dependencies: lib1 + updated imports: l2.kt diff --git a/js/js.translator/testData/incremental/invalidation/exceptionsFromInlineFunction/main/m.kt b/js/js.translator/testData/incremental/invalidation/exceptionsFromInlineFunction/main/m.kt new file mode 100644 index 00000000000..568d1686a6f --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/exceptionsFromInlineFunction/main/m.kt @@ -0,0 +1,15 @@ +fun box(stepId: Int): String { + when (stepId) { + 0, 2, 4, 6, 7 -> if (qux() != stepId) return "Fail" + 1, 3, 5, 8 -> { + try { + val r = qux() + return "Fail, got $r" + } catch (e: Exception) { + } + } + + else -> return "Unknown" + } + return "OK" +} diff --git a/js/js.translator/testData/incremental/invalidation/exceptionsFromInlineFunction/main/module.info b/js/js.translator/testData/incremental/invalidation/exceptionsFromInlineFunction/main/module.info new file mode 100644 index 00000000000..2c1bc274a52 --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/exceptionsFromInlineFunction/main/module.info @@ -0,0 +1,5 @@ +STEP 0: + dependencies: lib1, lib2 + added file: m.kt +STEP 1..8: + dependencies: lib1, lib2 diff --git a/js/js.translator/testData/incremental/invalidation/exceptionsFromInlineFunction/project.info b/js/js.translator/testData/incremental/invalidation/exceptionsFromInlineFunction/project.info new file mode 100644 index 00000000000..405c78a7188 --- /dev/null +++ b/js/js.translator/testData/incremental/invalidation/exceptionsFromInlineFunction/project.info @@ -0,0 +1,26 @@ +MODULES: lib1, lib2, main + +STEP 0: + libs: lib1, lib2, main + dirty js: lib1, lib2, main +STEP 1: + libs: lib1, lib2, main + dirty js: lib1, lib2 +STEP 2: + libs: lib1, lib2, main + dirty js: lib1, lib2, main +STEP 3: + libs: lib1, lib2, main + dirty js: lib1, lib2 +STEP 4: + libs: lib1, lib2, main + dirty js: lib2, main +STEP 5..6: + libs: lib1, lib2, main + dirty js: lib1, lib2 +STEP 7: + libs: lib1, lib2, main + dirty js: lib2 +STEP 8: + libs: lib1, lib2, main + dirty js: lib1, lib2