From 532b9e2c5f015d4cb6ae341f2c28f82a2e78f2a6 Mon Sep 17 00:00:00 2001 From: Dmitriy Dolovov Date: Thu, 23 Jun 2022 01:20:52 +0400 Subject: [PATCH] [Native][IR] Partial linkage support for cached inline functions - Support partial linkage for declarations from inline functions that are lazily deserialized from a KLIB with static cache - Linker API: Split IrModuleDeserializer.deserializeIrSymbol() into deserializeIrSymbolOrFail() and tryDeserializeIrSymbol() - Linker API: Refactor KotlinIrLinker.handleSignatureIdNotFoundInModuleWithDependencies() to deserializeOrReturnUnboundIrSymbolIfPartialLinkageEnabled() ^KT-52478 --- .../ir/serialization.common/build.gradle.kts | 1 + .../BasicIrModuleDeserializer.kt | 8 +- .../IncrementalCompilationSupport.kt | 8 +- .../serialization/IrFileDeserializer.kt | 14 +- .../serialization/IrModuleDeserializer.kt | 23 ++- .../common/serialization/KotlinIrLinker.kt | 141 +++----------- .../BasicUnlinkedDeclarationsSupport.kt | 176 ++++++++++++++++++ .../unlinked/UnlinkedDeclarationsProcessor.kt | 50 +++-- .../unlinked/UnlinkedDeclarationsSupport.kt | 17 +- .../unlinked/UsedClassifierSymbols.kt | 60 ++++++ .../jetbrains/kotlin/ir/backend/js/klib.kt | 4 +- .../js/lower/serialization/ir/JsIrLinker.kt | 5 +- .../ir/JsLazyIrModuleDeserializer.kt | 10 +- .../ir/JsUnlinkedDeclarationsSupport.kt | 13 +- .../backend/jvm/serialization/JvmIrLinker.kt | 10 +- .../IrProviderForCEnumAndCStructStubs.kt | 1 + .../konan/serialization/KonanIrlinker.kt | 25 ++- .../KonanUnlinkedDeclarationsSupport.kt | 14 +- 18 files changed, 378 insertions(+), 202 deletions(-) create mode 100644 compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/unlinked/BasicUnlinkedDeclarationsSupport.kt create mode 100644 compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/unlinked/UsedClassifierSymbols.kt diff --git a/compiler/ir/serialization.common/build.gradle.kts b/compiler/ir/serialization.common/build.gradle.kts index 0fb9942293b..9b604b49ffc 100644 --- a/compiler/ir/serialization.common/build.gradle.kts +++ b/compiler/ir/serialization.common/build.gradle.kts @@ -13,6 +13,7 @@ dependencies { compileOnly(project(":kotlin-reflect-api")) compileOnly(intellijCore()) + compileOnly(commonDependency("org.jetbrains.intellij.deps:trove4j")) } sourceSets { diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/BasicIrModuleDeserializer.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/BasicIrModuleDeserializer.kt index ce40734d376..40da205a148 100644 --- a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/BasicIrModuleDeserializer.kt +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/BasicIrModuleDeserializer.kt @@ -97,7 +97,7 @@ abstract class BasicIrModuleDeserializer( // TODO: fix to topLevel checker override fun contains(idSig: IdSignature): Boolean = idSig in moduleReversedFileIndex - open fun tryDeserializeIrSymbol(idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol? { + override fun tryDeserializeIrSymbol(idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol? { val topLevelSignature = idSig.topLevelSignature() val fileLocalDeserializationState = moduleReversedFileIndex[topLevelSignature] ?: return null @@ -107,9 +107,9 @@ abstract class BasicIrModuleDeserializer( return fileLocalDeserializationState.fileDeserializer.symbolDeserializer.deserializeIrSymbol(idSig, symbolKind) } - final override fun deserializeIrSymbol(idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind) = - tryDeserializeIrSymbol(idSig, symbolKind) - ?: error("No file for ${idSig.topLevelSignature()} (@ $idSig) in module $moduleDescriptor") + override fun deserializedSymbolNotFound(idSig: IdSignature): Nothing { + error("No file for ${idSig.topLevelSignature()} (@ $idSig) in module $moduleDescriptor") + } override val moduleFragment: IrModuleFragment = IrModuleFragmentImpl(moduleDescriptor, linker.builtIns, emptyList()) diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IncrementalCompilationSupport.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IncrementalCompilationSupport.kt index 1c3a7cb7a8c..6da9c441a39 100644 --- a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IncrementalCompilationSupport.kt +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IncrementalCompilationSupport.kt @@ -113,14 +113,16 @@ class CurrentModuleWithICDeserializer( return idSig in dirtyDeclarations || idSig.topLevelSignature() in icDeserializer || idSig in delegate } - override fun deserializeIrSymbol(idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol { + override fun tryDeserializeIrSymbol(idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol { dirtyDeclarations[idSig]?.let { return it } - if (idSig.topLevelSignature() in icDeserializer) return icDeserializer.deserializeIrSymbol(idSig, symbolKind) + if (idSig.topLevelSignature() in icDeserializer) return icDeserializer.deserializeIrSymbolOrFail(idSig, symbolKind) - return delegate.deserializeIrSymbol(idSig, symbolKind) + return delegate.deserializeIrSymbolOrFail(idSig, symbolKind) } + override fun deserializedSymbolNotFound(idSig: IdSignature): Nothing = delegate.deserializedSymbolNotFound(idSig) + override fun addModuleReachableTopLevel(idSig: IdSignature) { assert(idSig in icDeserializer) icDeserializer.addModuleReachableTopLevel(idSig) diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrFileDeserializer.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrFileDeserializer.kt index 14e78042932..54a72ca2f89 100644 --- a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrFileDeserializer.kt +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrFileDeserializer.kt @@ -74,18 +74,8 @@ class FileDeserializationState( ::addIdSignature, linker::handleExpectActualMapping, symbolProcessor = linker.symbolProcessor, - ) { idSig, symbolKind -> - - val topLevelSig = idSig.topLevelSignature() - val actualModuleDeserializer = moduleDeserializer.findModuleDeserializerForTopLevelId(topLevelSig) - ?: run { - // The symbol might be gone in newer version of dependency KLIB. Then the KLIB that was compiled against - // the older version of dependency KLIB will still have a reference to non-existing symbol. And the linker will have to - // handle such situation appropriately. See KT-41378. - linker.handleSignatureIdNotFoundInModuleWithDependencies(idSig, moduleDeserializer) - } - - actualModuleDeserializer.deserializeIrSymbol(idSig, symbolKind) + ) { idSignature, symbolKind -> + linker.deserializeOrReturnUnboundIrSymbolIfPartialLinkageEnabled(idSignature, symbolKind, moduleDeserializer) } val declarationDeserializer = IrDeclarationDeserializer( diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrModuleDeserializer.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrModuleDeserializer.kt index a8e4a227060..d0f2c86e366 100644 --- a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrModuleDeserializer.kt +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrModuleDeserializer.kt @@ -58,7 +58,8 @@ enum class IrModuleDeserializerKind { abstract class IrModuleDeserializer(private val _moduleDescriptor: ModuleDescriptor?, val libraryAbiVersion: KotlinAbiVersion) { abstract operator fun contains(idSig: IdSignature): Boolean - abstract fun deserializeIrSymbol(idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol + abstract fun tryDeserializeIrSymbol(idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol? + abstract fun deserializedSymbolNotFound(idSig: IdSignature): Nothing val moduleDescriptor: ModuleDescriptor get() = _moduleDescriptor ?: error("No ModuleDescriptor provided") @@ -72,7 +73,7 @@ abstract class IrModuleDeserializer(private val _moduleDescriptor: ModuleDescrip val signature = symbol.signature require(signature != null) { "Symbol is not public API: ${symbol.descriptor}" } assert(symbol.hasDescriptor) - deserializeIrSymbol(signature, symbol.kind()) + deserializeIrSymbolOrFail(signature, symbol.kind()) } open val klib: IrLibrary get() = error("Unsupported operation") @@ -104,6 +105,9 @@ abstract class IrModuleDeserializer(private val _moduleDescriptor: ModuleDescrip open fun signatureDeserializerForFile(fileName: String): IdSignatureDeserializer = error("Unsupported") } +fun IrModuleDeserializer.deserializeIrSymbolOrFail(idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol = + tryDeserializeIrSymbol(idSig, symbolKind) ?: deserializedSymbolNotFound(idSig) + // Used to resolve built in symbols like `kotlin.ir.internal.*` or `kotlin.FunctionN` class IrModuleDeserializerWithBuiltIns( private val builtIns: IrBuiltIns, @@ -199,16 +203,17 @@ class IrModuleDeserializerWithBuiltIns( } } - override fun deserializeIrSymbol(idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol { + override fun tryDeserializeIrSymbol(idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol? { irBuiltInsMap[idSig]?.let { return it } val topLevel = idSig.topLevelSignature() - if (checkIsFunctionInterface(topLevel)) return resolveFunctionalInterface(idSig, symbolKind) - return delegate.deserializeIrSymbol(idSig, symbolKind) + return delegate.tryDeserializeIrSymbol(idSig, symbolKind) } + override fun deserializedSymbolNotFound(idSig: IdSignature): Nothing = delegate.deserializedSymbolNotFound(idSig) + override fun declareIrSymbol(symbol: IrSymbol) { val signature = symbol.signature if (signature != null && checkIsFunctionInterface(signature)) @@ -253,11 +258,13 @@ open class CurrentModuleDeserializer( ) : IrModuleDeserializer(moduleFragment.descriptor, KotlinAbiVersion.CURRENT) { override fun contains(idSig: IdSignature): Boolean = false // TODO: - override fun deserializeIrSymbol(idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol { + override fun tryDeserializeIrSymbol(idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind): Nothing = error("Unreachable execution: there could not be back-links (sig: $idSig)") - } - override fun declareIrSymbol(symbol: IrSymbol) {} + override fun deserializedSymbolNotFound(idSig: IdSignature): Nothing = + error("Unreachable execution: there could not be back-links (sig: $idSig)") + + override fun declareIrSymbol(symbol: IrSymbol) = Unit override val kind get() = IrModuleDeserializerKind.CURRENT } 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 97734f1274f..fcfa69c3972 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 @@ -9,7 +9,6 @@ import org.jetbrains.kotlin.backend.common.overrides.FakeOverrideBuilder import org.jetbrains.kotlin.backend.common.overrides.FileLocalAwareLinker import org.jetbrains.kotlin.backend.common.serialization.encodings.BinarySymbolData import org.jetbrains.kotlin.backend.common.serialization.linkerissues.* -import org.jetbrains.kotlin.backend.common.serialization.unlinked.UnlinkedDeclarationsProcessor import org.jetbrains.kotlin.backend.common.serialization.unlinked.UnlinkedDeclarationsSupport import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor import org.jetbrains.kotlin.descriptors.DeclarationDescriptor @@ -19,14 +18,7 @@ import org.jetbrains.kotlin.ir.builders.TranslationPluginContext import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.linkage.IrDeserializer import org.jetbrains.kotlin.ir.symbols.* -import org.jetbrains.kotlin.ir.types.IrErrorType -import org.jetbrains.kotlin.ir.types.IrSimpleType -import org.jetbrains.kotlin.ir.types.IrType -import org.jetbrains.kotlin.ir.types.IrTypeProjection import org.jetbrains.kotlin.ir.util.* -import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid -import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid -import org.jetbrains.kotlin.library.KotlinAbiVersion import org.jetbrains.kotlin.library.KotlinLibrary import org.jetbrains.kotlin.library.uniqueName import org.jetbrains.kotlin.name.Name @@ -59,34 +51,36 @@ abstract class KotlinIrLinker( private lateinit var linkerExtensions: Collection - protected open val unlinkedDeclarationsSupport: UnlinkedDeclarationsSupport = UnlinkedDeclarationsSupport.DISABLED - protected open val userVisibleIrModulesSupport: UserVisibleIrModulesSupport = UserVisibleIrModulesSupport.DEFAULT + protected open val unlinkedDeclarationsSupport: UnlinkedDeclarationsSupport get() = UnlinkedDeclarationsSupport.DISABLED + protected open val userVisibleIrModulesSupport: UserVisibleIrModulesSupport get() = UserVisibleIrModulesSupport.DEFAULT - fun handleSignatureIdNotFoundInModuleWithDependencies( + fun deserializeOrReturnUnboundIrSymbolIfPartialLinkageEnabled( idSignature: IdSignature, + symbolKind: BinarySymbolData.SymbolKind, moduleDeserializer: IrModuleDeserializer - ): IrModuleDeserializer { - if (unlinkedDeclarationsSupport.allowUnboundSymbols) { - return object : IrModuleDeserializer(null, KotlinAbiVersion.CURRENT) { - override fun contains(idSig: IdSignature): Boolean = false + ): IrSymbol { + val topLevelSignature: IdSignature = idSignature.topLevelSignature() - override fun deserializeIrSymbol(idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol { - return referenceDeserializedSymbol(symbolTable, null, symbolKind, idSig) - } + // Note: The top-level symbol might be gone in newer version of dependency KLIB. Then the KLIB that was compiled against + // the older version of dependency KLIB will still have a reference to non-existing symbol. And the linker will have to + // handle such situation appropriately. See KT-41378. + val actualModuleDeserializer: IrModuleDeserializer? = moduleDeserializer.findModuleDeserializerForTopLevelId(topLevelSignature) - override val moduleFragment: IrModuleFragment - get() = TODO("Not yet implemented") - override val moduleDependencies: Collection get() = emptyList() - override val kind: IrModuleDeserializerKind - get() = TODO("Not yet implemented") - } - } else { - throw SignatureIdNotFoundInModuleWithDependencies( - idSignature = idSignature, - problemModuleDeserializer = moduleDeserializer, - allModuleDeserializers = deserializersForModules.values, - userVisibleIrModulesSupport = userVisibleIrModulesSupport - ).raiseIssue(messageLogger) + // Note: It might happen that the top-level symbol still exists in KLIB, but nested symbol has been removed. + // Then the `actualModuleDeserializer` will be non-null, but `actualModuleDeserializer.tryDeserializeIrSymbol()` call + // will return null. + val symbol: IrSymbol? = actualModuleDeserializer?.tryDeserializeIrSymbol(idSignature, symbolKind) + + return symbol ?: run { + if (unlinkedDeclarationsSupport.allowUnboundSymbols) + referenceDeserializedSymbol(symbolTable, null, symbolKind, idSignature) + else + throw SignatureIdNotFoundInModuleWithDependencies( + idSignature = idSignature, + problemModuleDeserializer = moduleDeserializer, + allModuleDeserializers = deserializersForModules.values, + userVisibleIrModulesSupport = userVisibleIrModulesSupport + ).raiseIssue(messageLogger) } } @@ -221,93 +215,16 @@ abstract class KotlinIrLinker( deserializersForModules.values.forEach { it.init() } } - - private fun markUnlinkedClassifiers(): Set { - if (!unlinkedDeclarationsSupport.allowUnboundSymbols) return emptySet() - val entries = fakeOverrideBuilder.fakeOverrideCandidates - val result = mutableSetOf() - - fun IrType.isUnlinked(visited: MutableSet): Boolean { - val simpleType = this as? IrSimpleType ?: return this !is IrErrorType - - val classifier = simpleType.classifier - - if (!classifier.isBound) { - return true - } - - if (classifier in result) { - return true - } - - if (!visited.add(classifier)) return false - - val superTypes = when (val decl = classifier.owner) { - is IrClass -> decl.superTypes - is IrTypeParameter -> decl.superTypes - else -> emptyList() - } - - if (superTypes.any { it.isUnlinked(visited) }) { - result.add(classifier) - return true - } - - for (ta in simpleType.arguments) { - if (ta is IrTypeProjection) { - val projected = ta.type - if (projected.isUnlinked(visited)) { - return true - } - } - } - - return false - } - - fun IrClass.isUnlinked(visited: MutableSet): Boolean { - if (symbol in result) return true - for (s in superTypes) { - if (s.isUnlinked(visited)) { - result.add(symbol) - return true - } - } - return false - } - - val toRemove = mutableListOf() - - for (e in entries) { - val klass = e.key - if (klass.isUnlinked(mutableSetOf())) { - toRemove.add(klass) - } - } - - toRemove.forEach { entries.remove(it) } - - return result - } - - private fun applyToModules(transformer: IrElementTransformerVoid) { - deserializersForModules.values.forEach { it.moduleFragment.transformChildrenVoid(transformer) } - } - override fun postProcess() { finalizeExpectActualLinker() - val unlinkedClassifiers = markUnlinkedClassifiers() + unlinkedDeclarationsSupport.markUsedClassifiersExcludingUnlinkedFromFakeOverrideBuilding(fakeOverrideBuilder) fakeOverrideBuilder.provideFakeOverrides() triedToDeserializeDeclarationForSymbol.clear() - unlinkedDeclarationsSupport.whenUnboundSymbolsAllowed { unlinkedMarkerTypeHandler -> - val t = UnlinkedDeclarationsProcessor(builtIns, unlinkedClassifiers, unlinkedMarkerTypeHandler, messageLogger) - t.addLinkageErrorIntoUnlinkedClasses() - - applyToModules(t.signatureTransformer()) - applyToModules(t.usageTransformer()) + unlinkedDeclarationsSupport.processUnlinkedDeclarations(messageLogger) { + deserializersForModules.values.map { it.moduleFragment } } // TODO: fix IrPluginContext to make it not produce additional external reference @@ -359,7 +276,7 @@ abstract class KotlinIrLinker( ?: error("No module for name '$moduleName' found") assert(signature == signature.topLevelSignature()) { "Signature '$signature' has to be top level" } if (signature !in moduleDeserializer) error("No signature $signature in module $moduleName") - return moduleDeserializer.deserializeIrSymbol(signature, topLevelKindToSymbolKind(kind)).also { + return moduleDeserializer.deserializeIrSymbolOrFail(signature, topLevelKindToSymbolKind(kind)).also { deserializeAllReachableTopLevels() } } diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/unlinked/BasicUnlinkedDeclarationsSupport.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/unlinked/BasicUnlinkedDeclarationsSupport.kt new file mode 100644 index 00000000000..a985983e4b5 --- /dev/null +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/unlinked/BasicUnlinkedDeclarationsSupport.kt @@ -0,0 +1,176 @@ +/* + * 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.unlinked + +import org.jetbrains.kotlin.backend.common.overrides.FakeOverrideBuilder +import org.jetbrains.kotlin.backend.common.serialization.unlinked.UsedClassifierSymbolStatus.* +import org.jetbrains.kotlin.descriptors.NotFoundClasses +import org.jetbrains.kotlin.ir.IrBuiltIns +import org.jetbrains.kotlin.ir.IrElement +import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.expressions.IrClassReference +import org.jetbrains.kotlin.ir.expressions.IrConstantObject +import org.jetbrains.kotlin.ir.expressions.IrExpression +import org.jetbrains.kotlin.ir.expressions.IrTypeOperatorCall +import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol +import org.jetbrains.kotlin.ir.types.IrErrorType +import org.jetbrains.kotlin.ir.types.IrSimpleType +import org.jetbrains.kotlin.ir.types.IrType +import org.jetbrains.kotlin.ir.types.IrTypeProjection +import org.jetbrains.kotlin.ir.util.IrMessageLogger +import org.jetbrains.kotlin.ir.util.parentClassOrNull +import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid +import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid +import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid + +abstract class BasicUnlinkedDeclarationsSupport : UnlinkedDeclarationsSupport { + protected abstract val handler: UnlinkedDeclarationsSupport.UnlinkedMarkerTypeHandler + protected abstract val builtIns: IrBuiltIns + + private val usedClassifierSymbols = UsedClassifierSymbols() + + final override fun markUsedClassifiersExcludingUnlinkedFromFakeOverrideBuilding(fakeOverrideBuilder: FakeOverrideBuilder) { + if (!allowUnboundSymbols) return + + val entries = fakeOverrideBuilder.fakeOverrideCandidates + if (entries.isEmpty()) return + + val toRemove = hashSetOf() + for (clazz in entries.keys) { + if (clazz.symbol.isUnlinkedClassifier(visited = hashSetOf())) { + toRemove += clazz + } + } + + entries -= toRemove + } + + private fun IrType.isUnlinkedType(visited: MutableSet): Boolean { + val simpleType = this as? IrSimpleType ?: return this !is IrErrorType + + if (simpleType.classifier.isUnlinkedClassifier(visited)) + return true + + for (argument in simpleType.arguments) { + if (argument is IrTypeProjection) { + if (argument.type.isUnlinkedType(visited)) + return true + } + } + + return false + } + + private fun IrClassifierSymbol.isUnlinkedClassifier(visited: MutableSet): Boolean { + when (val status = usedClassifierSymbols[this]) { + UNLINKED, LINKED -> return status.isUnlinked + null -> { + // Unknown classifier. Continue. + } + } + + if (!isBound || (hasDescriptor && descriptor is NotFoundClasses.MockClassDescriptor)) + return usedClassifierSymbols.register(this, UNLINKED) + + if (!visited.add(this)) + return false // Recursion avoidance. + + when (val classifier = owner) { + is IrClass -> { + if (classifier.parentClassOrNull?.symbol?.isUnlinkedClassifier(visited) == true) + return usedClassifierSymbols.register(this, UNLINKED) + + for (typeParameter in classifier.typeParameters) { + if (typeParameter.superTypes.any { it.isUnlinkedType(visited) }) + return usedClassifierSymbols.register(this, UNLINKED) + } + + if (classifier.superTypes.any { it.isUnlinkedType(visited) }) + return usedClassifierSymbols.register(this, UNLINKED) + } + is IrTypeParameter -> { + if (classifier.superTypes.any { it.isUnlinkedType(visited) }) + return usedClassifierSymbols.register(this, UNLINKED) + } + } + + return usedClassifierSymbols.register(this, LINKED) + } + + override fun markUsedClassifiersInInlineLazyIrFunction(function: IrFunction) { + if (!allowUnboundSymbols) return + + function.acceptChildrenVoid(object : IrElementVisitorVoid { + override fun visitElement(element: IrElement) { + element.acceptChildrenVoid(this) + } + + fun visitType(type: IrType?) { + type?.isUnlinkedType(visited = hashSetOf()) + } + + override fun visitValueParameter(declaration: IrValueParameter) { + visitType(declaration.type) + super.visitValueParameter(declaration) + } + + override fun visitTypeParameter(declaration: IrTypeParameter) { + declaration.superTypes.forEach(::visitType) + super.visitTypeParameter(declaration) + } + + override fun visitFunction(declaration: IrFunction) { + visitType(declaration.returnType) + super.visitFunction(declaration) + } + + override fun visitField(declaration: IrField) { + visitType(declaration.type) + super.visitField(declaration) + } + + override fun visitVariable(declaration: IrVariable) { + visitType(declaration.type) + super.visitVariable(declaration) + } + + override fun visitExpression(expression: IrExpression) { + visitType(expression.type) + super.visitExpression(expression) + } + + override fun visitClassReference(expression: IrClassReference) { + visitType(expression.classType) + super.visitClassReference(expression) + } + + override fun visitConstantObject(expression: IrConstantObject) { + expression.typeArguments.forEach(::visitType) + super.visitConstantObject(expression) + } + + override fun visitTypeOperator(expression: IrTypeOperatorCall) { + visitType(expression.typeOperand) + super.visitTypeOperator(expression) + } + }) + } + + override fun processUnlinkedDeclarations(messageLogger: IrMessageLogger, lazyRoots: () -> List) { + if (!allowUnboundSymbols) return + + val processor = UnlinkedDeclarationsProcessor(builtIns, usedClassifierSymbols, handler, messageLogger) + processor.addLinkageErrorIntoUnlinkedClasses() + + val roots = lazyRoots() + + val signatureTransformer = processor.signatureTransformer() + roots.forEach { it.transformChildrenVoid(signatureTransformer) } + + val usageTransformer = processor.usageTransformer() + roots.forEach { it.transformChildrenVoid(usageTransformer) } + } +} diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/unlinked/UnlinkedDeclarationsProcessor.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/unlinked/UnlinkedDeclarationsProcessor.kt index dcd600795df..1fae64ed09c 100644 --- a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/unlinked/UnlinkedDeclarationsProcessor.kt +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/unlinked/UnlinkedDeclarationsProcessor.kt @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.backend.common.serialization.unlinked import org.jetbrains.kotlin.backend.common.serialization.unlinked.UnlinkedDeclarationsSupport.UnlinkedMarkerTypeHandler +import org.jetbrains.kotlin.backend.common.serialization.unlinked.UsedClassifierSymbolStatus.Companion.isUnlinked import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.ir.IrBuiltIns import org.jetbrains.kotlin.ir.IrElement @@ -27,39 +28,34 @@ import org.jetbrains.kotlin.name.Name internal class UnlinkedDeclarationsProcessor( private val builtIns: IrBuiltIns, - private val unlinkedClassifiers: Set, + private val usedClassifierSymbols: UsedClassifierSymbols, private val unlinkedMarkerTypeHandler: UnlinkedMarkerTypeHandler, private val messageLogger: IrMessageLogger ) { - companion object { - private val errorOrigin = object : IrStatementOriginImpl("LINKAGE ERROR") {} + private val ERROR_ORIGIN = object : IrStatementOriginImpl("LINKAGE ERROR") {} } fun addLinkageErrorIntoUnlinkedClasses() { - for (u in unlinkedClassifiers) { - if (u is IrClassSymbol) { - val klass = u.owner - val anonInitializer = klass.declarations.firstOrNull { it is IrAnonymousInitializer } as IrAnonymousInitializer? ?: run { - builtIns.irFactory.createAnonymousInitializer( - klass.startOffset, - klass.endOffset, - IrDeclarationOrigin.DEFINED, - IrAnonymousInitializerSymbolImpl() - ).also { - it.body = builtIns.irFactory.createBlockBody(klass.startOffset, klass.endOffset) - it.parent = klass - klass.declarations.add(it) - } + usedClassifierSymbols.forEachClassSymbolToPatch { unlinkedSymbol -> + val clazz = unlinkedSymbol.owner + clazz.reportUnlinkedSymbolsWarning("Class", clazz.fqNameForIrSerialization) + + val anonInitializer = clazz.declarations.firstNotNullOfOrNull { it as? IrAnonymousInitializer } + ?: builtIns.irFactory.createAnonymousInitializer( + clazz.startOffset, + clazz.endOffset, + IrDeclarationOrigin.DEFINED, + IrAnonymousInitializerSymbolImpl() + ).also { + it.body = builtIns.irFactory.createBlockBody(clazz.startOffset, clazz.endOffset) + it.parent = clazz + clazz.declarations.add(it) } - anonInitializer.body.statements.clear() + anonInitializer.body.statements.clear() + anonInitializer.body.statements.add(clazz.throwLinkageError(clazz.symbol)) - klass.reportUnlinkedSymbolsWarning("Class", klass.fqNameForIrSerialization) - - anonInitializer.body.statements.add(klass.throwLinkageError(klass.symbol)) - - klass.superTypes = klass.superTypes.filter { !it.isUnlinked() } - } + clazz.superTypes = clazz.superTypes.filter { !it.isUnlinked() } } } @@ -255,7 +251,7 @@ internal class UnlinkedDeclarationsProcessor( return false } - private fun IrClassifierSymbol.isUnlinked(): Boolean = !isBound || this in unlinkedClassifiers + private fun IrClassifierSymbol.isUnlinked(): Boolean = !isBound || usedClassifierSymbols[this].isUnlinked private fun IrType.isUnlinked(): Boolean { val simpleType = this as? IrSimpleType ?: return false @@ -287,7 +283,7 @@ internal class UnlinkedDeclarationsProcessor( private fun IrElement.throwLinkageError(unlinkedSymbol: IrSymbol?, message: String = "Unlinked IR symbol"): IrCall { val messageLiteral = message + unlinkedSymbol?.signature?.render()?.let { " $it" }.orEmpty() - val irCall = IrCallImpl(startOffset, endOffset, builtIns.nothingType, builtIns.linkageErrorSymbol, 0, 1, errorOrigin) + val irCall = IrCallImpl(startOffset, endOffset, builtIns.nothingType, builtIns.linkageErrorSymbol, 0, 1, ERROR_ORIGIN) irCall.putValueArgument(0, IrConstImpl.string(startOffset, endOffset, builtIns.stringType, messageLiteral)) return irCall } @@ -338,7 +334,7 @@ internal class UnlinkedDeclarationsProcessor( if (!symbol.isUnlinked() && !expression.type.isUnlinked()) return expression reportWarning( - "Accessing declaration contains unlinked symbol ${symbol.signature?.render() ?: ""}", + "Accessing declaration with unlinked symbol ${symbol.signature?.render() ?: ""}", currentFile?.location(expression.startOffset) ) diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/unlinked/UnlinkedDeclarationsSupport.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/unlinked/UnlinkedDeclarationsSupport.kt index b81facc801e..db0f1ee6c9f 100644 --- a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/unlinked/UnlinkedDeclarationsSupport.kt +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/unlinked/UnlinkedDeclarationsSupport.kt @@ -5,11 +5,22 @@ package org.jetbrains.kotlin.backend.common.serialization.unlinked +import org.jetbrains.kotlin.backend.common.overrides.FakeOverrideBuilder +import org.jetbrains.kotlin.ir.IrElement +import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.types.IrType +import org.jetbrains.kotlin.ir.util.IrMessageLogger interface UnlinkedDeclarationsSupport { val allowUnboundSymbols: Boolean - fun whenUnboundSymbolsAllowed(action: (UnlinkedMarkerTypeHandler) -> T): T? + + /** For general use in IR linker. */ + fun markUsedClassifiersExcludingUnlinkedFromFakeOverrideBuilding(fakeOverrideBuilder: FakeOverrideBuilder) + + /** For local use only in inline lazy-IR functions. */ + fun markUsedClassifiersInInlineLazyIrFunction(function: IrFunction) + + fun processUnlinkedDeclarations(messageLogger: IrMessageLogger, lazyRoots: () -> List) interface UnlinkedMarkerTypeHandler { val unlinkedMarkerType: IrType @@ -19,7 +30,9 @@ interface UnlinkedDeclarationsSupport { companion object { val DISABLED = object : UnlinkedDeclarationsSupport { override val allowUnboundSymbols get() = false - override fun whenUnboundSymbolsAllowed(action: (UnlinkedMarkerTypeHandler) -> T): T? = null + override fun markUsedClassifiersExcludingUnlinkedFromFakeOverrideBuilding(fakeOverrideBuilder: FakeOverrideBuilder) = Unit + override fun markUsedClassifiersInInlineLazyIrFunction(function: IrFunction) = Unit + override fun processUnlinkedDeclarations(messageLogger: IrMessageLogger, lazyRoots: () -> List) = Unit } } } diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/unlinked/UsedClassifierSymbols.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/unlinked/UsedClassifierSymbols.kt new file mode 100644 index 00000000000..8f39ba5321a --- /dev/null +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/unlinked/UsedClassifierSymbols.kt @@ -0,0 +1,60 @@ +/* + * 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.unlinked + +import gnu.trove.THashSet +import gnu.trove.TObjectByteHashMap +import org.jetbrains.kotlin.backend.common.serialization.unlinked.UsedClassifierSymbolStatus.* +import org.jetbrains.kotlin.ir.symbols.IrClassSymbol +import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol + +internal enum class UsedClassifierSymbolStatus(val isUnlinked: Boolean) { + /** IR symbol of unlinked classifier. */ + UNLINKED(true), + + /** IR symbol of linked classifier. */ + LINKED(false); + + companion object { + val UsedClassifierSymbolStatus?.isUnlinked: Boolean get() = this?.isUnlinked == true + } +} + +internal class UsedClassifierSymbols { + private val symbols = TObjectByteHashMap() + private val patchedSymbols = THashSet() // To avoid re-patching what already has been patched. + + fun forEachClassSymbolToPatch(patchAction: (IrClassSymbol) -> Unit) { + symbols.forEachEntry { symbol, code -> + if (symbol.isBound && code.status == UNLINKED && symbol is IrClassSymbol && patchedSymbols.add(symbol)) { + patchAction(symbol) + } + true + } + } + + operator fun get(symbol: IrClassifierSymbol): UsedClassifierSymbolStatus? = symbols[symbol].status + + fun register(symbol: IrClassifierSymbol, status: UsedClassifierSymbolStatus): Boolean { + symbols.put(symbol, status.code) + return status.isUnlinked + } + + companion object { + private inline val Byte.status: UsedClassifierSymbolStatus? + get() = when (this) { + 1.toByte() -> UNLINKED + 2.toByte() -> LINKED + else -> null + } + + private inline val UsedClassifierSymbolStatus.code: Byte + get() = when (this) { + UNLINKED -> 1.toByte() + LINKED -> 2.toByte() + } + } +} 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 0c2022ae738..0e73def67cc 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 @@ -376,7 +376,7 @@ fun getIrModuleInfoForKlib( val irBuiltIns = IrBuiltInsOverDescriptors(moduleDescriptor.builtIns, typeTranslator, symbolTable) val allowUnboundSymbols = configuration[JSConfigurationKeys.PARTIAL_LINKAGE] ?: false - val unlinkedDeclarationsSupport = JsUnlinkedDeclarationsSupport(allowUnboundSymbols) + val unlinkedDeclarationsSupport = JsUnlinkedDeclarationsSupport(irBuiltIns, allowUnboundSymbols) val irLinker = JsIrLinker( currentModule = null, @@ -435,7 +435,7 @@ fun getIrModuleInfoForSourceFiles( } val allowUnboundSymbols = configuration[JSConfigurationKeys.PARTIAL_LINKAGE] ?: false - val unlinkedDeclarationsSupport = JsUnlinkedDeclarationsSupport(allowUnboundSymbols) + val unlinkedDeclarationsSupport = JsUnlinkedDeclarationsSupport(irBuiltIns, allowUnboundSymbols) val irLinker = JsIrLinker( currentModule = psi2IrContext.moduleDescriptor, diff --git a/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/lower/serialization/ir/JsIrLinker.kt b/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/lower/serialization/ir/JsIrLinker.kt index 4df2ee40726..8cb040ac847 100644 --- a/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/lower/serialization/ir/JsIrLinker.kt +++ b/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/lower/serialization/ir/JsIrLinker.kt @@ -30,7 +30,10 @@ class JsIrLinker( override val translationPluginContext: TranslationPluginContext?, private val icData: ICData? = null, friendModules: Map> = emptyMap(), - override val unlinkedDeclarationsSupport: UnlinkedDeclarationsSupport = JsUnlinkedDeclarationsSupport(allowUnboundSymbols = false), + override val unlinkedDeclarationsSupport: UnlinkedDeclarationsSupport = JsUnlinkedDeclarationsSupport( + builtIns, + allowUnboundSymbols = false + ), private val stubGenerator: DeclarationStubGenerator? = null ) : KotlinIrLinker( currentModule = currentModule, diff --git a/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/lower/serialization/ir/JsLazyIrModuleDeserializer.kt b/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/lower/serialization/ir/JsLazyIrModuleDeserializer.kt index 38c13d3cfd5..a80b64384f9 100644 --- a/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/lower/serialization/ir/JsLazyIrModuleDeserializer.kt +++ b/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/lower/serialization/ir/JsLazyIrModuleDeserializer.kt @@ -35,12 +35,8 @@ class JsLazyIrModuleDeserializer( private val descriptorFinder = DescriptorByIdSignatureFinderImpl(moduleDescriptor, JsManglerDesc) - private fun resolveDescriptor(idSig: IdSignature): DeclarationDescriptor { - return descriptorFinder.findDescriptorBySignature(idSig) ?: error("No descriptor found for $idSig") - } - - override fun deserializeIrSymbol(idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol { - val descriptor = resolveDescriptor(idSig) + override fun tryDeserializeIrSymbol(idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol? { + val descriptor = descriptorFinder.findDescriptorBySignature(idSig) ?: return null val declaration = stubGenerator.run { when (symbolKind) { @@ -57,6 +53,8 @@ class JsLazyIrModuleDeserializer( return declaration.symbol } + override fun deserializedSymbolNotFound(idSig: IdSignature): Nothing = error("No descriptor found for $idSig") + @OptIn(ObsoleteDescriptorBasedAPI::class) override fun declareIrSymbol(symbol: IrSymbol) { if (symbol is IrFieldSymbol) { diff --git a/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/lower/serialization/ir/JsUnlinkedDeclarationsSupport.kt b/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/lower/serialization/ir/JsUnlinkedDeclarationsSupport.kt index 9449160a3e9..c83df235471 100644 --- a/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/lower/serialization/ir/JsUnlinkedDeclarationsSupport.kt +++ b/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/lower/serialization/ir/JsUnlinkedDeclarationsSupport.kt @@ -5,19 +5,20 @@ package org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir -import org.jetbrains.kotlin.backend.common.serialization.unlinked.UnlinkedDeclarationsSupport +import org.jetbrains.kotlin.backend.common.serialization.unlinked.BasicUnlinkedDeclarationsSupport import org.jetbrains.kotlin.backend.common.serialization.unlinked.UnlinkedDeclarationsSupport.UnlinkedMarkerTypeHandler +import org.jetbrains.kotlin.ir.IrBuiltIns import org.jetbrains.kotlin.ir.types.IrErrorType import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.impl.IrErrorTypeImpl import org.jetbrains.kotlin.types.Variance -class JsUnlinkedDeclarationsSupport(override val allowUnboundSymbols: Boolean) : UnlinkedDeclarationsSupport { - private val handler = object : UnlinkedMarkerTypeHandler { +class JsUnlinkedDeclarationsSupport( + override val builtIns: IrBuiltIns, + override val allowUnboundSymbols: Boolean +) : BasicUnlinkedDeclarationsSupport() { + override val handler = object : UnlinkedMarkerTypeHandler { override val unlinkedMarkerType = IrErrorTypeImpl(null, emptyList(), Variance.INVARIANT) override fun IrType.isUnlinkedMarkerType() = this is IrErrorType } - - override fun whenUnboundSymbolsAllowed(action: (UnlinkedMarkerTypeHandler) -> T): T? = - if (allowUnboundSymbols) action(handler) else null } diff --git a/compiler/ir/serialization.jvm/src/org/jetbrains/kotlin/ir/backend/jvm/serialization/JvmIrLinker.kt b/compiler/ir/serialization.jvm/src/org/jetbrains/kotlin/ir/backend/jvm/serialization/JvmIrLinker.kt index fb173b7f32d..cc57fd30480 100644 --- a/compiler/ir/serialization.jvm/src/org/jetbrains/kotlin/ir/backend/jvm/serialization/JvmIrLinker.kt +++ b/compiler/ir/serialization.jvm/src/org/jetbrains/kotlin/ir/backend/jvm/serialization/JvmIrLinker.kt @@ -134,12 +134,10 @@ class JvmIrLinker( DescriptorByIdSignatureFinderImpl.LookupMode.MODULE_ONLY ) - private fun resolveDescriptor(idSig: IdSignature): DeclarationDescriptor { - return descriptorFinder.findDescriptorBySignature(idSig) ?: error("No descriptor found for $idSig") - } + private fun resolveDescriptor(idSig: IdSignature): DeclarationDescriptor? = descriptorFinder.findDescriptorBySignature(idSig) - override fun deserializeIrSymbol(idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol { - val descriptor = resolveDescriptor(idSig) + override fun tryDeserializeIrSymbol(idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol? { + val descriptor = resolveDescriptor(idSig) ?: return null val declaration = stubGenerator.run { when (symbolKind) { @@ -156,6 +154,8 @@ class JvmIrLinker( return declaration.symbol } + override fun deserializedSymbolNotFound(idSig: IdSignature): Nothing = error("No descriptor found for $idSig") + override fun declareIrSymbol(symbol: IrSymbol) { if (symbol is IrFieldSymbol) { declareJavaFieldStub(symbol) diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/interop/IrProviderForCEnumAndCStructStubs.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/interop/IrProviderForCEnumAndCStructStubs.kt index 7105b0592a5..20cbabe40bb 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/interop/IrProviderForCEnumAndCStructStubs.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/interop/IrProviderForCEnumAndCStructStubs.kt @@ -112,6 +112,7 @@ internal class IrProviderForCEnumAndCStructStubs( generateIrIfNeeded(s, file) s.owner } + // TODO: better error message? else -> error("Unexpected symbol kind $symbolKind for sig $idSignature") } } diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanIrlinker.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanIrlinker.kt index 4f08b3e8795..1155c49404e 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanIrlinker.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanIrlinker.kt @@ -606,8 +606,8 @@ internal class KonanIrLinker( return cenumsProvider.getDeclaration(descriptor, idSig, file, symbolKind).symbol } - override fun deserializeIrSymbol(idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol { - val descriptor = descriptorByIdSignatureFinder.findDescriptorBySignature(idSig) ?: error("Expecting descriptor for $idSig") + override fun tryDeserializeIrSymbol(idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol? { + val descriptor = descriptorByIdSignatureFinder.findDescriptorBySignature(idSig) ?: return null // If library is cached we don't need to create an IrClass for struct or enum. if (!isLibraryCached && descriptor.isCEnumsOrCStruct()) return resolveCEnumsOrStruct(descriptor, idSig, symbolKind) @@ -616,6 +616,8 @@ internal class KonanIrLinker( return symbolOwner.symbol } + override fun deserializedSymbolNotFound(idSig: IdSignature): Nothing = error("No descriptor found for $idSig") + override val moduleFragment: IrModuleFragment = KonanIrModuleFragmentImpl(moduleDescriptor, builtIns) override val moduleDependencies: Collection = listOfNotNull(forwardDeclarationDeserializer) @@ -664,6 +666,8 @@ internal class KonanIrLinker( return (stubGenerator.generateMemberStub(descriptor) as IrSymbolOwner).symbol } + override fun deserializedSymbolNotFound(idSig: IdSignature): Nothing = error("No descriptor found for $idSig") + private val inlineFunctionReferences by lazy { cachedLibraries.getLibraryCache(klib)!!.serializedInlineFunctionBodies.associateBy { fileDeserializationStates[it.file].declarationDeserializer.symbolDeserializer.deserializeIdSignature(it.functionSignature) @@ -673,7 +677,7 @@ internal class KonanIrLinker( fun deserializeInlineFunction(function: IrFunction): InlineFunctionOriginInfo { val packageFragment = function.getPackageFragment() as? IrExternalPackageFragment ?: error("Expected an external package fragment for ${function.render()}") - if (function.parents.any { (it as? IrFunction)?.isInline == true}) { + if (function.parents.any { (it as? IrFunction)?.isInline == true }) { // Already deserialized by the top-most inline function. return InlineFunctionOriginInfo( function, @@ -742,8 +746,13 @@ internal class KonanIrLinker( } } + unlinkedDeclarationsSupport.markUsedClassifiersExcludingUnlinkedFromFakeOverrideBuilding(fakeOverrideBuilder) + unlinkedDeclarationsSupport.markUsedClassifiersInInlineLazyIrFunction(function) + fakeOverrideBuilder.provideFakeOverrides() + unlinkedDeclarationsSupport.processUnlinkedDeclarations(linker.messageLogger) { listOf(function) } + return InlineFunctionOriginInfo(function, fileDeserializationState.file, inlineFunctionReference.startOffset, inlineFunctionReference.endOffset) } @@ -829,10 +838,10 @@ internal class KonanIrLinker( override fun contains(idSig: IdSignature): Boolean = idSig.isForwardDeclarationSignature() - private fun resolveDescriptor(idSig: IdSignature): ClassDescriptor = + private fun resolveDescriptor(idSig: IdSignature): ClassDescriptor? = with(idSig as IdSignature.CommonSignature) { val classId = ClassId(packageFqName(), FqName(declarationFqName), false) - moduleDescriptor.findClassAcrossModuleDependencies(classId) ?: error("No declaration found with $idSig") + moduleDescriptor.findClassAcrossModuleDependencies(classId) } private fun buildForwardDeclarationStub(descriptor: ClassDescriptor): IrClass { @@ -841,11 +850,11 @@ internal class KonanIrLinker( } } - override fun deserializeIrSymbol(idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol { + override fun tryDeserializeIrSymbol(idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol? { require(symbolKind == BinarySymbolData.SymbolKind.CLASS_SYMBOL) { "Only class could be a Forward declaration $idSig (kind $symbolKind)" } - val descriptor = resolveDescriptor(idSig) + val descriptor = resolveDescriptor(idSig) ?: return null val actualModule = descriptor.module if (actualModule !== moduleDescriptor) { val moduleDeserializer = resolveModuleDeserializer(actualModule, idSig) @@ -856,6 +865,8 @@ internal class KonanIrLinker( return declaredDeclaration.getOrPut(idSig) { buildForwardDeclarationStub(descriptor) }.symbol } + override fun deserializedSymbolNotFound(idSig: IdSignature): Nothing = error("No descriptor found for $idSig") + override val moduleFragment: IrModuleFragment = KonanIrModuleFragmentImpl(moduleDescriptor, builtIns) override val moduleDependencies: Collection = emptyList() diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanUnlinkedDeclarationsSupport.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanUnlinkedDeclarationsSupport.kt index 77b7ca326e7..c9b51155ae0 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanUnlinkedDeclarationsSupport.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanUnlinkedDeclarationsSupport.kt @@ -5,7 +5,7 @@ package org.jetbrains.kotlin.backend.konan.serialization -import org.jetbrains.kotlin.backend.common.serialization.unlinked.UnlinkedDeclarationsSupport +import org.jetbrains.kotlin.backend.common.serialization.unlinked.BasicUnlinkedDeclarationsSupport import org.jetbrains.kotlin.backend.common.serialization.unlinked.UnlinkedDeclarationsSupport.UnlinkedMarkerTypeHandler import org.jetbrains.kotlin.ir.IrBuiltIns import org.jetbrains.kotlin.ir.types.IrErrorType @@ -16,10 +16,13 @@ import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl * Kotlin/Native backend does not support [IrErrorType]. * So, let's use a special instance of nullable [kotlin.Any] as a marker-type instead. */ -class KonanUnlinkedDeclarationsSupport(irBuiltIns: IrBuiltIns, override val allowUnboundSymbols: Boolean) : UnlinkedDeclarationsSupport { - private val handler = object : UnlinkedMarkerTypeHandler { +class KonanUnlinkedDeclarationsSupport( + override val builtIns: IrBuiltIns, + override val allowUnboundSymbols: Boolean +) : BasicUnlinkedDeclarationsSupport() { + override val handler = object : UnlinkedMarkerTypeHandler { override val unlinkedMarkerType = IrSimpleTypeImpl( - classifier = irBuiltIns.anyClass, + classifier = builtIns.anyClass, hasQuestionMark = true, arguments = emptyList(), annotations = emptyList() @@ -27,7 +30,4 @@ class KonanUnlinkedDeclarationsSupport(irBuiltIns: IrBuiltIns, override val allo override fun IrType.isUnlinkedMarkerType(): Boolean = this === unlinkedMarkerType } - - override fun whenUnboundSymbolsAllowed(action: (UnlinkedMarkerTypeHandler) -> T): T? = - if (allowUnboundSymbols) action(handler) else null } \ No newline at end of file