From e4556ecc0d08cd1ad83281d2b1037ecce4c9037f Mon Sep 17 00:00:00 2001 From: Dmitriy Dolovov Date: Thu, 8 Sep 2022 17:59:40 +0200 Subject: [PATCH] [IR] User-friendly message about unexpected unlinked symbols ^KT-53649 --- .../kotlin/ir/backend/js/compiler.kt | 15 ++--- .../kotlin/ir/backend/js/compilerWithIC.kt | 10 ++-- .../kotlin/ir/backend/js/ic/CacheUpdater.kt | 12 ++-- .../ir/backend/js/ic/JsIrLinkerLoader.kt | 5 +- .../kotlin/backend/jvm/JvmIrCodegenFactory.kt | 8 ++- .../kotlin/backend/jvm/JvmIrSerializerImpl.kt | 4 +- .../jetbrains/kotlin/backend/wasm/compiler.kt | 12 ++-- .../kotlin/psi2ir/Psi2IrTranslator.kt | 13 +++-- .../kotlin/ir/util/IrMessageLogger.kt | 6 +- .../jetbrains/kotlin/ir/util/SymbolTable.kt | 7 --- .../common/serialization/KotlinIrLinker.kt | 8 +-- .../IrDeserializationExceptions.kt | 19 ------ .../linkerissues/KotlinIrLinkerIssues.kt | 52 +++++++++++++++-- .../serialization/linkerissues/checks.kt | 54 +++++++++++++++++ .../jetbrains/kotlin/ir/backend/js/klib.kt | 58 +++++++++---------- .../frontend/classic/ClassicFrontendFacade.kt | 8 +-- .../test/frontend/fir/FirFrontendFacade.kt | 5 +- .../kotlin/ir/AbstractIrGeneratorTestCase.kt | 7 ++- .../kotlin/klib/AbstractKlibTextTestCase.kt | 16 ++++- .../CompileKotlinAgainstCustomBinariesTest.kt | 4 +- .../kotlin/benchmarks/GenerateIrRuntime.kt | 8 ++- .../incremental/AbstractInvalidationTest.kt | 4 +- .../js/test/converters/JsIrBackendFacade.kt | 10 ++-- .../js/test/converters/JsKlibBackendFacade.kt | 6 +- .../jetbrains/kotlin/backend/konan/PsiToIr.kt | 9 ++- .../scripting/js/JsCoreScriptingCompiler.kt | 7 ++- .../js/JsScriptDependencyCompiler.kt | 7 +-- 27 files changed, 231 insertions(+), 143 deletions(-) create mode 100644 compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/linkerissues/checks.kt diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compiler.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compiler.kt index a2b9ae39865..a7f9f961b72 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compiler.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compiler.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.ir.backend.js import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig import org.jetbrains.kotlin.backend.common.phaser.invokeToplevel +import org.jetbrains.kotlin.backend.common.serialization.linkerissues.checkNoUnboundSymbols import org.jetbrains.kotlin.config.CompilerConfiguration import org.jetbrains.kotlin.ir.IrBuiltIns import org.jetbrains.kotlin.ir.backend.js.codegen.JsGenerationGranularity @@ -21,9 +22,7 @@ import org.jetbrains.kotlin.ir.declarations.IrFactory import org.jetbrains.kotlin.ir.declarations.IrModuleFragment import org.jetbrains.kotlin.ir.util.ExternalDependenciesGenerator import org.jetbrains.kotlin.ir.util.SymbolTable -import org.jetbrains.kotlin.ir.util.noUnboundLeft import org.jetbrains.kotlin.js.backend.ast.JsProgram -import org.jetbrains.kotlin.js.config.JSConfigurationKeys import org.jetbrains.kotlin.js.config.RuntimeDiagnostic import org.jetbrains.kotlin.name.FqName import java.io.File @@ -95,7 +94,7 @@ fun compileIr( moduleToName: Map, irBuiltIns: IrBuiltIns, symbolTable: SymbolTable, - deserializer: JsIrLinker, + irLinker: JsIrLinker, phaseConfig: PhaseConfig, exportedDeclarations: Set, dceRuntimeDiagnostic: RuntimeDiagnostic?, @@ -114,8 +113,6 @@ fun compileIr( is MainModule.Klib -> dependencyModules } - val allowUnboundSymbols = configuration[JSConfigurationKeys.PARTIAL_LINKAGE] ?: false - val context = JsIrBackendContext( moduleDescriptor, irBuiltIns, @@ -133,13 +130,11 @@ fun compileIr( ) // Load declarations referenced during `context` initialization - val irProviders = listOf(deserializer) + val irProviders = listOf(irLinker) ExternalDependenciesGenerator(symbolTable, irProviders).generateUnboundSymbolsAsDependencies() - deserializer.postProcess() - if (!allowUnboundSymbols) { - symbolTable.noUnboundLeft("Unbound symbols at the end of linker") - } + irLinker.postProcess() + irLinker.checkNoUnboundSymbols(symbolTable, "at the end of IR linkage process") allModules.forEach { module -> collectNativeImplementations(context, module) 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 b62b5516c41..4af9272cdd0 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,6 +7,7 @@ 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.lower.collectNativeImplementations @@ -17,7 +18,6 @@ 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.ir.util.noUnboundLeft import org.jetbrains.kotlin.js.config.RuntimeDiagnostic import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.psi2ir.descriptors.IrBuiltInsOverDescriptors @@ -27,7 +27,7 @@ import org.jetbrains.kotlin.psi2ir.descriptors.IrBuiltInsOverDescriptors fun compileWithIC( mainModule: IrModuleFragment, configuration: CompilerConfiguration, - deserializer: JsIrLinker, + irLinker: JsIrLinker, allModules: Collection, filesToLower: Collection, mainArguments: List? = null, @@ -63,11 +63,11 @@ fun compileWithIC( ) // Load declarations referenced during `context` initialization - val irProviders = listOf(deserializer) + val irProviders = listOf(irLinker) ExternalDependenciesGenerator(symbolTable, irProviders).generateUnboundSymbolsAsDependencies() - deserializer.postProcess() - symbolTable.noUnboundLeft("Unbound symbols at the end of linker") + irLinker.postProcess() + irLinker.checkNoUnboundSymbols(symbolTable, "at the end of IR linkage process") allModules.forEach { collectNativeImplementations(context, it) 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 1e9a531e3e2..7707fcc8540 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 @@ -26,7 +26,7 @@ fun interface CacheExecutor { fun execute( mainModule: IrModuleFragment, allModules: Collection, - deserializer: JsIrLinker, + irLinker: JsIrLinker, configuration: CompilerConfiguration, dirtyFiles: Collection, exportedDeclarations: Set, @@ -87,7 +87,7 @@ class CacheUpdater( val allResolvedDependencies = jsResolveLibraries( allModules, compilerConfiguration[JSConfigurationKeys.REPOSITORIES] ?: emptyList(), - compilerConfiguration[IrMessageLogger.IR_MESSAGE_LOGGER].toResolverLogger() + compilerConfiguration.resolverLogger ) return allResolvedDependencies.getFullList().associateBy { KotlinLibraryFile(it) } @@ -568,7 +568,7 @@ class CacheUpdater( val rebuiltFragments = executor.execute( mainModule = loadedIr.loadedFragments[mainLibraryFile] ?: notFoundIcError("main lib loaded fragment", mainLibraryFile), allModules = loadedIr.loadedFragments.values, - deserializer = loadedIr.linker, + irLinker = loadedIr.linker, configuration = compilerConfiguration, dirtyFiles = loadedIr.loadedFragments.flatMap { (libFile, libFragment) -> dirtyFileExports[libFile]?.let { libDirtyFiles -> @@ -617,7 +617,7 @@ fun rebuildCacheForDirtyFiles( return currentIrModule to buildCacheForModuleFiles( mainModule = currentIrModule, allModules = irModules.values, - deserializer = jsIrLinker, + irLinker = jsIrLinker, configuration = configuration, dirtyFiles = dirtyIrFiles, exportedDeclarations = exportedDeclarations, @@ -628,7 +628,7 @@ fun rebuildCacheForDirtyFiles( fun buildCacheForModuleFiles( mainModule: IrModuleFragment, allModules: Collection, - deserializer: JsIrLinker, + irLinker: JsIrLinker, configuration: CompilerConfiguration, dirtyFiles: Collection, exportedDeclarations: Set, @@ -639,7 +639,7 @@ fun buildCacheForModuleFiles( allModules = allModules, filesToLower = dirtyFiles, configuration = configuration, - deserializer = deserializer, + 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 d365deccc6d..053037c8c4a 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 @@ -19,8 +19,8 @@ import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsManglerDesc import org.jetbrains.kotlin.ir.declarations.IrFactory import org.jetbrains.kotlin.ir.declarations.IrModuleFragment import org.jetbrains.kotlin.ir.util.ExternalDependenciesGenerator -import org.jetbrains.kotlin.ir.util.IrMessageLogger import org.jetbrains.kotlin.ir.util.SymbolTable +import org.jetbrains.kotlin.ir.util.irMessageLogger import org.jetbrains.kotlin.library.KotlinLibrary import org.jetbrains.kotlin.library.unresolvedDependencies import org.jetbrains.kotlin.psi2ir.descriptors.IrBuiltInsOverDescriptors @@ -36,13 +36,12 @@ internal class JsIrLinkerLoader( ) { @OptIn(ObsoleteDescriptorBasedAPI::class) private fun createLinker(loadedModules: Map): JsIrLinker { - val logger = compilerConfiguration[IrMessageLogger.IR_MESSAGE_LOGGER] ?: IrMessageLogger.None val signaturer = IdSignatureDescriptor(JsManglerDesc) val symbolTable = SymbolTable(signaturer, irFactory) val moduleDescriptor = loadedModules.keys.last() val typeTranslator = TypeTranslatorImpl(symbolTable, compilerConfiguration.languageVersionSettings, moduleDescriptor) val irBuiltIns = IrBuiltInsOverDescriptors(moduleDescriptor.builtIns, typeTranslator, symbolTable) - return JsIrLinker(null, logger, irBuiltIns, symbolTable, null) + return JsIrLinker(null, compilerConfiguration.irMessageLogger, irBuiltIns, symbolTable, null) } private fun loadModules(): Map { diff --git a/compiler/ir/backend.jvm/entrypoint/src/org/jetbrains/kotlin/backend/jvm/JvmIrCodegenFactory.kt b/compiler/ir/backend.jvm/entrypoint/src/org/jetbrains/kotlin/backend/jvm/JvmIrCodegenFactory.kt index 4889cf2b306..fdcddca379b 100644 --- a/compiler/ir/backend.jvm/entrypoint/src/org/jetbrains/kotlin/backend/jvm/JvmIrCodegenFactory.kt +++ b/compiler/ir/backend.jvm/entrypoint/src/org/jetbrains/kotlin/backend/jvm/JvmIrCodegenFactory.kt @@ -12,6 +12,7 @@ import org.jetbrains.kotlin.backend.common.phaser.CompilerPhase import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig import org.jetbrains.kotlin.backend.common.phaser.invokeToplevel import org.jetbrains.kotlin.backend.common.serialization.DescriptorByIdSignatureFinderImpl +import org.jetbrains.kotlin.backend.common.serialization.linkerissues.checkNoUnboundSymbols import org.jetbrains.kotlin.backend.jvm.intrinsics.IrIntrinsicMethods import org.jetbrains.kotlin.backend.jvm.ir.getIoFile import org.jetbrains.kotlin.backend.jvm.ir.getKtFile @@ -113,15 +114,16 @@ open class JvmIrCodegenFactory( val symbolTable = SymbolTable(signaturer, IrFactoryImpl) mangler to symbolTable } + val messageLogger = input.configuration.irMessageLogger val psi2ir = Psi2IrTranslator( input.languageVersionSettings, Psi2IrConfiguration( input.ignoreErrors, allowUnboundSymbols = false, - input.skipBodies, - ) + input.skipBodies + ), + messageLogger::checkNoUnboundSymbols ) - val messageLogger = input.configuration[IrMessageLogger.IR_MESSAGE_LOGGER] ?: IrMessageLogger.None val psi2irContext = psi2ir.createGeneratorContext( input.module, input.bindingContext, diff --git a/compiler/ir/backend.jvm/entrypoint/src/org/jetbrains/kotlin/backend/jvm/JvmIrSerializerImpl.kt b/compiler/ir/backend.jvm/entrypoint/src/org/jetbrains/kotlin/backend/jvm/JvmIrSerializerImpl.kt index c3bb85d7c14..cfdc3c3dc31 100644 --- a/compiler/ir/backend.jvm/entrypoint/src/org/jetbrains/kotlin/backend/jvm/JvmIrSerializerImpl.kt +++ b/compiler/ir/backend.jvm/entrypoint/src/org/jetbrains/kotlin/backend/jvm/JvmIrSerializerImpl.kt @@ -14,7 +14,7 @@ import org.jetbrains.kotlin.config.JVMConfigurationKeys import org.jetbrains.kotlin.config.JvmSerializeIrMode import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrFile -import org.jetbrains.kotlin.ir.util.IrMessageLogger +import org.jetbrains.kotlin.ir.util.irMessageLogger import org.jetbrains.kotlin.name.FqName class JvmIrSerializerImpl(private val configuration: CompilerConfiguration) : JvmIrSerializer { @@ -34,7 +34,7 @@ class JvmIrSerializerImpl(private val configuration: CompilerConfiguration) : Jv private fun makeSerializerSession(fileClassFqName: FqName) = JvmIrSerializerSession( - configuration.get(IrMessageLogger.IR_MESSAGE_LOGGER) ?: IrMessageLogger.None, + configuration.irMessageLogger, declarationTable, mutableMapOf(), configuration.get(JVMConfigurationKeys.SERIALIZE_IR) ?: JvmSerializeIrMode.NONE, diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/compiler.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/compiler.kt index 386c7aa61f8..e1cd2076ed0 100644 --- a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/compiler.kt +++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/compiler.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.backend.wasm import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig import org.jetbrains.kotlin.backend.common.phaser.invokeToplevel +import org.jetbrains.kotlin.backend.common.serialization.linkerissues.checkNoUnboundSymbols import org.jetbrains.kotlin.backend.wasm.ir2wasm.WasmCompiledModuleFragment import org.jetbrains.kotlin.backend.wasm.ir2wasm.WasmModuleFragmentGenerator import org.jetbrains.kotlin.backend.wasm.lower.markExportedDeclarations @@ -16,7 +17,6 @@ import org.jetbrains.kotlin.ir.backend.js.loadIr import org.jetbrains.kotlin.ir.declarations.IrFactory import org.jetbrains.kotlin.ir.declarations.IrModuleFragment import org.jetbrains.kotlin.ir.util.ExternalDependenciesGenerator -import org.jetbrains.kotlin.ir.util.noUnboundLeft import org.jetbrains.kotlin.ir.util.patchDeclarationParents import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.wasm.ir.convertors.WasmIrToBinary @@ -35,7 +35,7 @@ fun compileToLoweredIr( ): Pair, WasmBackendContext> { val mainModule = depsDescriptors.mainModule val configuration = depsDescriptors.compilerConfiguration - val (moduleFragment, dependencyModules, irBuiltIns, symbolTable, deserializer) = loadIr( + val (moduleFragment, dependencyModules, irBuiltIns, symbolTable, irLinker) = loadIr( depsDescriptors, irFactory, verifySignatures = false, @@ -52,15 +52,15 @@ fun compileToLoweredIr( // Load declarations referenced during `context` initialization allModules.forEach { - ExternalDependenciesGenerator(symbolTable, listOf(deserializer)).generateUnboundSymbolsAsDependencies() + ExternalDependenciesGenerator(symbolTable, listOf(irLinker)).generateUnboundSymbolsAsDependencies() } // Create stubs - ExternalDependenciesGenerator(symbolTable, listOf(deserializer)).generateUnboundSymbolsAsDependencies() + ExternalDependenciesGenerator(symbolTable, listOf(irLinker)).generateUnboundSymbolsAsDependencies() allModules.forEach { it.patchDeclarationParents() } - deserializer.postProcess() - symbolTable.noUnboundLeft("Unbound symbols at the end of linker") + irLinker.postProcess() + irLinker.checkNoUnboundSymbols(symbolTable, "at the end of IR linkage process") for (module in allModules) for (file in module.files) diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/Psi2IrTranslator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/Psi2IrTranslator.kt index f2329f0d3d4..8a0e6ce5948 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/Psi2IrTranslator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/Psi2IrTranslator.kt @@ -24,7 +24,6 @@ import org.jetbrains.kotlin.ir.linkage.IrDeserializer import org.jetbrains.kotlin.ir.linkage.IrProvider import org.jetbrains.kotlin.ir.symbols.IrSymbol import org.jetbrains.kotlin.ir.util.SymbolTable -import org.jetbrains.kotlin.ir.util.noUnboundLeft import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi2ir.descriptors.IrBuiltInsOverDescriptors import org.jetbrains.kotlin.psi2ir.generators.GeneratorContext @@ -44,6 +43,7 @@ fun interface Psi2IrPostprocessingStep { class Psi2IrTranslator( val languageVersionSettings: LanguageVersionSettings, val configuration: Psi2IrConfiguration, + private val checkNoUnboundSymbols: (SymbolTable, String) -> Unit ) { private val postprocessingSteps = SmartList() @@ -80,6 +80,7 @@ class Psi2IrTranslator( expectDescriptorToSymbol: MutableMap? = null, fragmentInfo: EvaluatorFragmentInfo? = null ): IrModuleFragment { + val moduleGenerator = fragmentInfo?.let { FragmentModuleGenerator(context, it) } ?: ModuleGenerator(context, expectDescriptorToSymbol) @@ -92,9 +93,7 @@ class Psi2IrTranslator( moduleGenerator.generateUnboundSymbolsAsDependencies(irProviders) deserializers.forEach { it.postProcess() } - if (!context.configuration.allowUnboundSymbols) { - context.symbolTable.noUnboundLeft("Unbound symbols not allowed\n") - } + context.checkNoUnboundSymbols { "after generation of IR module ${irModule.name.asString()}" } postprocessingSteps.forEach { it.invoke(irModule) } // assert(context.symbolTable.allUnbound.isEmpty()) // TODO: fix IrPluginContext to make it not produce additional external reference @@ -102,7 +101,13 @@ class Psi2IrTranslator( // TODO: remove it once plugin API improved moduleGenerator.generateUnboundSymbolsAsDependencies(irProviders) deserializers.forEach { it.postProcess() } + context.checkNoUnboundSymbols { "after applying all post-processing steps for the generated IR module ${irModule.name.asString()}" } return irModule } + + private fun GeneratorContext.checkNoUnboundSymbols(whenDetected: () -> String) { + if (!configuration.allowUnboundSymbols) + checkNoUnboundSymbols(symbolTable, whenDetected()) + } } diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrMessageLogger.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrMessageLogger.kt index 9069a51c5d7..95ebb68b62b 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrMessageLogger.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrMessageLogger.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.ir.util +import org.jetbrains.kotlin.config.CompilerConfiguration import org.jetbrains.kotlin.config.CompilerConfigurationKey interface IrMessageLogger { @@ -25,4 +26,7 @@ interface IrMessageLogger { @JvmStatic val IR_MESSAGE_LOGGER = CompilerConfigurationKey("ir message logger") } -} \ No newline at end of file +} + +val CompilerConfiguration.irMessageLogger: IrMessageLogger + get() = this[IrMessageLogger.IR_MESSAGE_LOGGER] ?: IrMessageLogger.None diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/SymbolTable.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/SymbolTable.kt index 9fee1a7d199..66380f4ae41 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/SymbolTable.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/SymbolTable.kt @@ -1177,10 +1177,3 @@ val SymbolTable.allUnbound: Set addUnbound(unboundTypeAliases) addUnbound(unboundTypeParameters) } - -fun SymbolTable.noUnboundLeft(message: String) { - val unbound = this.allUnbound - assert(unbound.isEmpty()) { - message + "\n" + unbound.joinToString("\n") - } -} diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/KotlinIrLinker.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/KotlinIrLinker.kt index fcfa69c3972..b961877f040 100644 --- a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/KotlinIrLinker.kt +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/KotlinIrLinker.kt @@ -51,7 +51,7 @@ abstract class KotlinIrLinker( private lateinit var linkerExtensions: Collection - protected open val unlinkedDeclarationsSupport: UnlinkedDeclarationsSupport get() = UnlinkedDeclarationsSupport.DISABLED + open val unlinkedDeclarationsSupport: UnlinkedDeclarationsSupport get() = UnlinkedDeclarationsSupport.DISABLED protected open val userVisibleIrModulesSupport: UserVisibleIrModulesSupport get() = UserVisibleIrModulesSupport.DEFAULT fun deserializeOrReturnUnboundIrSymbolIfPartialLinkageEnabled( @@ -75,7 +75,7 @@ abstract class KotlinIrLinker( if (unlinkedDeclarationsSupport.allowUnboundSymbols) referenceDeserializedSymbol(symbolTable, null, symbolKind, idSignature) else - throw SignatureIdNotFoundInModuleWithDependencies( + SignatureIdNotFoundInModuleWithDependencies( idSignature = idSignature, problemModuleDeserializer = moduleDeserializer, allModuleDeserializers = deserializersForModules.values, @@ -86,7 +86,7 @@ abstract class KotlinIrLinker( fun resolveModuleDeserializer(module: ModuleDescriptor, idSignature: IdSignature?): IrModuleDeserializer { return deserializersForModules[module.name.asString()] - ?: throw NoDeserializerForModule(module.name, idSignature).raiseIssue(messageLogger) + ?: NoDeserializerForModule(module.name, idSignature).raiseIssue(messageLogger) } protected abstract fun createModuleDeserializer( @@ -165,7 +165,7 @@ abstract class KotlinIrLinker( ?: return null } catch (e: IrSymbolTypeMismatchException) { if (!unlinkedDeclarationsSupport.allowUnboundSymbols) { - throw SymbolTypeMismatch(e, deserializersForModules.values, userVisibleIrModulesSupport).raiseIssue(messageLogger) + SymbolTypeMismatch(e, deserializersForModules.values, userVisibleIrModulesSupport).raiseIssue(messageLogger) } } } diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/linkerissues/IrDeserializationExceptions.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/linkerissues/IrDeserializationExceptions.kt index 941f6e559e7..f979f14c008 100644 --- a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/linkerissues/IrDeserializationExceptions.kt +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/linkerissues/IrDeserializationExceptions.kt @@ -7,8 +7,6 @@ package org.jetbrains.kotlin.backend.common.serialization.linkerissues import org.jetbrains.kotlin.ir.declarations.IrAnnotationContainer import org.jetbrains.kotlin.ir.symbols.IrSymbol -import kotlin.contracts.ExperimentalContracts -import kotlin.contracts.contract sealed class IrDeserializationException(message: String) : Exception(message) { override val message: String get() = super.message!! @@ -22,20 +20,3 @@ class IrSymbolTypeMismatchException( class IrDisallowedErrorNode( clazz: Class ) : IrDeserializationException("${clazz::class.java.simpleName} found but error nodes are not allowed.") - -@OptIn(ExperimentalContracts::class) -internal inline fun checkSymbolType(symbol: IrSymbol): T { - contract { - returns() implies (symbol is T) - } - - if (symbol !is T) throw IrSymbolTypeMismatchException(T::class.java, symbol) else return symbol -} - -@OptIn(ExperimentalContracts::class) -internal inline fun checkErrorNodesAllowed(errorNodesAllowed: Boolean) { - contract { - returns() implies errorNodesAllowed - } - if (!errorNodesAllowed) throw IrDisallowedErrorNode(T::class.java) -} diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/linkerissues/KotlinIrLinkerIssues.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/linkerissues/KotlinIrLinkerIssues.kt index c30139d26d9..f2ef9a452e8 100644 --- a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/linkerissues/KotlinIrLinkerIssues.kt +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/linkerissues/KotlinIrLinkerIssues.kt @@ -5,11 +5,13 @@ package org.jetbrains.kotlin.backend.common.serialization.linkerissues +import org.jetbrains.kotlin.analyzer.CompilationErrorException import org.jetbrains.kotlin.backend.common.serialization.IrModuleDeserializer import org.jetbrains.kotlin.backend.common.serialization.linkerissues.PotentialConflictKind.* import org.jetbrains.kotlin.backend.common.serialization.linkerissues.PotentialConflictKind.Companion.mostSignificantConflictKind import org.jetbrains.kotlin.backend.common.serialization.linkerissues.PotentialConflictReason.Companion.mostSignificantConflictReasons import org.jetbrains.kotlin.ir.linkage.KotlinIrLinkerInternalException +import org.jetbrains.kotlin.ir.symbols.IrSymbol import org.jetbrains.kotlin.ir.util.IdSignature import org.jetbrains.kotlin.ir.util.IrMessageLogger import org.jetbrains.kotlin.name.Name @@ -18,12 +20,50 @@ import org.jetbrains.kotlin.utils.ResolvedDependencyId import org.jetbrains.kotlin.utils.ResolvedDependencyVersion import kotlin.Comparator -abstract class KotlinIrLinkerIssue { +/** + * TODO: Currently, [KotlinIrLinkerInternalException] is only needed to show the stacktrace to the user. + * If stacktrace is not needed it's enough to throw [CompilationErrorException] to interrupt the compilation process. + * But, probably, we don't even need to show the stacktrace, so we could probably get rid of [KotlinIrLinkerInternalException] at all. + */ +abstract class KotlinIrLinkerIssue(private val needStacktrace: Boolean) { protected abstract val errorMessage: String - fun raiseIssue(messageLogger: IrMessageLogger): KotlinIrLinkerInternalException { + fun raiseIssue(messageLogger: IrMessageLogger): Nothing { messageLogger.report(IrMessageLogger.Severity.ERROR, errorMessage, null) - throw KotlinIrLinkerInternalException() + throw if (needStacktrace) KotlinIrLinkerInternalException() else CompilationErrorException() + } +} + +class UnexpectedUnboundIrSymbols(unboundSymbols: Set, whenDetected: String) : KotlinIrLinkerIssue(needStacktrace = false) { + override val errorMessage = buildString { + // cause: + append("There ").append( + when (val count = unboundSymbols.size) { + 1 -> "is still an unbound symbol" + else -> "are still $count unbound symbols" + } + ).append(" ").append(whenDetected).append(":\n") + unboundSymbols.joinTo(this, separator = "\n") + + // explanation: + append("\n\nThis could happen if there are two libraries, where one library was compiled against the different version") + append(" of the other library than the one currently used in the project.") + + // action items: + append(" Please check that the project configuration is correct and has consistent versions of dependencies.") + if (unboundSymbols.any { looksLikeEnumEntries(it.signature) }) { + append("\n\nAnother possible reason is that some parts of the project are compiled with EnumEntries language feature enabled,") + append(" but other parts or used libraries are compiled with EnumEntries language feature disabled.") + } + } + + companion object { + fun looksLikeEnumEntries(signature: IdSignature?) : Boolean = when (signature) { + is IdSignature.AccessorSignature -> looksLikeEnumEntries(signature.propertySignature) + is IdSignature.CompositeSignature -> looksLikeEnumEntries(signature.inner) + is IdSignature.CommonSignature -> signature.shortName == "entries" + else -> false + } } } @@ -32,7 +72,7 @@ class SignatureIdNotFoundInModuleWithDependencies( private val problemModuleDeserializer: IrModuleDeserializer, private val allModuleDeserializers: Collection, private val userVisibleIrModulesSupport: UserVisibleIrModulesSupport -) : KotlinIrLinkerIssue() { +) : KotlinIrLinkerIssue(needStacktrace = false) { override val errorMessage = try { computeErrorMessage() } catch (e: Throwable) { @@ -89,7 +129,7 @@ class SignatureIdNotFoundInModuleWithDependencies( } } -class NoDeserializerForModule(moduleName: Name, idSignature: IdSignature?) : KotlinIrLinkerIssue() { +class NoDeserializerForModule(moduleName: Name, idSignature: IdSignature?) : KotlinIrLinkerIssue(needStacktrace = false) { override val errorMessage = buildString { append("Could not load module ${moduleName.asString()}") if (idSignature != null) append(" in an attempt to find deserializer for symbol ${idSignature.render()}.") @@ -100,7 +140,7 @@ class SymbolTypeMismatch( private val cause: IrSymbolTypeMismatchException, private val allModuleDeserializers: Collection, private val userVisibleIrModulesSupport: UserVisibleIrModulesSupport -) : KotlinIrLinkerIssue() { +) : KotlinIrLinkerIssue(needStacktrace = true) { override val errorMessage = try { computeErrorMessage() } catch (e: Throwable) { diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/linkerissues/checks.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/linkerissues/checks.kt new file mode 100644 index 00000000000..13b97900fae --- /dev/null +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/linkerissues/checks.kt @@ -0,0 +1,54 @@ +/* + * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.backend.common.serialization.linkerissues + +import org.jetbrains.kotlin.backend.common.serialization.KotlinIrLinker +import org.jetbrains.kotlin.config.CompilerConfiguration +import org.jetbrains.kotlin.ir.declarations.IrAnnotationContainer +import org.jetbrains.kotlin.ir.symbols.IrSymbol +import org.jetbrains.kotlin.ir.util.IrMessageLogger +import org.jetbrains.kotlin.ir.util.SymbolTable +import org.jetbrains.kotlin.ir.util.allUnbound +import org.jetbrains.kotlin.ir.util.irMessageLogger +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.contract + +@OptIn(ExperimentalContracts::class) +internal inline fun checkSymbolType(symbol: IrSymbol): T { + contract { + returns() implies (symbol is T) + } + + if (symbol !is T) throw IrSymbolTypeMismatchException(T::class.java, symbol) else return symbol +} + +@OptIn(ExperimentalContracts::class) +internal inline fun checkErrorNodesAllowed(errorNodesAllowed: Boolean) { + contract { + returns() implies errorNodesAllowed + } + if (!errorNodesAllowed) throw IrDisallowedErrorNode(T::class.java) +} + +// N.B. Checks for absence of unbound symbols only when unbound symbols are not allowed. +fun KotlinIrLinker.checkNoUnboundSymbols(symbolTable: SymbolTable, whenDetected: String) { + if (!unlinkedDeclarationsSupport.allowUnboundSymbols) + messageLogger.checkNoUnboundSymbols(symbolTable, whenDetected) +} + +// N.B. Always checks for absence of unbound symbols. The condition whether this check should be applied is controlled outside. +fun IrMessageLogger.checkNoUnboundSymbols(symbolTable: SymbolTable, whenDetected: String) { + val unboundSymbols = symbolTable.allUnbound + if (unboundSymbols.isNotEmpty()) + UnexpectedUnboundIrSymbols(unboundSymbols, whenDetected).raiseIssue(this) +} + +// N.B. Always checks for absence of unbound symbols. The condition whether this check should be applied is controlled outside. +fun CompilerConfiguration.checkNoUnboundSymbols(symbolTable: SymbolTable, whenDetected: String) { + val unboundSymbols = symbolTable.allUnbound + if (unboundSymbols.isNotEmpty()) + UnexpectedUnboundIrSymbols(unboundSymbols, whenDetected).raiseIssue(irMessageLogger) +} diff --git a/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/klib.kt b/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/klib.kt index 0e73def67cc..5e8a95a2a67 100644 --- a/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/klib.kt +++ b/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/klib.kt @@ -16,6 +16,7 @@ import org.jetbrains.kotlin.backend.common.extensions.IrPluginContextImpl import org.jetbrains.kotlin.backend.common.lower.ExpectDeclarationRemover import org.jetbrains.kotlin.backend.common.overrides.FakeOverrideChecker import org.jetbrains.kotlin.backend.common.serialization.* +import org.jetbrains.kotlin.backend.common.serialization.linkerissues.checkNoUnboundSymbols import org.jetbrains.kotlin.backend.common.serialization.mangle.ManglerChecker import org.jetbrains.kotlin.backend.common.serialization.mangle.descriptor.Ir2DescriptorManglerAdapter import org.jetbrains.kotlin.backend.common.serialization.metadata.DynamicTypeDeserializer @@ -84,30 +85,22 @@ private val CompilerConfiguration.metadataVersion private val CompilerConfiguration.expectActualLinker: Boolean get() = get(CommonConfigurationKeys.EXPECT_ACTUAL_LINKER) ?: false -class KotlinFileSerializedData(val metadata: ByteArray, val irData: SerializedIrFile) +val CompilerConfiguration.resolverLogger: Logger + get() = when (val messageLogger = this[IrMessageLogger.IR_MESSAGE_LOGGER]) { + null -> DummyLogger + else -> object : Logger { + override fun log(message: String) = messageLogger.report(IrMessageLogger.Severity.INFO, message, null) + override fun error(message: String) = messageLogger.report(IrMessageLogger.Severity.ERROR, message, null) + override fun warning(message: String) = messageLogger.report(IrMessageLogger.Severity.WARNING, message, null) -fun IrMessageLogger?.toResolverLogger(): Logger { - if (this == null) return DummyLogger - - return object : Logger { - override fun log(message: String) { - report(IrMessageLogger.Severity.INFO, message, null) - } - - override fun error(message: String) { - report(IrMessageLogger.Severity.ERROR, message, null) - } - - override fun warning(message: String) { - report(IrMessageLogger.Severity.WARNING, message, null) - } - - override fun fatal(message: String): Nothing { - report(IrMessageLogger.Severity.ERROR, message, null) - kotlin.error("FATAL ERROR: $message") + override fun fatal(message: String): Nothing { + messageLogger.report(IrMessageLogger.Severity.ERROR, message, null) + kotlin.error("FATAL ERROR: $message") + } } } -} + +class KotlinFileSerializedData(val metadata: ByteArray, val irData: SerializedIrFile) fun generateIrForKlibSerialization( project: Project, @@ -123,7 +116,7 @@ fun generateIrForKlibSerialization( ): IrModuleFragment { val incrementalDataProvider = configuration.get(JSConfigurationKeys.INCREMENTAL_DATA_PROVIDER) val errorPolicy = configuration.get(JSConfigurationKeys.ERROR_TOLERANCE_POLICY) ?: ErrorTolerancePolicy.DEFAULT - val messageLogger = configuration.get(IrMessageLogger.IR_MESSAGE_LOGGER) ?: IrMessageLogger.None + val messageLogger = configuration.irMessageLogger val allowUnboundSymbols = configuration[JSConfigurationKeys.PARTIAL_LINKAGE] ?: false val serializedIrFiles = mutableListOf() @@ -153,7 +146,11 @@ fun generateIrForKlibSerialization( } val symbolTable = SymbolTable(IdSignatureDescriptor(JsManglerDesc), irFactory) - val psi2Ir = Psi2IrTranslator(configuration.languageVersionSettings, Psi2IrConfiguration(errorPolicy.allowErrors, allowUnboundSymbols)) + val psi2Ir = Psi2IrTranslator( + configuration.languageVersionSettings, + Psi2IrConfiguration(errorPolicy.allowErrors, allowUnboundSymbols), + messageLogger::checkNoUnboundSymbols + ) val psi2IrContext = psi2Ir.createGeneratorContext(analysisResult.moduleDescriptor, analysisResult.bindingContext, symbolTable) val irBuiltIns = psi2IrContext.irBuiltIns @@ -215,7 +212,7 @@ fun generateKLib( val files = (depsDescriptors.mainModule as MainModule.SourceFiles).files val configuration = depsDescriptors.compilerConfiguration val allDependencies = depsDescriptors.allDependencies.map { it.library } - val messageLogger = configuration.get(IrMessageLogger.IR_MESSAGE_LOGGER) ?: IrMessageLogger.None + val messageLogger = configuration.irMessageLogger val icData = mutableListOf() val expectDescriptorToSymbol = mutableMapOf() @@ -311,7 +308,7 @@ fun loadIr( val configuration = depsDescriptors.compilerConfiguration val allDependencies = depsDescriptors.allDependencies.map { it.library } val errorPolicy = configuration.get(JSConfigurationKeys.ERROR_TOLERANCE_POLICY) ?: ErrorTolerancePolicy.DEFAULT - val messageLogger = configuration.get(IrMessageLogger.IR_MESSAGE_LOGGER) ?: IrMessageLogger.None + val messageLogger = configuration.irMessageLogger val allowUnboundSymbol = configuration[JSConfigurationKeys.PARTIAL_LINKAGE] ?: false val signaturer = IdSignatureDescriptor(JsManglerDesc) @@ -459,9 +456,6 @@ fun getIrModuleInfoForSourceFiles( ) val moduleFragment = psi2IrContext.generateModuleFragmentWithPlugins(project, files, irLinker, messageLogger) - if (!allowUnboundSymbols) { - symbolTable.noUnboundLeft("Unbound symbols left after linker") - } // TODO: not sure whether this check should be enabled by default. Add configuration key for it. val mangleChecker = ManglerChecker(JsManglerIr, Ir2DescriptorManglerAdapter(JsManglerDesc)) @@ -513,7 +507,8 @@ private fun preparePsi2Ir( val analysisResult = depsDescriptors.jsFrontEndResult val psi2Ir = Psi2IrTranslator( depsDescriptors.compilerConfiguration.languageVersionSettings, - Psi2IrConfiguration(errorIgnorancePolicy.allowErrors, allowUnboundSymbols) + Psi2IrConfiguration(errorIgnorancePolicy.allowErrors, allowUnboundSymbols), + depsDescriptors.compilerConfiguration::checkNoUnboundSymbols ) return psi2Ir.createGeneratorContext( analysisResult.moduleDescriptor, @@ -530,8 +525,7 @@ fun GeneratorContext.generateModuleFragmentWithPlugins( expectDescriptorToSymbol: MutableMap? = null, stubGenerator: DeclarationStubGenerator? = null ): IrModuleFragment { - val psi2Ir = Psi2IrTranslator(languageVersionSettings, configuration) - + val psi2Ir = Psi2IrTranslator(languageVersionSettings, configuration, messageLogger::checkNoUnboundSymbols) val extensions = IrGenerationExtension.getInstances(project) if (extensions.isNotEmpty()) { @@ -606,7 +600,7 @@ class ModulesStructure( val allResolvedDependencies = jsResolveLibraries( dependencies, compilerConfiguration[JSConfigurationKeys.REPOSITORIES] ?: emptyList(), - compilerConfiguration[IrMessageLogger.IR_MESSAGE_LOGGER].toResolverLogger() + compilerConfiguration.resolverLogger ) val allDependencies = allResolvedDependencies.getFullResolvedList() diff --git a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/classic/ClassicFrontendFacade.kt b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/classic/ClassicFrontendFacade.kt index 448b384b525..9d6d385031f 100644 --- a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/classic/ClassicFrontendFacade.kt +++ b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/classic/ClassicFrontendFacade.kt @@ -34,11 +34,7 @@ import org.jetbrains.kotlin.incremental.components.EnumWhenTracker import org.jetbrains.kotlin.incremental.components.ExpectActualTracker import org.jetbrains.kotlin.incremental.components.InlineConstTracker import org.jetbrains.kotlin.incremental.components.LookupTracker -import org.jetbrains.kotlin.ir.backend.js.JsFactories -import org.jetbrains.kotlin.ir.backend.js.TopDownAnalyzerFacadeForJSIR -import org.jetbrains.kotlin.ir.backend.js.jsResolveLibraries -import org.jetbrains.kotlin.ir.backend.js.toResolverLogger -import org.jetbrains.kotlin.ir.util.IrMessageLogger +import org.jetbrains.kotlin.ir.backend.js.* import org.jetbrains.kotlin.js.analyze.TopDownAnalyzerFacadeForJS import org.jetbrains.kotlin.js.config.JSConfigurationKeys import org.jetbrains.kotlin.library.unresolvedDependencies @@ -258,7 +254,7 @@ class ClassicFrontendFacade( val resolvedLibraries = jsResolveLibraries( names, configuration[JSConfigurationKeys.REPOSITORIES] ?: emptyList(), - configuration[IrMessageLogger.IR_MESSAGE_LOGGER].toResolverLogger() + configuration.resolverLogger ).getFullResolvedList() var builtInsModule: KotlinBuiltIns? = null diff --git a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/FirFrontendFacade.kt b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/FirFrontendFacade.kt index 1375f68f918..e1d238af36a 100644 --- a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/FirFrontendFacade.kt +++ b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/FirFrontendFacade.kt @@ -26,8 +26,7 @@ import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrar import org.jetbrains.kotlin.fir.session.FirSessionConfigurator import org.jetbrains.kotlin.fir.session.FirSessionFactory import org.jetbrains.kotlin.ir.backend.js.jsResolveLibraries -import org.jetbrains.kotlin.ir.backend.js.toResolverLogger -import org.jetbrains.kotlin.ir.util.IrMessageLogger +import org.jetbrains.kotlin.ir.backend.js.resolverLogger import org.jetbrains.kotlin.js.config.JSConfigurationKeys import org.jetbrains.kotlin.js.resolve.JsPlatformAnalyzerServices import org.jetbrains.kotlin.library.resolver.KotlinResolvedLibrary @@ -262,7 +261,7 @@ fun resolveJsLibraries( ): List { val paths = getAllJsDependenciesPaths(module, testServices) val repositories = configuration[JSConfigurationKeys.REPOSITORIES] ?: emptyList() - val logger = configuration[IrMessageLogger.IR_MESSAGE_LOGGER].toResolverLogger() + val logger = configuration.resolverLogger return jsResolveLibraries(paths, repositories, logger).getFullResolvedList() } diff --git a/compiler/tests-common/tests/org/jetbrains/kotlin/ir/AbstractIrGeneratorTestCase.kt b/compiler/tests-common/tests/org/jetbrains/kotlin/ir/AbstractIrGeneratorTestCase.kt index 7fe98219924..299e6a0707d 100644 --- a/compiler/tests-common/tests/org/jetbrains/kotlin/ir/AbstractIrGeneratorTestCase.kt +++ b/compiler/tests-common/tests/org/jetbrains/kotlin/ir/AbstractIrGeneratorTestCase.kt @@ -18,6 +18,7 @@ package org.jetbrains.kotlin.ir import org.jetbrains.kotlin.analyzer.AnalysisResult import org.jetbrains.kotlin.backend.common.serialization.DescriptorByIdSignatureFinderImpl +import org.jetbrains.kotlin.backend.common.serialization.linkerissues.checkNoUnboundSymbols import org.jetbrains.kotlin.backend.common.serialization.signature.IdSignatureDescriptor import org.jetbrains.kotlin.backend.jvm.JvmGeneratorExtensionsImpl import org.jetbrains.kotlin.backend.jvm.serialization.JvmIdSignatureDescriptor @@ -96,7 +97,11 @@ abstract class AbstractIrGeneratorTestCase : CodegenTestCase() { protected open fun generateIrModule(ignoreErrors: Boolean = false): IrModuleFragment { assert(myFiles != null) { "myFiles not initialized" } assert(myEnvironment != null) { "myEnvironment not initialized" } - val psi2Ir = Psi2IrTranslator(myEnvironment.configuration.languageVersionSettings, Psi2IrConfiguration(ignoreErrors)) + val psi2Ir = Psi2IrTranslator( + myEnvironment.configuration.languageVersionSettings, + Psi2IrConfiguration(ignoreErrors), + myEnvironment.configuration::checkNoUnboundSymbols + ) return doGenerateIrModule(psi2Ir) } diff --git a/compiler/tests-common/tests/org/jetbrains/kotlin/klib/AbstractKlibTextTestCase.kt b/compiler/tests-common/tests/org/jetbrains/kotlin/klib/AbstractKlibTextTestCase.kt index 26c682c36c4..e4056a8cd8b 100644 --- a/compiler/tests-common/tests/org/jetbrains/kotlin/klib/AbstractKlibTextTestCase.kt +++ b/compiler/tests-common/tests/org/jetbrains/kotlin/klib/AbstractKlibTextTestCase.kt @@ -11,6 +11,7 @@ import junit.framework.TestCase import org.jetbrains.kotlin.backend.common.serialization.CompatibilityMode import org.jetbrains.kotlin.backend.common.serialization.DeserializationStrategy import org.jetbrains.kotlin.backend.common.serialization.KlibIrVersion +import org.jetbrains.kotlin.backend.common.serialization.linkerissues.checkNoUnboundSymbols import org.jetbrains.kotlin.backend.common.serialization.metadata.KlibMetadataIncrementalSerializer import org.jetbrains.kotlin.backend.common.serialization.metadata.KlibMetadataVersion import org.jetbrains.kotlin.backend.common.serialization.signature.IdSignatureDescriptor @@ -257,12 +258,21 @@ abstract class AbstractKlibTextTestCase : CodegenTestCase() { return md } - private fun generateIrModule(stdlib: KotlinLibrary, ignoreErrors: Boolean, expectActualSymbols: MutableMap): Pair { + private fun generateIrModule( + stdlib: KotlinLibrary, + ignoreErrors: Boolean, + expectActualSymbols: MutableMap + ): Pair { val stdlibDescriptor = getModuleDescriptor(stdlib) val ktFiles = myFiles.psiFiles - val psi2Ir = Psi2IrTranslator(myEnvironment.configuration.languageVersionSettings, Psi2IrConfiguration(ignoreErrors)) + val messageLogger = IrMessageLogger.None + val psi2Ir = Psi2IrTranslator( + myEnvironment.configuration.languageVersionSettings, + Psi2IrConfiguration(ignoreErrors), + myEnvironment.configuration::checkNoUnboundSymbols + ) val analysisResult = TopDownAnalyzerFacadeForJS.analyzeFiles( ktFiles, myEnvironment.project, myEnvironment.configuration, moduleDescriptors = listOf(stdlibDescriptor), @@ -280,7 +290,7 @@ abstract class AbstractKlibTextTestCase : CodegenTestCase() { val symbolTable = SymbolTable(IdSignatureDescriptor(JsManglerDesc), IrFactoryImpl, NameProvider.DEFAULT) val context = psi2Ir.createGeneratorContext(moduleDescriptor, bindingContext, symbolTable) val irBuiltIns = context.irBuiltIns - val irLinker = JsIrLinker(moduleDescriptor, IrMessageLogger.None, irBuiltIns, symbolTable, null) + val irLinker = JsIrLinker(moduleDescriptor, messageLogger, irBuiltIns, symbolTable, null) irLinker.deserializeIrModuleHeader(stdlibDescriptor, stdlib) return psi2Ir.generateModuleFragment(context, ktFiles, listOf(irLinker), emptyList(), expectActualSymbols) to bindingContext diff --git a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstCustomBinariesTest.kt b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstCustomBinariesTest.kt index b5613575d60..f64267a1d40 100644 --- a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstCustomBinariesTest.kt +++ b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstCustomBinariesTest.kt @@ -692,12 +692,12 @@ class CompileKotlinAgainstCustomBinariesTest : AbstractKotlinCompilerIntegration fun testUnreachableExtensionVarPropertyDeclaration() { val (output, exitCode) = compileKotlin("source.kt", tmpdir, expectedFileName = null) - assertEquals("Output:\n$output", ExitCode.INTERNAL_ERROR, exitCode) + assertEquals("Output:\n$output", ExitCode.COMPILATION_ERROR, exitCode) } fun testUnreachableExtensionValPropertyDeclaration() { val (output, exitCode) = compileKotlin("source.kt", tmpdir, expectedFileName = null) - assertEquals("Output:\n$output", ExitCode.INTERNAL_ERROR, exitCode) + assertEquals("Output:\n$output", ExitCode.COMPILATION_ERROR, exitCode) } fun testAnonymousObjectTypeMetadata() { diff --git a/js/js.tests/test/org/jetbrains/kotlin/benchmarks/GenerateIrRuntime.kt b/js/js.tests/test/org/jetbrains/kotlin/benchmarks/GenerateIrRuntime.kt index a806068951c..94cee37f452 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/benchmarks/GenerateIrRuntime.kt +++ b/js/js.tests/test/org/jetbrains/kotlin/benchmarks/GenerateIrRuntime.kt @@ -16,6 +16,7 @@ import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig import org.jetbrains.kotlin.backend.common.phaser.invokeToplevel import org.jetbrains.kotlin.backend.common.serialization.CompatibilityMode import org.jetbrains.kotlin.backend.common.serialization.KlibIrVersion +import org.jetbrains.kotlin.backend.common.serialization.linkerissues.checkNoUnboundSymbols import org.jetbrains.kotlin.backend.common.serialization.metadata.KlibMetadataVersion import org.jetbrains.kotlin.backend.common.serialization.signature.IdSignatureDescriptor import org.jetbrains.kotlin.build.report.DoNothingBuildReporter @@ -462,13 +463,14 @@ class GenerateIrRuntime { } private fun doPsi2Ir(files: List, analysisResult: AnalysisResult): IrModuleFragment { - val psi2Ir = Psi2IrTranslator(languageVersionSettings, Psi2IrConfiguration()) + val messageLogger = IrMessageLogger.None + val psi2Ir = Psi2IrTranslator(languageVersionSettings, Psi2IrConfiguration(), messageLogger::checkNoUnboundSymbols) val symbolTable = SymbolTable(IdSignatureDescriptor(JsManglerDesc), IrFactoryImpl) val psi2IrContext = psi2Ir.createGeneratorContext(analysisResult.moduleDescriptor, analysisResult.bindingContext, symbolTable) val irLinker = JsIrLinker( psi2IrContext.moduleDescriptor, - IrMessageLogger.None, + messageLogger, psi2IrContext.irBuiltIns, psi2IrContext.symbolTable, null @@ -476,7 +478,7 @@ class GenerateIrRuntime { val irProviders = listOf(irLinker) - val psi2IrTranslator = Psi2IrTranslator(languageVersionSettings, psi2IrContext.configuration) + val psi2IrTranslator = Psi2IrTranslator(languageVersionSettings, psi2IrContext.configuration, messageLogger::checkNoUnboundSymbols) return psi2IrTranslator.generateModuleFragment(psi2IrContext, files, irProviders, emptyList(), null) } 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 1e2b2569613..dd4b585082b 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/incremental/AbstractInvalidationTest.kt +++ b/js/js.tests/test/org/jetbrains/kotlin/incremental/AbstractInvalidationTest.kt @@ -213,7 +213,7 @@ abstract class AbstractInvalidationTest : KotlinTestWithEnvironment() { fun executorWithBoxExport( currentModule: IrModuleFragment, allModules: Collection, - deserializer: JsIrLinker, + irLinker: JsIrLinker, configuration: CompilerConfiguration, dirtyFiles: Collection, exportedDeclarations: Set, @@ -222,7 +222,7 @@ abstract class AbstractInvalidationTest : KotlinTestWithEnvironment() { return buildCacheForModuleFiles( mainModule = currentModule, allModules = allModules, - deserializer = deserializer, + irLinker = irLinker, configuration = configuration, dirtyFiles = dirtyFiles, exportedDeclarations = exportedDeclarations + FqName(BOX_FUNCTION_NAME), diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/converters/JsIrBackendFacade.kt b/js/js.tests/test/org/jetbrains/kotlin/js/test/converters/JsIrBackendFacade.kt index a868ae4ec19..c642ae6bbe5 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/converters/JsIrBackendFacade.kt +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/converters/JsIrBackendFacade.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.js.test.converters import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig import org.jetbrains.kotlin.backend.common.phaser.toPhaseMap +import org.jetbrains.kotlin.backend.common.serialization.linkerissues.checkNoUnboundSymbols import org.jetbrains.kotlin.backend.common.serialization.signature.IdSignatureDescriptor import org.jetbrains.kotlin.config.CommonConfigurationKeys import org.jetbrains.kotlin.config.CompilerConfiguration @@ -24,8 +25,8 @@ import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.IrModuleToJsTransf import org.jetbrains.kotlin.ir.backend.js.SourceMapsInfo import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.TranslationMode import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImplForJsIC -import org.jetbrains.kotlin.ir.util.IrMessageLogger import org.jetbrains.kotlin.ir.util.SymbolTable +import org.jetbrains.kotlin.ir.util.irMessageLogger import org.jetbrains.kotlin.js.config.ErrorTolerancePolicy import org.jetbrains.kotlin.js.config.JSConfigurationKeys import org.jetbrains.kotlin.js.test.handlers.JsBoxRunner.Companion.TEST_FUNCTION @@ -212,7 +213,7 @@ class JsIrBackendFacade( private fun loadIrFromKlib(module: TestModule, configuration: CompilerConfiguration): IrModuleInfo { val filesToLoad = module.files.takeIf { !firstTimeCompilation }?.map { "/${it.relativePath}" }?.toSet() - val messageLogger = configuration.get(IrMessageLogger.IR_MESSAGE_LOGGER) ?: IrMessageLogger.None + val messageLogger = configuration.irMessageLogger val symbolTable = SymbolTable(IdSignatureDescriptor(JsManglerDesc), IrFactoryImplForJsIC(WholeWorldStageController()),) val moduleDescriptor = testServices.moduleDescriptorProvider.getModuleDescriptor(module) @@ -239,13 +240,14 @@ class JsIrBackendFacade( inputArtifact: ClassicFrontendOutputArtifact ): IrModuleInfo { val errorPolicy = configuration.get(JSConfigurationKeys.ERROR_TOLERANCE_POLICY) ?: ErrorTolerancePolicy.DEFAULT - val messageLogger = configuration.get(IrMessageLogger.IR_MESSAGE_LOGGER) ?: IrMessageLogger.None + val messageLogger = configuration.irMessageLogger val symbolTable = SymbolTable(IdSignatureDescriptor(JsManglerDesc), IrFactoryImplForJsIC(WholeWorldStageController()),) val verifySignatures = JsEnvironmentConfigurationDirectives.SKIP_MANGLE_VERIFICATION !in module.directives val psi2Ir = Psi2IrTranslator( configuration.languageVersionSettings, - Psi2IrConfiguration(errorPolicy.allowErrors) + Psi2IrConfiguration(errorPolicy.allowErrors), + messageLogger::checkNoUnboundSymbols ) val psi2IrContext = psi2Ir.createGeneratorContext( inputArtifact.analysisResult.moduleDescriptor, diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/converters/JsKlibBackendFacade.kt b/js/js.tests/test/org/jetbrains/kotlin/js/test/converters/JsKlibBackendFacade.kt index 68f99ea8f6c..b76d394bfdb 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/converters/JsKlibBackendFacade.kt +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/converters/JsKlibBackendFacade.kt @@ -9,7 +9,7 @@ import org.jetbrains.kotlin.config.CommonConfigurationKeys import org.jetbrains.kotlin.config.languageVersionSettings import org.jetbrains.kotlin.incremental.components.LookupTracker import org.jetbrains.kotlin.ir.backend.js.* -import org.jetbrains.kotlin.ir.util.IrMessageLogger +import org.jetbrains.kotlin.ir.util.irMessageLogger import org.jetbrains.kotlin.js.config.ErrorTolerancePolicy import org.jetbrains.kotlin.js.config.JSConfigurationKeys import org.jetbrains.kotlin.js.test.utils.JsIrIncrementalDataProvider @@ -56,7 +56,7 @@ class JsKlibBackendFacade( configuration[CommonConfigurationKeys.MODULE_NAME]!!, project, configuration, - configuration.get(IrMessageLogger.IR_MESSAGE_LOGGER) ?: IrMessageLogger.None, + configuration.irMessageLogger, inputArtifact.bindingContext, inputArtifact.sourceFiles, klibPath = outputFile, @@ -76,7 +76,7 @@ class JsKlibBackendFacade( val lib = jsResolveLibraries( dependencies.map { testServices.jsLibraryProvider.getPathByDescriptor(it) } + listOf(outputFile), configuration[JSConfigurationKeys.REPOSITORIES] ?: emptyList(), - configuration[IrMessageLogger.IR_MESSAGE_LOGGER].toResolverLogger() + configuration.resolverLogger ).getFullResolvedList().last().library val moduleDescriptor = JsFactories.DefaultDeserializedDescriptorFactory.createDescriptorOptionalBuiltIns( diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/PsiToIr.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/PsiToIr.kt index 8a736cb016b..3802ce2dada 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/PsiToIr.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/PsiToIr.kt @@ -4,6 +4,7 @@ import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension import org.jetbrains.kotlin.backend.common.extensions.IrPluginContextImpl import org.jetbrains.kotlin.backend.common.overrides.FakeOverrideChecker import org.jetbrains.kotlin.backend.common.serialization.DescriptorByIdSignatureFinderImpl +import org.jetbrains.kotlin.backend.common.serialization.linkerissues.checkNoUnboundSymbols import org.jetbrains.kotlin.backend.common.serialization.mangle.ManglerChecker import org.jetbrains.kotlin.backend.common.serialization.mangle.descriptor.Ir2DescriptorManglerAdapter import org.jetbrains.kotlin.backend.konan.descriptors.isForwardDeclarationModule @@ -52,7 +53,11 @@ internal fun Context.psiToIr( val allowUnboundSymbols = config.configuration[KonanConfigKeys.PARTIAL_LINKAGE] ?: false - val translator = Psi2IrTranslator(config.configuration.languageVersionSettings, Psi2IrConfiguration(ignoreErrors = false, allowUnboundSymbols = allowUnboundSymbols)) + val translator = Psi2IrTranslator( + config.configuration.languageVersionSettings, + Psi2IrConfiguration(ignoreErrors = false, allowUnboundSymbols = allowUnboundSymbols), + messageLogger::checkNoUnboundSymbols + ) val generatorContext = translator.createGeneratorContext(moduleDescriptor, bindingContext, symbolTable) val pluginExtensions = IrGenerationExtension.getInstances(config.project) @@ -211,7 +216,7 @@ internal fun Context.psiToIr( // Enable lazy IR genration for newly-created symbols inside BE stubGenerator.unboundSymbolGeneration = true - symbolTable.noUnboundLeft("Unbound symbols left after linker") + messageLogger.checkNoUnboundSymbols(symbolTable, "at the end of IR linkage process") mainModule.acceptVoid(ManglerChecker(KonanManglerIr, Ir2DescriptorManglerAdapter(KonanManglerDesc))) diff --git a/plugins/scripting/scripting-compiler-js/src/org/jetbrains/kotlin/scripting/js/JsCoreScriptingCompiler.kt b/plugins/scripting/scripting-compiler-js/src/org/jetbrains/kotlin/scripting/js/JsCoreScriptingCompiler.kt index 7db95693a25..08521f2c826 100644 --- a/plugins/scripting/scripting-compiler-js/src/org/jetbrains/kotlin/scripting/js/JsCoreScriptingCompiler.kt +++ b/plugins/scripting/scripting-compiler-js/src/org/jetbrains/kotlin/scripting/js/JsCoreScriptingCompiler.kt @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.scripting.js import org.jetbrains.kotlin.backend.common.serialization.DescriptorByIdSignatureFinderImpl +import org.jetbrains.kotlin.backend.common.serialization.linkerissues.checkNoUnboundSymbols import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys import org.jetbrains.kotlin.cli.common.environment.setIdeaIoUseFallback import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport @@ -67,7 +68,11 @@ class JsCoreScriptingCompiler( val files = listOf(snippetKtFile) val (bindingContext, module) = analysisResult - val psi2ir = Psi2IrTranslator(environment.configuration.languageVersionSettings, Psi2IrConfiguration()) + val psi2ir = Psi2IrTranslator( + environment.configuration.languageVersionSettings, + Psi2IrConfiguration(), + environment.configuration::checkNoUnboundSymbols + ) val generatorExtensions = if (replCompilerState == null) GeneratorExtensions() diff --git a/plugins/scripting/scripting-compiler-js/src/org/jetbrains/kotlin/scripting/js/JsScriptDependencyCompiler.kt b/plugins/scripting/scripting-compiler-js/src/org/jetbrains/kotlin/scripting/js/JsScriptDependencyCompiler.kt index d359d2c8cf2..afcababa996 100644 --- a/plugins/scripting/scripting-compiler-js/src/org/jetbrains/kotlin/scripting/js/JsScriptDependencyCompiler.kt +++ b/plugins/scripting/scripting-compiler-js/src/org/jetbrains/kotlin/scripting/js/JsScriptDependencyCompiler.kt @@ -17,10 +17,7 @@ import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext import org.jetbrains.kotlin.ir.backend.js.generateJsCode import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsIrLinker import org.jetbrains.kotlin.ir.backend.js.utils.NameTables -import org.jetbrains.kotlin.ir.util.ExternalDependenciesGenerator -import org.jetbrains.kotlin.ir.util.IrMessageLogger -import org.jetbrains.kotlin.ir.util.SymbolTable -import org.jetbrains.kotlin.ir.util.patchDeclarationParents +import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.js.config.JSConfigurationKeys import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi2ir.descriptors.IrBuiltInsOverDescriptors @@ -38,7 +35,7 @@ class JsScriptDependencyCompiler( fun compile(dependencies: List): String { val builtIns: KotlinBuiltIns = dependencies.single { it.allDependencyModules.isEmpty() }.builtIns val languageVersionSettings = LanguageVersionSettingsImpl.DEFAULT - val messageLogger = configuration[IrMessageLogger.IR_MESSAGE_LOGGER] ?: IrMessageLogger.None + val messageLogger = configuration.irMessageLogger val moduleName = Name.special("") val storageManager = LockBasedStorageManager.NO_LOCKS val moduleDescriptor = ModuleDescriptorImpl(moduleName, storageManager, builtIns, null).also {