From eda30ff7048a83a7a411f4e6202eb361b86d298c Mon Sep 17 00:00:00 2001 From: Sergej Jaskiewicz Date: Fri, 15 Dec 2023 20:05:02 +0100 Subject: [PATCH] [klib] Implement diagnostics for clashing KLIB signatures Now, we detect clashing signatures during serialization to KLIB and report a compiler error if two or more declarations have the same `IdSignature` For example, for the following code: ```kotlin @Deprecated("", level = DeprecationLevel.HIDDEN) fun foo(): String = "" fun foo(): Int = 0 ``` the compiler will produce this diagnostic: ``` e: main.kt:1:1 Platform declaration clash: The following declarations have the same KLIB signature (/foo|foo(){}[0]): fun foo(): String defined in root package fun foo(): Int defined in root package e: main.kt:4:1 Platform declaration clash: The following declarations have the same KLIB signature (/foo|foo(){}[0]): fun foo(): String defined in root package fun foo(): Int defined in root package ``` Note that we report this diagnostic during serialization and not earlier (e.g., in fir2ir) for more robustness, so ensure that we check exactly the signatures that will be written to a KLIB. If we later introduce some annotation for customizing a declaration's signature (e.g., for preserving binary compatibility), this diagnostic will continue to work as expected. ^KT-63670 Fixed --- .../diagnostics/rendering/CommonRenderers.kt | 24 +++++++++ .../jvm/diagnostics/JvmBackendErrors.kt | 27 +++++----- .../kotlin/diagnostics/rendering/Renderers.kt | 14 ++--- .../ir/serialization.common/build.gradle.kts | 1 + .../ConflictingKlibSignaturesData.kt | 11 ++++ .../diagnostics/IdSignatureClashDetector.kt | 29 +++++++++++ .../common/diagnostics/SerializationErrors.kt | 52 +++++++++++++++++++ .../common/serialization/DeclarationTable.kt | 26 +++------- .../serialization/IrModuleSerializer.kt | 18 ++++++- .../jetbrains/kotlin/ir/backend/js/klib.kt | 6 +-- .../serialization/ir/JsDeclarationTable.kt | 29 +---------- .../serialization/ir/JsIrModuleSerializer.kt | 20 ++++--- .../serialization/KonanIrModuleSerializer.kt | 15 +++++- .../signatureClash.diag.txt | 14 +++++ .../klibSerializationTests/signatureClash.kt | 20 +++++++ .../kotlin/klib/AbstractKlibIrTextTestCase.kt | 26 +++++++--- .../kotlin/renderer/DescriptorRenderer.kt | 5 ++ .../kotlin/benchmarks/GenerateIrRuntime.kt | 9 ++-- .../generators/tests/GenerateJsTests.kt | 9 ++++ .../ir/AbstractJsBlackBoxCodegenTestBase.kt | 4 +- .../FirPsiJsKlibDiagnosticsTestGenerated.java | 33 ++++++++++++ .../org/jetbrains/kotlin/cli/bc/K2Native.kt | 1 + .../backend/konan/FirNativeSerializer.kt | 21 +++++++- .../backend/konan/driver/phases/Serializer.kt | 9 +++- .../SignatureClashDiagnostics/main.kt | 12 +++++ .../SignatureClashDiagnostics/output.txt | 11 ++++ .../konan/test/blackbox/CompilerOutputTest.kt | 18 +++++-- 27 files changed, 366 insertions(+), 98 deletions(-) create mode 100644 compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/diagnostics/ConflictingKlibSignaturesData.kt create mode 100644 compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/diagnostics/IdSignatureClashDetector.kt create mode 100644 compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/diagnostics/SerializationErrors.kt create mode 100644 compiler/testData/diagnostics/klibSerializationTests/signatureClash.diag.txt create mode 100644 compiler/testData/diagnostics/klibSerializationTests/signatureClash.kt create mode 100644 js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/fir/FirPsiJsKlibDiagnosticsTestGenerated.java create mode 100644 native/native.tests/testData/compilerOutput/SignatureClashDiagnostics/main.kt create mode 100644 native/native.tests/testData/compilerOutput/SignatureClashDiagnostics/output.txt diff --git a/compiler/frontend.common-psi/src/org/jetbrains/kotlin/diagnostics/rendering/CommonRenderers.kt b/compiler/frontend.common-psi/src/org/jetbrains/kotlin/diagnostics/rendering/CommonRenderers.kt index 707da2f7650..e17ed080956 100644 --- a/compiler/frontend.common-psi/src/org/jetbrains/kotlin/diagnostics/rendering/CommonRenderers.kt +++ b/compiler/frontend.common-psi/src/org/jetbrains/kotlin/diagnostics/rendering/CommonRenderers.kt @@ -9,6 +9,7 @@ import com.intellij.openapi.util.text.StringUtil import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.types.Variance +import org.jetbrains.kotlin.utils.addToStdlib.joinToWithBuffer import java.io.PrintWriter import java.io.StringWriter @@ -63,4 +64,27 @@ object CommonRenderers { } } } + + @JvmStatic + fun renderConflictingSignatureData( + signatureKind: String, + sortUsing: Comparator, + declarationRenderer: DiagnosticParameterRenderer, + renderSignature: StringBuilder.(Data) -> Unit, + declarations: (Data) -> Collection, + ) = Renderer { data -> + val sortedDeclarations = declarations(data).sortedWith(sortUsing) + val renderingContext = RenderingContext.Impl(sortedDeclarations) + buildString { + append("The following declarations have the same ") + append(signatureKind) + append(" signature (") + renderSignature(data) + appendLine("):") + sortedDeclarations.joinToWithBuffer(this, separator = "\n") { descriptor -> + append(" ") + append(declarationRenderer.render(descriptor, renderingContext)) + } + } + } } diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/diagnostics/JvmBackendErrors.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/diagnostics/JvmBackendErrors.kt index 8fd7818acbf..6dac01ddd08 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/diagnostics/JvmBackendErrors.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/diagnostics/JvmBackendErrors.kt @@ -11,12 +11,14 @@ import org.jetbrains.kotlin.diagnostics.SourceElementPositioningStrategies.DECLA import org.jetbrains.kotlin.diagnostics.error0 import org.jetbrains.kotlin.diagnostics.error1 import org.jetbrains.kotlin.diagnostics.error2 -import org.jetbrains.kotlin.diagnostics.rendering.* +import org.jetbrains.kotlin.diagnostics.rendering.BaseDiagnosticRendererFactory +import org.jetbrains.kotlin.diagnostics.rendering.CommonRenderers import org.jetbrains.kotlin.diagnostics.rendering.CommonRenderers.NAME import org.jetbrains.kotlin.diagnostics.rendering.CommonRenderers.STRING +import org.jetbrains.kotlin.diagnostics.rendering.Renderers +import org.jetbrains.kotlin.diagnostics.rendering.RootDiagnosticRendererFactory import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.MemberComparator -import org.jetbrains.kotlin.utils.join object JvmBackendErrors { val CONFLICTING_JVM_DECLARATIONS by error1(DECLARATION_SIGNATURE_OR_DEFAULT) @@ -48,17 +50,16 @@ object JvmBackendErrors { object KtDefaultJvmErrorMessages : BaseDiagnosticRendererFactory() { @JvmField - val CONFLICTING_JVM_DECLARATIONS_DATA = Renderer { - val renderedDescriptors = it.signatureDescriptors.sortedWith(MemberComparator.INSTANCE) - val renderingContext = RenderingContext.Impl(renderedDescriptors) - """ - The following declarations have the same JVM signature (${it.signature.name}${it.signature.desc}): - - """.trimIndent() + - join(renderedDescriptors.map { descriptor -> - " " + Renderers.WITHOUT_MODIFIERS.render(descriptor, renderingContext) - }, "\n") - } + val CONFLICTING_JVM_DECLARATIONS_DATA = CommonRenderers.renderConflictingSignatureData( + signatureKind = "JVM", + sortUsing = MemberComparator.INSTANCE, + declarationRenderer = Renderers.WITHOUT_MODIFIERS, + renderSignature = { + append(it.signature.name) + append(it.signature.desc) + }, + declarations = ConflictingJvmDeclarationsData::signatureDescriptors, + ) override val MAP = KtDiagnosticFactoryToRendererMap("KT").also { map -> map.put(JvmBackendErrors.CONFLICTING_JVM_DECLARATIONS, "Platform declaration clash: {0}", CONFLICTING_JVM_DECLARATIONS_DATA) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/Renderers.kt b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/Renderers.kt index 2b01e3861ce..eca81f7c8d9 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/Renderers.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/Renderers.kt @@ -31,13 +31,14 @@ import org.jetbrains.kotlin.diagnostics.rendering.TabledDescriptorRenderer.newTe import org.jetbrains.kotlin.name.FqNameUnsafe import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.platform.isCommon -import org.jetbrains.kotlin.psi.* -import org.jetbrains.kotlin.renderer.AnnotationArgumentsRenderingPolicy +import org.jetbrains.kotlin.psi.KtClass +import org.jetbrains.kotlin.psi.KtClassOrObject +import org.jetbrains.kotlin.psi.KtNamedDeclaration import org.jetbrains.kotlin.renderer.DescriptorRenderer import org.jetbrains.kotlin.renderer.DescriptorRenderer.Companion.DEBUG_TEXT -import org.jetbrains.kotlin.renderer.DescriptorRendererModifier import org.jetbrains.kotlin.renderer.PropertyAccessorRenderingPolicy -import org.jetbrains.kotlin.resolve.* +import org.jetbrains.kotlin.resolve.DescriptorUtils +import org.jetbrains.kotlin.resolve.MemberComparator import org.jetbrains.kotlin.resolve.calls.inference.* import org.jetbrains.kotlin.resolve.calls.inference.TypeBounds.Bound import org.jetbrains.kotlin.resolve.calls.inference.TypeBounds.BoundKind.LOWER_BOUND @@ -52,6 +53,7 @@ import org.jetbrains.kotlin.types.checker.KotlinTypeChecker import org.jetbrains.kotlin.utils.IDEAPlatforms import org.jetbrains.kotlin.utils.IDEAPluginsCompatibilityAPI import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull +import org.jetbrains.kotlin.utils.addToStdlib.joinToWithBuffer object Renderers { @@ -706,9 +708,7 @@ object Renderers { @JvmField val COMPACT_WITHOUT_SUPERTYPES = DescriptorRenderer.COMPACT_WITHOUT_SUPERTYPES.asRenderer() @JvmField - val WITHOUT_MODIFIERS = DescriptorRenderer.withOptions { - modifiers = emptySet() - }.asRenderer() + val WITHOUT_MODIFIERS = DescriptorRenderer.WITHOUT_MODIFIERS.asRenderer() @JvmField val SHORT_NAMES_IN_TYPES = DescriptorRenderer.SHORT_NAMES_IN_TYPES.asRenderer() @JvmField diff --git a/compiler/ir/serialization.common/build.gradle.kts b/compiler/ir/serialization.common/build.gradle.kts index bf087f07a32..890d3f27702 100644 --- a/compiler/ir/serialization.common/build.gradle.kts +++ b/compiler/ir/serialization.common/build.gradle.kts @@ -10,6 +10,7 @@ dependencies { api(project(":kotlin-util-klib-metadata")) api(project(":compiler:util")) implementation(project(":compiler:psi")) + implementation(project(":compiler:frontend.common-psi")) compileOnly(commonDependency("org.jetbrains.kotlin:kotlin-reflect")) { isTransitive = false } compileOnly(commonDependency("org.jetbrains.intellij.deps.fastutil:intellij-deps-fastutil")) diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/diagnostics/ConflictingKlibSignaturesData.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/diagnostics/ConflictingKlibSignaturesData.kt new file mode 100644 index 00000000000..f4aef58b11a --- /dev/null +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/diagnostics/ConflictingKlibSignaturesData.kt @@ -0,0 +1,11 @@ +/* + * Copyright 2010-2023 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.diagnostics + +import org.jetbrains.kotlin.ir.declarations.IrDeclaration +import org.jetbrains.kotlin.ir.util.IdSignature + +internal data class ConflictingKlibSignaturesData(val signature: IdSignature, val declarations: Collection) diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/diagnostics/IdSignatureClashDetector.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/diagnostics/IdSignatureClashDetector.kt new file mode 100644 index 00000000000..e940dcbb1af --- /dev/null +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/diagnostics/IdSignatureClashDetector.kt @@ -0,0 +1,29 @@ +/* + * Copyright 2010-2023 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.diagnostics + +import org.jetbrains.kotlin.ir.IrDiagnosticReporter +import org.jetbrains.kotlin.ir.declarations.IrDeclaration +import org.jetbrains.kotlin.ir.linkage.SignatureClashDetector +import org.jetbrains.kotlin.ir.util.IdSignature +import org.jetbrains.kotlin.ir.util.file +import org.jetbrains.kotlin.ir.util.parentClassOrNull + +class IdSignatureClashDetector : SignatureClashDetector() { + override fun reportSignatureConflict( + signature: IdSignature, + declarations: Collection, + diagnosticReporter: IrDiagnosticReporter + ) { + reportSignatureClashTo( + diagnosticReporter, + SerializationErrors.CONFLICTING_KLIB_SIGNATURES_ERROR, + declarations, + ConflictingKlibSignaturesData(signature, declarations), + reportOnIfSynthetic = { it.parentClassOrNull ?: it.file }, + ) + } +} \ No newline at end of file diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/diagnostics/SerializationErrors.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/diagnostics/SerializationErrors.kt new file mode 100644 index 00000000000..26291f52fcb --- /dev/null +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/diagnostics/SerializationErrors.kt @@ -0,0 +1,52 @@ +/* + * Copyright 2010-2023 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.diagnostics + +import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.backend.common.diagnostics.SerializationDiagnosticRenderers.CONFLICTING_KLIB_SIGNATURES_DATA +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.diagnostics.KtDiagnosticFactoryToRendererMap +import org.jetbrains.kotlin.diagnostics.error1 +import org.jetbrains.kotlin.diagnostics.rendering.BaseDiagnosticRendererFactory +import org.jetbrains.kotlin.diagnostics.rendering.CommonRenderers +import org.jetbrains.kotlin.diagnostics.rendering.Renderer +import org.jetbrains.kotlin.diagnostics.rendering.RootDiagnosticRendererFactory +import org.jetbrains.kotlin.ir.declarations.IrDeclaration +import org.jetbrains.kotlin.ir.descriptors.toIrBasedDescriptor +import org.jetbrains.kotlin.ir.util.render +import org.jetbrains.kotlin.renderer.DescriptorRenderer +import org.jetbrains.kotlin.resolve.MemberComparator + +internal object SerializationErrors { + val CONFLICTING_KLIB_SIGNATURES_ERROR by error1() + + init { + RootDiagnosticRendererFactory.registerFactory(KtDefaultSerializationErrorMessages) + } +} + +internal object KtDefaultSerializationErrorMessages : BaseDiagnosticRendererFactory() { + override val MAP = KtDiagnosticFactoryToRendererMap("KT").also { map -> + map.put( + SerializationErrors.CONFLICTING_KLIB_SIGNATURES_ERROR, + "Platform declaration clash: {0}", + CONFLICTING_KLIB_SIGNATURES_DATA, + ) + } +} + +internal object SerializationDiagnosticRenderers { + val CONFLICTING_KLIB_SIGNATURES_DATA = + CommonRenderers.renderConflictingSignatureData( + signatureKind = "KLIB", + sortUsing = MemberComparator.INSTANCE, + declarationRenderer = Renderer { + DescriptorRenderer.WITHOUT_MODIFIERS.render(it) + }, + renderSignature = { append(it.signature.render()) }, + declarations = { it.declarations.map(IrDeclaration::toIrBasedDescriptor) }, + ) +} \ No newline at end of file diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/DeclarationTable.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/DeclarationTable.kt index 390db83a60b..40c2a6e8415 100644 --- a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/DeclarationTable.kt +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/DeclarationTable.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.backend.common.serialization +import org.jetbrains.kotlin.backend.common.diagnostics.IdSignatureClashDetector import org.jetbrains.kotlin.backend.common.serialization.signature.IdSignatureFactory import org.jetbrains.kotlin.backend.common.serialization.signature.PublicIdSignatureComputer import org.jetbrains.kotlin.ir.IrBuiltIns @@ -15,37 +16,24 @@ import org.jetbrains.kotlin.ir.util.IdSignature import org.jetbrains.kotlin.ir.util.KotlinMangler import org.jetbrains.kotlin.ir.util.render - -interface IdSignatureClashTracker { - fun commit(declaration: IrDeclaration, signature: IdSignature) - - companion object { - val DEFAULT_TRACKER = object : IdSignatureClashTracker { - override fun commit(declaration: IrDeclaration, signature: IdSignature) {} - } - } -} - -abstract class GlobalDeclarationTable( - private val mangler: KotlinMangler.IrMangler, - private val clashTracker: IdSignatureClashTracker -) { +abstract class GlobalDeclarationTable(private val mangler: KotlinMangler.IrMangler) { val publicIdSignatureComputer = PublicIdSignatureComputer(mangler) + internal val clashDetector = IdSignatureClashDetector() protected val table = hashMapOf() - constructor(mangler: KotlinMangler.IrMangler) : this(mangler, IdSignatureClashTracker.DEFAULT_TRACKER) - protected fun loadKnownBuiltins(builtIns: IrBuiltIns) { builtIns.knownBuiltins.forEach { val symbol = (it as IrSymbolOwner).symbol - table[it] = symbol.signature!!.also { id -> clashTracker.commit(it, id) } + table[it] = symbol.signature!!.also { id -> clashDetector.trackDeclaration(it, id) } } } open fun computeSignatureByDeclaration(declaration: IrDeclaration, compatibleMode: Boolean): IdSignature { return table.getOrPut(declaration) { - publicIdSignatureComputer.composePublicIdSignature(declaration, compatibleMode).also { clashTracker.commit(declaration, it) } + publicIdSignatureComputer.composePublicIdSignature(declaration, compatibleMode).also { + clashDetector.trackDeclaration(declaration, it) + } } } diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrModuleSerializer.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrModuleSerializer.kt index bd26523c2b5..9963026ddcc 100644 --- a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrModuleSerializer.kt +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrModuleSerializer.kt @@ -6,14 +6,23 @@ package org.jetbrains.kotlin.backend.common.serialization import org.jetbrains.kotlin.builtins.FunctionInterfacePackageFragment +import org.jetbrains.kotlin.diagnostics.DiagnosticReporter +import org.jetbrains.kotlin.ir.IrDiagnosticReporter import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.declarations.IrModuleFragment import org.jetbrains.kotlin.ir.util.IrMessageLogger import org.jetbrains.kotlin.library.SerializedIrFile import org.jetbrains.kotlin.library.SerializedIrModule -abstract class IrModuleSerializer(protected val messageLogger: IrMessageLogger, protected val compatibilityMode: CompatibilityMode, protected val normalizeAbsolutePaths: Boolean, protected val sourceBaseDirs: Collection) { - abstract fun createSerializerForFile(file: IrFile): F +abstract class IrModuleSerializer( + protected val diagnosticReporter: IrDiagnosticReporter, + protected val messageLogger: IrMessageLogger, + protected val compatibilityMode: CompatibilityMode, + protected val normalizeAbsolutePaths: Boolean, + protected val sourceBaseDirs: Collection, + private val shouldCheckSignaturesOnUniqueness: Boolean, +) { + abstract fun createSerializerForFile(file: IrFile): Serializer /** * Allows to skip [file] during serialization. @@ -23,6 +32,8 @@ abstract class IrModuleSerializer(protected val messageLog protected open fun backendSpecificFileFilter(file: IrFile): Boolean = true + protected abstract val globalDeclarationTable: GlobalDeclarationTable + private fun serializeIrFile(file: IrFile): SerializedIrFile { val fileSerializer = createSerializerForFile(file) return fileSerializer.serializeIrFile(file) @@ -33,6 +44,9 @@ abstract class IrModuleSerializer(protected val messageLog .filter { it.packageFragmentDescriptor !is FunctionInterfacePackageFragment } .filter(this::backendSpecificFileFilter) .map(this::serializeIrFile) + if (shouldCheckSignaturesOnUniqueness) { + globalDeclarationTable.clashDetector.reportErrorsTo(diagnosticReporter) + } return SerializedIrModule(serializedFiles) } } \ No newline at end of file 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 16ed58855d5..39cc9d57626 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 @@ -631,7 +631,7 @@ fun serializeModuleIntoKlib( val compatibilityMode = CompatibilityMode(abiVersion) val sourceBaseDirs = configuration[CommonConfigurationKeys.KLIB_RELATIVE_PATH_BASES] ?: emptyList() val absolutePathNormalization = configuration[CommonConfigurationKeys.KLIB_NORMALIZE_ABSOLUTE_PATH] ?: false - val signatureClashChecks = configuration[CommonConfigurationKeys.PRODUCE_KLIB_SIGNATURES_CLASH_CHECKS] ?: false + val signatureClashChecks = configuration[CommonConfigurationKeys.PRODUCE_KLIB_SIGNATURES_CLASH_CHECKS] ?: true val moduleExportedNames = moduleFragment.collectExportedNames() @@ -643,6 +643,7 @@ fun serializeModuleIntoKlib( val serializedIr = JsIrModuleSerializer( + irDiagnosticReporter, messageLogger, moduleFragment.irBuiltins, compatibilityMode, @@ -650,8 +651,7 @@ fun serializeModuleIntoKlib( sourceBaseDirs = sourceBaseDirs, configuration.languageVersionSettings, signatureClashChecks, - jsIrFileMetadataFactory = { JsIrFileMetadata(moduleExportedNames[it]?.values?.toSmartList() ?: emptyList()) } - ).serializedIrModule(moduleFragment) + ) { JsIrFileMetadata(moduleExportedNames[it]?.values?.toSmartList() ?: emptyList()) }.serializedIrModule(moduleFragment) val moduleDescriptor = moduleFragment.descriptor diff --git a/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/lower/serialization/ir/JsDeclarationTable.kt b/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/lower/serialization/ir/JsDeclarationTable.kt index d63e74f3783..100bfae306d 100644 --- a/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/lower/serialization/ir/JsDeclarationTable.kt +++ b/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/lower/serialization/ir/JsDeclarationTable.kt @@ -6,36 +6,9 @@ package org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir import org.jetbrains.kotlin.backend.common.serialization.GlobalDeclarationTable -import org.jetbrains.kotlin.backend.common.serialization.IdSignatureClashTracker import org.jetbrains.kotlin.ir.IrBuiltIns -import org.jetbrains.kotlin.ir.declarations.IrDeclaration -import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction -import org.jetbrains.kotlin.ir.declarations.IrTypeParameter -import org.jetbrains.kotlin.ir.util.IdSignature -import org.jetbrains.kotlin.ir.util.render -class JsUniqIdClashTracker() : IdSignatureClashTracker { - private val committedIdSignatures = mutableMapOf() - - override fun commit(declaration: IrDeclaration, signature: IdSignature) { - if (!signature.isPubliclyVisible) return // don't track local ids - - if (signature in committedIdSignatures) { - val clashedDeclaration = committedIdSignatures[signature]!! - val parent = declaration.parent - val clashedParent = clashedDeclaration.parent - if (declaration !is IrTypeParameter || parent !is IrSimpleFunction || clashedParent !is IrSimpleFunction || parent.correspondingPropertySymbol !== clashedParent.correspondingPropertySymbol) { - // TODO: handle clashes properly - error("IdSignature clash: $signature; Existed declaration ${clashedDeclaration.render()} clashed with new ${declaration.render()}") - } - } - - committedIdSignatures[signature] = declaration - } -} - -class JsGlobalDeclarationTable(builtIns: IrBuiltIns, tracker: IdSignatureClashTracker = JsUniqIdClashTracker()) : - GlobalDeclarationTable(JsManglerIr, tracker) { +class JsGlobalDeclarationTable(builtIns: IrBuiltIns) : GlobalDeclarationTable(JsManglerIr) { init { loadKnownBuiltins(builtIns) } diff --git a/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/lower/serialization/ir/JsIrModuleSerializer.kt b/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/lower/serialization/ir/JsIrModuleSerializer.kt index cea831f7e9c..9b13e1782e0 100644 --- a/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/lower/serialization/ir/JsIrModuleSerializer.kt +++ b/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/lower/serialization/ir/JsIrModuleSerializer.kt @@ -7,14 +7,16 @@ package org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir import org.jetbrains.kotlin.backend.common.serialization.CompatibilityMode import org.jetbrains.kotlin.backend.common.serialization.DeclarationTable -import org.jetbrains.kotlin.backend.common.serialization.IdSignatureClashTracker import org.jetbrains.kotlin.backend.common.serialization.IrModuleSerializer import org.jetbrains.kotlin.config.LanguageVersionSettings +import org.jetbrains.kotlin.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.ir.IrBuiltIns +import org.jetbrains.kotlin.ir.IrDiagnosticReporter import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.util.IrMessageLogger class JsIrModuleSerializer( + diagnosticReporter: IrDiagnosticReporter, messageLogger: IrMessageLogger, irBuiltIns: IrBuiltIns, compatibilityMode: CompatibilityMode, @@ -22,13 +24,17 @@ class JsIrModuleSerializer( sourceBaseDirs: Collection, private val languageVersionSettings: LanguageVersionSettings, shouldCheckSignaturesOnUniqueness: Boolean = true, - private val jsIrFileMetadataFactory: JsIrFileMetadataFactory = JsIrFileEmptyMetadataFactory -) : IrModuleSerializer(messageLogger, compatibilityMode, normalizeAbsolutePaths, sourceBaseDirs) { + private val jsIrFileMetadataFactory: JsIrFileMetadataFactory = JsIrFileEmptyMetadataFactory, +) : IrModuleSerializer( + diagnosticReporter, + messageLogger, + compatibilityMode, + normalizeAbsolutePaths, + sourceBaseDirs, + shouldCheckSignaturesOnUniqueness, +) { - private val globalDeclarationTable = JsGlobalDeclarationTable( - irBuiltIns, - if (shouldCheckSignaturesOnUniqueness) JsUniqIdClashTracker() else IdSignatureClashTracker.DEFAULT_TRACKER - ) + override val globalDeclarationTable = JsGlobalDeclarationTable(irBuiltIns) override fun createSerializerForFile(file: IrFile): JsIrFileSerializer = JsIrFileSerializer( diff --git a/compiler/ir/serialization.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanIrModuleSerializer.kt b/compiler/ir/serialization.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanIrModuleSerializer.kt index dd7111c1139..7c47b6a4018 100644 --- a/compiler/ir/serialization.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanIrModuleSerializer.kt +++ b/compiler/ir/serialization.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanIrModuleSerializer.kt @@ -8,12 +8,15 @@ package org.jetbrains.kotlin.backend.konan.serialization import org.jetbrains.kotlin.backend.common.serialization.CompatibilityMode import org.jetbrains.kotlin.backend.common.serialization.IrModuleSerializer import org.jetbrains.kotlin.config.LanguageVersionSettings +import org.jetbrains.kotlin.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.ir.IrBuiltIns +import org.jetbrains.kotlin.ir.IrDiagnosticReporter import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.util.IrMessageLogger import org.jetbrains.kotlin.name.NativeStandardInteropNames class KonanIrModuleSerializer( + diagnosticReporter: IrDiagnosticReporter, messageLogger: IrMessageLogger, irBuiltIns: IrBuiltIns, compatibilityMode: CompatibilityMode, @@ -22,9 +25,17 @@ class KonanIrModuleSerializer( private val languageVersionSettings: LanguageVersionSettings, private val bodiesOnlyForInlines: Boolean = false, private val skipPrivateApi: Boolean = false, -) : IrModuleSerializer(messageLogger, compatibilityMode, normalizeAbsolutePaths, sourceBaseDirs) { + shouldCheckSignaturesOnUniqueness: Boolean = true, +) : IrModuleSerializer( + diagnosticReporter, + messageLogger, + compatibilityMode, + normalizeAbsolutePaths, + sourceBaseDirs, + shouldCheckSignaturesOnUniqueness, +) { - private val globalDeclarationTable = KonanGlobalDeclarationTable(irBuiltIns) + override val globalDeclarationTable = KonanGlobalDeclarationTable(irBuiltIns) // We skip files with IR for C structs and enums because they should be // generated anew. diff --git a/compiler/testData/diagnostics/klibSerializationTests/signatureClash.diag.txt b/compiler/testData/diagnostics/klibSerializationTests/signatureClash.diag.txt new file mode 100644 index 00000000000..95fa04108f6 --- /dev/null +++ b/compiler/testData/diagnostics/klibSerializationTests/signatureClash.diag.txt @@ -0,0 +1,14 @@ +/foo.kt:7:1: error: Platform declaration clash: The following declarations have the same KLIB signature (com.example.klib.serialization.diagnostics/foo|foo(){}[0]): + fun foo(): kotlin.Long defined in com.example.klib.serialization.diagnostics + fun foo(): kotlin.String defined in com.example.klib.serialization.diagnostics + fun foo(): kotlin.Int defined in com.example.klib.serialization.diagnostics + +/main.kt:13:1: error: Platform declaration clash: The following declarations have the same KLIB signature (com.example.klib.serialization.diagnostics/foo|foo(){}[0]): + fun foo(): kotlin.Long defined in com.example.klib.serialization.diagnostics + fun foo(): kotlin.String defined in com.example.klib.serialization.diagnostics + fun foo(): kotlin.Int defined in com.example.klib.serialization.diagnostics + +/main.kt:16:1: error: Platform declaration clash: The following declarations have the same KLIB signature (com.example.klib.serialization.diagnostics/foo|foo(){}[0]): + fun foo(): kotlin.Long defined in com.example.klib.serialization.diagnostics + fun foo(): kotlin.String defined in com.example.klib.serialization.diagnostics + fun foo(): kotlin.Int defined in com.example.klib.serialization.diagnostics diff --git a/compiler/testData/diagnostics/klibSerializationTests/signatureClash.kt b/compiler/testData/diagnostics/klibSerializationTests/signatureClash.kt new file mode 100644 index 00000000000..ee535c623f7 --- /dev/null +++ b/compiler/testData/diagnostics/klibSerializationTests/signatureClash.kt @@ -0,0 +1,20 @@ +// FIR_IDENTICAL +// RENDER_ALL_DIAGNOSTICS_FULL_TEXT + +// FILE: foo.kt +package com.example.klib.serialization.diagnostics + +@Deprecated("", level = DeprecationLevel.HIDDEN) +fun foo(): Long = 0L + +// FILE: main.kt +package com.example.klib.serialization.diagnostics + +@Deprecated("", level = DeprecationLevel.HIDDEN) +fun foo(): String = "" + +fun foo(): Int = 0 + +fun main() { + foo() +} diff --git a/compiler/tests-common/tests/org/jetbrains/kotlin/klib/AbstractKlibIrTextTestCase.kt b/compiler/tests-common/tests/org/jetbrains/kotlin/klib/AbstractKlibIrTextTestCase.kt index ebfb329691d..afcd0a5fbb3 100644 --- a/compiler/tests-common/tests/org/jetbrains/kotlin/klib/AbstractKlibIrTextTestCase.kt +++ b/compiler/tests-common/tests/org/jetbrains/kotlin/klib/AbstractKlibIrTextTestCase.kt @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.klib import com.intellij.openapi.project.Project import com.intellij.psi.PsiElement import junit.framework.TestCase +import org.jetbrains.kotlin.KtDiagnosticReporterWithImplicitIrBasedContext import org.jetbrains.kotlin.backend.common.CommonKLibResolver import org.jetbrains.kotlin.ir.util.isExpect import org.jetbrains.kotlin.backend.common.linkage.issues.checkNoUnboundSymbols @@ -24,6 +25,8 @@ import org.jetbrains.kotlin.config.* import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl +import org.jetbrains.kotlin.diagnostics.DiagnosticReporter +import org.jetbrains.kotlin.diagnostics.DiagnosticReporterFactory import org.jetbrains.kotlin.incremental.components.LookupTracker import org.jetbrains.kotlin.ir.AbstractIrGeneratorTestCase import org.jetbrains.kotlin.ir.IrElement @@ -139,16 +142,25 @@ abstract class AbstractKlibIrTextTestCase : CodegenTestCase() { return serializePackageFragment(moduleDescriptor, memberScope, ktFile.packageFqName) } - protected fun serializeModule(irModuleFragment: IrModuleFragment, bindingContext: BindingContext, stdlib: KotlinLibrary, containsErrorCode: Boolean): String { + private fun serializeModule( + irModuleFragment: IrModuleFragment, + bindingContext: BindingContext, + stdlib: KotlinLibrary, + containsErrorCode: Boolean, + ): String { val ktFiles = myFiles.psiFiles val serializedIr = JsIrModuleSerializer( - IrMessageLogger.None, - irModuleFragment.irBuiltins, - CompatibilityMode.CURRENT, - false, - emptyList(), + KtDiagnosticReporterWithImplicitIrBasedContext( + DiagnosticReporterFactory.createPendingReporter(), myEnvironment.configuration.languageVersionSettings, - ).serializedIrModule(irModuleFragment) + ), + IrMessageLogger.None, + irModuleFragment.irBuiltins, + CompatibilityMode.CURRENT, + false, + emptyList(), + myEnvironment.configuration.languageVersionSettings, + ).serializedIrModule(irModuleFragment) val moduleDescriptor = irModuleFragment.descriptor val metadataSerializer = klibMetadataIncrementalSerializer(myEnvironment.configuration, myEnvironment.project, containsErrorCode) diff --git a/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRenderer.kt b/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRenderer.kt index 9acc99c047a..0d902935af9 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRenderer.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRenderer.kt @@ -103,6 +103,11 @@ abstract class DescriptorRenderer { return DescriptorRendererImpl(options) } + @JvmField + val WITHOUT_MODIFIERS: DescriptorRenderer = withOptions { + modifiers = emptySet() + } + @JvmField val COMPACT_WITH_MODIFIERS: DescriptorRenderer = withOptions { withDefinedIn = false 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 a0e8f82444e..4b35ebdd4a5 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/benchmarks/GenerateIrRuntime.kt +++ b/js/js.tests/test/org/jetbrains/kotlin/benchmarks/GenerateIrRuntime.kt @@ -11,6 +11,7 @@ import com.intellij.openapi.vfs.StandardFileSystems import com.intellij.openapi.vfs.VfsUtilCore import com.intellij.openapi.vfs.VirtualFileManager import com.intellij.psi.PsiManager +import org.jetbrains.kotlin.KtDiagnosticReporterWithImplicitIrBasedContext import org.jetbrains.kotlin.KtPsiSourceFile import org.jetbrains.kotlin.analyzer.AnalysisResult import org.jetbrains.kotlin.backend.common.linkage.issues.checkNoUnboundSymbols @@ -37,7 +38,6 @@ 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.lower.serialization.ir.JsIrModuleSerializer import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsManglerDesc -import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.collectExportedNames import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.IrModuleToJsTransformer import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.TranslationMode import org.jetbrains.kotlin.ir.declarations.IrModuleFragment @@ -529,7 +529,11 @@ class GenerateIrRuntime { private fun doSerializeIrModule(module: IrModuleFragment): SerializedIrModule { - val serializedIr = JsIrModuleSerializer( + return JsIrModuleSerializer( + KtDiagnosticReporterWithImplicitIrBasedContext( + DiagnosticReporterFactory.createPendingReporter(), + configuration.languageVersionSettings, + ), IrMessageLogger.None, module.irBuiltins, CompatibilityMode.CURRENT, @@ -537,7 +541,6 @@ class GenerateIrRuntime { emptyList(), configuration.languageVersionSettings, ).serializedIrModule(module) - return serializedIr } private fun doWriteIrModuleToStorage(serializedIrModule: SerializedIrModule, writer: KotlinLibraryOnlyIrWriter) { diff --git a/js/js.tests/test/org/jetbrains/kotlin/generators/tests/GenerateJsTests.kt b/js/js.tests/test/org/jetbrains/kotlin/generators/tests/GenerateJsTests.kt index a44ee2bb3cb..e71e029af4e 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/generators/tests/GenerateJsTests.kt +++ b/js/js.tests/test/org/jetbrains/kotlin/generators/tests/GenerateJsTests.kt @@ -211,6 +211,15 @@ fun main(args: Array) { model("debug/localVariables") } + testClass(suiteTestClassName = "FirPsiJsKlibDiagnosticsTestGenerated") { + model( + relativeRootPath = "diagnostics/klibSerializationTests", + pattern = "^([^_](.+))\\.kt$", + excludedPattern = excludedFirTestdataPattern, + targetBackend = TargetBackend.JS_IR + ) + } + testClass(suiteTestClassName = "FirPsiJsOldFrontendDiagnosticsTestGenerated") { model( relativeRootPath = "diagnostics/testsWithJsStdLib", diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/AbstractJsBlackBoxCodegenTestBase.kt b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/AbstractJsBlackBoxCodegenTestBase.kt index 4e67ab1ba8b..5db34ae1f03 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/AbstractJsBlackBoxCodegenTestBase.kt +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/AbstractJsBlackBoxCodegenTestBase.kt @@ -164,5 +164,7 @@ fun < irHandlersStep() facadeStep(backendFacade) - klibArtifactsHandlersStep() + klibArtifactsHandlersStep { + useHandlers(::JsBackendDiagnosticsHandler) + } } diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/fir/FirPsiJsKlibDiagnosticsTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/fir/FirPsiJsKlibDiagnosticsTestGenerated.java new file mode 100644 index 00000000000..fd1a7c7833f --- /dev/null +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/fir/FirPsiJsKlibDiagnosticsTestGenerated.java @@ -0,0 +1,33 @@ +/* + * Copyright 2010-2024 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.js.test.fir; + +import com.intellij.testFramework.TestDataPath; +import org.jetbrains.kotlin.test.util.KtTestUtil; +import org.jetbrains.kotlin.test.TargetBackend; +import org.jetbrains.kotlin.test.TestMetadata; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import java.io.File; +import java.util.regex.Pattern; + +/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.GenerateJsTestsKt}. DO NOT MODIFY MANUALLY */ +@SuppressWarnings("all") +@TestMetadata("compiler/testData/diagnostics/klibSerializationTests") +@TestDataPath("$PROJECT_ROOT") +public class FirPsiJsKlibDiagnosticsTestGenerated extends AbstractFirPsiJsDiagnosticWithBackendTest { + @Test + public void testAllFilesPresentInKlibSerializationTests() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/klibSerializationTests"), Pattern.compile("^([^_](.+))\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), TargetBackend.JS_IR, true); + } + + @Test + @TestMetadata("signatureClash.kt") + public void testSignatureClash() throws Exception { + runTest("compiler/testData/diagnostics/klibSerializationTests/signatureClash.kt"); + } +} diff --git a/kotlin-native/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2Native.kt b/kotlin-native/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2Native.kt index b59a1ab69ad..7ae61e239b3 100644 --- a/kotlin-native/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2Native.kt +++ b/kotlin-native/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2Native.kt @@ -108,6 +108,7 @@ class K2Native : CLICompiler() { configuration.put(CommonConfigurationKeys.KLIB_NORMALIZE_ABSOLUTE_PATH, arguments.normalizeAbsolutePath) configuration.put(CLIConfigurationKeys.RENDER_DIAGNOSTIC_INTERNAL_NAME, arguments.renderInternalDiagnosticNames) + configuration.put(CommonConfigurationKeys.PRODUCE_KLIB_SIGNATURES_CLASH_CHECKS, arguments.enableSignatureClashChecks) return environment } diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/FirNativeSerializer.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/FirNativeSerializer.kt index 4416c921038..69dd9025252 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/FirNativeSerializer.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/FirNativeSerializer.kt @@ -1,5 +1,6 @@ package org.jetbrains.kotlin.backend.konan +import org.jetbrains.kotlin.KtDiagnosticReporterWithImplicitIrBasedContext import org.jetbrains.kotlin.KtSourceFile import org.jetbrains.kotlin.backend.common.serialization.CompatibilityMode import org.jetbrains.kotlin.backend.common.serialization.metadata.makeSerializedKlibMetadata @@ -10,9 +11,13 @@ import org.jetbrains.kotlin.backend.konan.driver.phases.FirOutput import org.jetbrains.kotlin.backend.konan.driver.phases.FirSerializerInput import org.jetbrains.kotlin.backend.konan.driver.phases.SerializerOutput import org.jetbrains.kotlin.backend.konan.serialization.KonanIrModuleSerializer +import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys +import org.jetbrains.kotlin.cli.common.fir.reportToMessageCollector import org.jetbrains.kotlin.config.CommonConfigurationKeys import org.jetbrains.kotlin.config.CompilerConfiguration import org.jetbrains.kotlin.config.languageVersionSettings +import org.jetbrains.kotlin.diagnostics.DiagnosticReporter +import org.jetbrains.kotlin.diagnostics.DiagnosticReporterFactory import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.backend.ConstValueProviderImpl import org.jetbrains.kotlin.fir.backend.extractFirDeclarations @@ -65,8 +70,10 @@ internal fun PhaseContext.firSerializerBase( } val actualizedFirDeclarations = fir2IrInput?.irActualizedResult?.actualizedExpectDeclarations?.extractFirDeclarations() - return serializeNativeModule( + val diagnosticReporter = DiagnosticReporterFactory.createPendingReporter() + val serializerOutput = serializeNativeModule( configuration = configuration, + diagnosticReporter = diagnosticReporter, messageLogger = configuration.get(IrMessageLogger.IR_MESSAGE_LOGGER) ?: IrMessageLogger.None, sourceFiles, usedResolvedLibraries?.map { it.library as KonanLibrary }, @@ -95,6 +102,12 @@ internal fun PhaseContext.firSerializerBase( produceHeaderKlib, ) } + val renderDiagnosticNames = configuration.getBoolean(CLIConfigurationKeys.RENDER_DIAGNOSTIC_INTERNAL_NAME) + diagnosticReporter.reportToMessageCollector(messageCollector, renderDiagnosticNames) + if (diagnosticReporter.hasErrors) { + throw KonanCompilationException("Compilation failed: there were errors during module serialization") + } + return serializerOutput } class KotlinFileSerializedData( @@ -109,6 +122,7 @@ class KotlinFileSerializedData( internal fun PhaseContext.serializeNativeModule( configuration: CompilerConfiguration, + diagnosticReporter: DiagnosticReporter, messageLogger: IrMessageLogger, files: List, dependencies: List?, @@ -125,9 +139,11 @@ internal fun PhaseContext.serializeNativeModule( val sourceBaseDirs = configuration[CommonConfigurationKeys.KLIB_RELATIVE_PATH_BASES] ?: emptyList() val absolutePathNormalization = configuration[CommonConfigurationKeys.KLIB_NORMALIZE_ABSOLUTE_PATH] ?: false + val signatureClashChecks = configuration[CommonConfigurationKeys.PRODUCE_KLIB_SIGNATURES_CLASH_CHECKS] ?: true val serializedIr = moduleFragment?.let { KonanIrModuleSerializer( + KtDiagnosticReporterWithImplicitIrBasedContext(diagnosticReporter, configuration.languageVersionSettings), messageLogger, moduleFragment.irBuiltins, CompatibilityMode.CURRENT, @@ -135,7 +151,8 @@ internal fun PhaseContext.serializeNativeModule( sourceBaseDirs = sourceBaseDirs, languageVersionSettings = configuration.languageVersionSettings, bodiesOnlyForInlines = bodiesOnlyForInlines, - skipPrivateApi = skipPrivateApi + skipPrivateApi = skipPrivateApi, + shouldCheckSignaturesOnUniqueness = signatureClashChecks, ).serializedIrModule(moduleFragment) } diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/Serializer.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/Serializer.kt index b4e1602fb8b..5952e470483 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/Serializer.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/Serializer.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.backend.konan.driver.phases +import org.jetbrains.kotlin.KtDiagnosticReporterWithImplicitIrBasedContext import org.jetbrains.kotlin.backend.common.phaser.createSimpleNamedCompilerPhase import org.jetbrains.kotlin.backend.common.serialization.CompatibilityMode import org.jetbrains.kotlin.backend.common.serialization.metadata.KlibMetadataMonolithicSerializer @@ -14,6 +15,7 @@ import org.jetbrains.kotlin.backend.konan.serialization.KonanIrModuleSerializer import org.jetbrains.kotlin.config.CommonConfigurationKeys import org.jetbrains.kotlin.config.languageVersionSettings import org.jetbrains.kotlin.descriptors.ModuleDescriptor +import org.jetbrains.kotlin.diagnostics.DiagnosticReporterFactory import org.jetbrains.kotlin.ir.util.IrMessageLogger import org.jetbrains.kotlin.konan.library.KonanLibrary import org.jetbrains.kotlin.library.SerializedIrModule @@ -44,7 +46,12 @@ internal val SerializerPhase = createSimpleNamedCompilerPhase = emptyList(), @@ -126,7 +126,7 @@ abstract class CompilerOutputTestBase : AbstractNativeSimpleTest() { return compilation.result } - private fun TestCompilationResult<*>.toOutput(): String { + internal fun TestCompilationResult<*>.toOutput(): String { check(this is TestCompilationResult.ImmediateResult<*>) { this } val loggedData = this.loggedData check(loggedData is LoggedData.CompilationToolCall) { loggedData::class } @@ -152,4 +152,16 @@ class ClassicCompilerOutputTest : CompilerOutputTestBase() @Tag("frontend-fir") @TestDataPath("\$PROJECT_ROOT") @EnforcedProperty(ClassLevelProperty.COMPILER_OUTPUT_INTERCEPTOR, "NONE") -class FirCompilerOutputTest : CompilerOutputTestBase() \ No newline at end of file +class FirCompilerOutputTest : CompilerOutputTestBase() { + + @Test + fun testSignatureClashDiagnostics() { + // TODO: use the Compiler Core test infrastructure for testing these diagnostics (KT-64393) + val rootDir = File("native/native.tests/testData/compilerOutput/SignatureClashDiagnostics") + val settings = testRunSettings + val compilationResult = compileLibrary(settings, rootDir.resolve("main.kt")) + val goldenData = rootDir.resolve("output.txt") + + KotlinTestUtils.assertEqualsToFile(goldenData, compilationResult.toOutput()) + } +} \ No newline at end of file