[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
This commit is contained in:
committed by
Space Team
parent
e0cb145c6b
commit
eda30ff704
@@ -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
|
||||
|
||||
|
||||
+1
-28
@@ -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<IdSignature, IrDeclaration>()
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
+13
-7
@@ -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<String>,
|
||||
private val languageVersionSettings: LanguageVersionSettings,
|
||||
shouldCheckSignaturesOnUniqueness: Boolean = true,
|
||||
private val jsIrFileMetadataFactory: JsIrFileMetadataFactory = JsIrFileEmptyMetadataFactory
|
||||
) : IrModuleSerializer<JsIrFileSerializer>(messageLogger, compatibilityMode, normalizeAbsolutePaths, sourceBaseDirs) {
|
||||
private val jsIrFileMetadataFactory: JsIrFileMetadataFactory = JsIrFileEmptyMetadataFactory,
|
||||
) : IrModuleSerializer<JsIrFileSerializer>(
|
||||
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(
|
||||
|
||||
Reference in New Issue
Block a user