diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compiler.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compiler.kt index a557184f5cc..7975b573b98 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compiler.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compiler.kt @@ -21,8 +21,6 @@ import org.jetbrains.kotlin.ir.declarations.StageController import org.jetbrains.kotlin.ir.declarations.stageController import org.jetbrains.kotlin.ir.util.DeclarationStubGenerator import org.jetbrains.kotlin.ir.util.ExternalDependenciesGenerator -import org.jetbrains.kotlin.ir.util.generateTypicalIrProviderList -import org.jetbrains.kotlin.ir.util.patchDeclarationParents import org.jetbrains.kotlin.library.KotlinLibrary import org.jetbrains.kotlin.library.resolver.KotlinLibraryResolveResult import org.jetbrains.kotlin.name.FqName diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/Psi2IrTranslator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/Psi2IrTranslator.kt index 58ec79838bc..32cf4bf2994 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/Psi2IrTranslator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/Psi2IrTranslator.kt @@ -83,11 +83,14 @@ class Psi2IrTranslator( expectDescriptorToSymbol?.let { referenceExpectsForUsedActuals(it, context.symbolTable, irModule) } postprocess(context, irModule) - irProviders.filterIsInstance().forEach { it.init(irModule) } + val deserializers = irProviders.filterIsInstance() + deserializers.forEach { it.init(irModule) } moduleGenerator.generateUnboundSymbolsAsDependencies(irProviders) + deserializers.forEach { it.postProcess() } assert(context.symbolTable.allUnbound.isEmpty()) + postprocessingSteps.forEach { it.invoke(irModule) } // assert(context.symbolTable.allUnbound.isEmpty()) // TODO: fix IrPluginContext to make it not produce additional external reference diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/descriptors/IrFunctionFactory.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/descriptors/IrFunctionFactory.kt index 9b22e20a1cb..ebfea51e183 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/descriptors/IrFunctionFactory.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/descriptors/IrFunctionFactory.kt @@ -333,6 +333,7 @@ class IrFunctionFactory(private val irBuiltIns: IrBuiltIns, private val symbolTa declarations += fDeclaration } + // TODO: eventualy delegate it to fakeOverrideBuilder addFakeOverrides() } @@ -454,11 +455,11 @@ class IrFunctionFactory(private val irBuiltIns: IrBuiltIns, private val symbolTa buildSimpleType() }) - klass.createMembers(isK, isSuspend, n, klass.name.identifier, descriptorFactory) - klass.parent = packageFragment packageFragment.declarations += klass + klass.createMembers(isK, isSuspend, n, klass.name.identifier, descriptorFactory) + return klass } } \ No newline at end of file diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/ExternalDependenciesGenerator.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/ExternalDependenciesGenerator.kt index 77b56b8d9c8..e1b69c364a8 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/ExternalDependenciesGenerator.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/ExternalDependenciesGenerator.kt @@ -18,9 +18,11 @@ package org.jetbrains.kotlin.ir.util import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.config.LanguageVersionSettings +import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.ir.declarations.IrDeclaration import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns +import org.jetbrains.kotlin.ir.descriptors.WrappedDeclarationDescriptor import org.jetbrains.kotlin.ir.symbols.IrSymbol import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult @@ -42,8 +44,10 @@ class ExternalDependenciesGenerator( /* Deserializing a reference may lead to new unbound references, so we loop until none are left. */ - lateinit var unbound: List + var unbound = setOf() + lateinit var prevUnbound: Set do { + prevUnbound = unbound unbound = symbolTable.allUnbound for (symbol in unbound) { @@ -51,16 +55,16 @@ class ExternalDependenciesGenerator( if (!symbol.isBound) { irProviders.getDeclaration(symbol) } - assert(symbol.isBound) { "$symbol unbound even after deserialization attempt" } } - } while (unbound.isNotEmpty()) + // We wait for the unbound to stabilize on fake overrides. + } while (unbound != prevUnbound) } } -fun List.getDeclaration(symbol: IrSymbol): IrDeclaration = +fun List.getDeclaration(symbol: IrSymbol): IrDeclaration? = firstNotNullResult { provider -> provider.getDeclaration(symbol) - } ?: error("Could not find declaration for unbound symbol $symbol") + } // In most cases, IrProviders list consist of an optional deserializer and a DeclarationStubGenerator. fun generateTypicalIrProviderList( diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/SymbolTable.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/SymbolTable.kt index 4bacc12561f..41426a0d9c9 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/SymbolTable.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/SymbolTable.kt @@ -18,13 +18,13 @@ package org.jetbrains.kotlin.ir.util -import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.impl.* -import org.jetbrains.kotlin.ir.declarations.lazy.IrLazyDeclarationBase import org.jetbrains.kotlin.ir.declarations.lazy.IrLazySymbolTable -import org.jetbrains.kotlin.ir.descriptors.* +import org.jetbrains.kotlin.ir.descriptors.WrappedDeclarationDescriptor +import org.jetbrains.kotlin.ir.descriptors.WrappedFunctionDescriptorWithContainerSource +import org.jetbrains.kotlin.ir.descriptors.WrappedPropertyDescriptorWithContainerSource import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrExpressionBody import org.jetbrains.kotlin.ir.symbols.* @@ -37,10 +37,6 @@ interface IrProvider { fun getDeclaration(symbol: IrSymbol): IrDeclaration? } -interface IrExtensionGenerator { - fun declare(symbol: IrSymbol): IrDeclaration? = null -} - interface IrDeserializer : IrProvider { fun init(moduleFragment: IrModuleFragment?) {} fun postProcess() {} @@ -950,9 +946,9 @@ inline fun ReferenceSymbolTable.withReferenceScop return result } -val SymbolTable.allUnbound: List +val SymbolTable.allUnbound: Set get() { - val r = mutableListOf() + val r = mutableSetOf() r.addAll(unboundClasses) r.addAll(unboundConstructors) r.addAll(unboundEnumEntries) @@ -961,5 +957,15 @@ val SymbolTable.allUnbound: List r.addAll(unboundProperties) r.addAll(unboundTypeAliases) r.addAll(unboundTypeParameters) - return r.filter { !it.isBound } + return r.filter { !it.isBound }.toSet() } + +fun SymbolTable.noUnboundLeft(message: String) { + val unbound = this.allUnbound + assert(unbound.isEmpty()) { + "$message\n" + + unbound.map { + "$it ${if (it.isPublicApi) it.signature.toString() else "NON-PUBLIC API $it"}" + }.joinToString("\n") + } +} \ No newline at end of file diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/FakeOverrides.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/FakeOverrides.kt new file mode 100644 index 00000000000..8176d6e01e5 --- /dev/null +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/FakeOverrides.kt @@ -0,0 +1,169 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.backend.common.serialization + +import org.jetbrains.kotlin.backend.common.serialization.signature.IdSignatureSerializer +import org.jetbrains.kotlin.ir.IrElement +import org.jetbrains.kotlin.ir.declarations.IrClass +import org.jetbrains.kotlin.ir.declarations.IrFunction +import org.jetbrains.kotlin.ir.declarations.IrModuleFragment +import org.jetbrains.kotlin.ir.declarations.IrOverridableMember +import org.jetbrains.kotlin.ir.declarations.impl.IrFakeOverrideFunctionImpl +import org.jetbrains.kotlin.ir.declarations.impl.IrFakeOverridePropertyImpl +import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns +import org.jetbrains.kotlin.ir.descriptors.WrappedPropertyDescriptor +import org.jetbrains.kotlin.ir.descriptors.WrappedSimpleFunctionDescriptor +import org.jetbrains.kotlin.ir.symbols.IrClassSymbol +import org.jetbrains.kotlin.ir.symbols.IrSymbol +import org.jetbrains.kotlin.ir.types.IrSimpleType +import org.jetbrains.kotlin.ir.types.IrType +import org.jetbrains.kotlin.ir.types.getClass +import org.jetbrains.kotlin.ir.util.SymbolTable +import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid +import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid +import org.jetbrains.kotlin.ir.visitors.acceptVoid + +interface PlatformFakeOverrideClassFilter { + fun constructFakeOverrides(clazz: IrClass): Boolean = true +} + +object DefaultFakeOverrideClassFilter : PlatformFakeOverrideClassFilter + +object FakeOverrideControl { + // If set to true: all fake overrides go to klib serialized IR. + // If set to false: eligible fake overrides are not serialized. + val serializeFakeOverrides: Boolean = false + + // If set to true: fake overrides are deserialized from klib serialized IR. + // If set to false: eligible fake overrides are constructed within IR linker. + val deserializeFakeOverrides: Boolean = false +} + +class FakeOverrideBuilderImpl( + val symbolTable: SymbolTable, + val signaturer: IdSignatureSerializer, + val irBuiltIns: IrBuiltIns, + private val platformSpecificClassFilter: PlatformFakeOverrideClassFilter = DefaultFakeOverrideClassFilter +) : FakeOverrideBuilder, FakeOverrideBuilderStrategy { + private val haveFakeOverrides = mutableSetOf() + override val propertyOverriddenSymbols = mutableMapOf>() + private val irOverridingUtil = IrOverridingUtil(irBuiltIns, this) + + override fun fakeOverrideMember( + superType: IrType, + member: IrOverridableMember, + clazz: IrClass + ): IrOverridableMember { + require(superType is IrSimpleType) { "superType is $superType, expected IrSimpleType" } + val classifier = superType.classifier + require(classifier is IrClassSymbol) { "superType classifier is not IrClassSymbol: $classifier" } + + val typeParameters = classifier.owner.typeParameters.map { it.symbol } + val typeArguments = + superType.arguments.map { it as? IrSimpleType ?: error("Unexpected super type $it") } + + assert(typeParameters.size == typeArguments.size) { + "typeParameters = $typeParameters size != typeArguments = $typeArguments size " + } + + val substitutionMap = typeParameters.zip(typeArguments).toMap() + val copier = + DeepCopyIrTreeWithSymbolsForFakeOverrides(substitutionMap, superType, clazz) + + val deepCopyFakeOverride = copier.copy(member) as IrOverridableMember + deepCopyFakeOverride.parent = clazz + + return deepCopyFakeOverride + } + + fun buildFakeOverrideChainsForClass(clazz: IrClass) { + if (haveFakeOverrides.contains(clazz)) return + if (!platformSpecificClassFilter.constructFakeOverrides(clazz) || !clazz.symbol.isPublicApi) return + + val superTypes = clazz.superTypes + + val superClasses = superTypes.map { + it.getClass() ?: error("Unexpected super type: $it") + } + + superClasses.forEach { + buildFakeOverrideChainsForClass(it) + haveFakeOverrides.add(it) + } + + irOverridingUtil.buildFakeOverridesForClass(clazz) + } + + override fun buildFakeOverridesForClass(clazz: IrClass) = irOverridingUtil.buildFakeOverridesForClass(clazz) + + override fun linkFakeOverride(fakeOverride: IrOverridableMember) { + when (fakeOverride) { + is IrFakeOverrideFunctionImpl -> linkFunctionFakeOverride(fakeOverride) + is IrFakeOverridePropertyImpl -> linkPropertyFakeOverride(fakeOverride) + else -> error("Unexpected fake override: $fakeOverride") + } + } + + private fun linkFunctionFakeOverride(declaration: IrFakeOverrideFunctionImpl) { + val signature = signaturer.composePublicIdSignature(declaration) + + symbolTable.declareSimpleFunctionFromLinker(WrappedSimpleFunctionDescriptor(), signature) { + declaration.acquireSymbol(it) + declaration + } + } + + private fun linkPropertyFakeOverride(declaration: IrFakeOverridePropertyImpl) { + val signature = signaturer.composePublicIdSignature(declaration) + + symbolTable.declarePropertyFromLinker(WrappedPropertyDescriptor(), signature) { + declaration.acquireSymbol(it) + declaration + } + + declaration.getter?.let { + it.correspondingPropertySymbol = declaration.symbol + linkFunctionFakeOverride(it as? IrFakeOverrideFunctionImpl + ?: error("Unexpected fake override getter: $it") + ) + } + declaration.setter?.let { + it.correspondingPropertySymbol = declaration.symbol + linkFunctionFakeOverride(it as? IrFakeOverrideFunctionImpl + ?: error("Unexpected fake override setter: $it") + ) + } + } + + fun provideFakeOverrides(module: IrModuleFragment) { + module.acceptVoid(object : IrElementVisitorVoid { + override fun visitElement(element: IrElement) { + element.acceptChildrenVoid(this) + } + + override fun visitClass(declaration: IrClass) { + buildFakeOverrideChainsForClass(declaration) + haveFakeOverrides.add(declaration) + super.visitClass(declaration) + } + + override fun visitFunction(declaration: IrFunction) { + // Don't go for function local classes + } + }) + } +} 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 468529b54e4..d3789a41117 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 @@ -105,8 +105,8 @@ class CurrentModuleWithICDeserializer( icDeserializer.deserializeReachableDeclarations() } - override fun postProcess() { - icDeserializer.postProcess() + override fun postProcess(postProcessor: (IrModuleFragment) -> Unit) { + icDeserializer.postProcess(postProcessor) } private fun DeclarationDescriptor.isDirtyDescriptor(): Boolean { @@ -134,4 +134,6 @@ class CurrentModuleWithICDeserializer( get() = delegate.moduleFragment override val moduleDependencies: Collection get() = delegate.moduleDependencies + override val isCurrent: Boolean + get() = delegate.isCurrent } \ No newline at end of file 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 271fe350d7f..da6df2c86f8 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 @@ -104,7 +104,7 @@ import org.jetbrains.kotlin.backend.common.serialization.proto.PublicIdSignature import org.jetbrains.kotlin.backend.common.serialization.proto.AccessorIdSignature as ProtoAccessorIdSignature import org.jetbrains.kotlin.backend.common.serialization.proto.FileLocalIdSignature as ProtoFileLocalIdSignature -abstract class IrFileDeserializer(val logger: LoggingContext, val builtIns: IrBuiltIns, val symbolTable: SymbolTable, protected var deserializeBodies: Boolean) { +abstract class IrFileDeserializer(val logger: LoggingContext, val builtIns: IrBuiltIns, val symbolTable: SymbolTable, var constructFakeOverrides: Boolean, protected var deserializeBodies: Boolean) { abstract fun deserializeIrSymbolToDeclare(code: Long): Pair abstract fun deserializeIrSymbol(code: Long): IrSymbol @@ -1038,7 +1038,9 @@ abstract class IrFileDeserializer(val logger: LoggingContext, val builtIns: IrBu }.usingParent { typeParameters = deserializeTypeParameters(proto.typeParameterList, true) - proto.declarationList.mapTo(declarations) { deserializeDeclaration(it) } + proto.declarationList + //.filterNot { isSkippableFakeOverride(it) } + .mapTo(declarations) { deserializeDeclaration(it) } thisReceiver = deserializeIrValueParameter(proto.thisReceiver, -1) @@ -1363,6 +1365,26 @@ abstract class IrFileDeserializer(val logger: LoggingContext, val builtIns: IrBu return declaration } + // Depending on deserialization strategy we either deserialize public api fake overrides + // or reconstruct them after IR linker completes. + private fun isSkippableFakeOverride(proto: ProtoDeclaration): Boolean { + if (!constructFakeOverrides) return false + + val isFakeOverride = when (proto.declaratorCase!!) { + IR_FUNCTION -> FunctionFlags.decode(proto.irFunction.base.base.flags).isFakeOverride + IR_PROPERTY -> PropertyFlags.decode(proto.irProperty.base.flags).isFakeOverride + // Don't consider IR_FIELDS here. + else -> false + } + val isPublicApi = when (proto.declaratorCase!!) { + IR_FUNCTION -> deserializeIrSymbol(proto.irFunction.base.base.symbol).signature.isPublic + IR_PROPERTY -> deserializeIrSymbol(proto.irProperty.base.symbol).signature.isPublic + // Don't consider IR_FIELDS here. + else -> false + } + return isFakeOverride && isPublicApi + } + fun deserializeDeclaration(proto: ProtoDeclaration, parent: IrDeclarationParent) = usingParent(parent) { deserializeDeclaration(proto) diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrFileSerializer.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrFileSerializer.kt index d5dd390c55a..e39c9a9fd7d 100644 --- a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrFileSerializer.kt +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrFileSerializer.kt @@ -1121,7 +1121,7 @@ open class IrFileSerializer( .setName(serializeName(clazz.name)) clazz.declarations.forEach { - proto.addDeclaration(serializeDeclaration(it)) + if (memberNeedsSerialization(it)) proto.addDeclaration(serializeDeclaration(it)) } clazz.typeParameters.forEach { @@ -1211,6 +1211,16 @@ open class IrFileSerializer( open fun backendSpecificExplicitRoot(declaration: IrFunction) = false open fun backendSpecificExplicitRoot(declaration: IrClass) = false open fun keepOrderOfProperties(property: IrProperty): Boolean = !property.isConst + open fun backendSpecificSerializeAllMembers(irClass: IrClass) = false + + fun memberNeedsSerialization(member: IrDeclaration): Boolean { + assert(member.parent is IrClass) + if (FakeOverrideControl.serializeFakeOverrides) return true + if (backendSpecificSerializeAllMembers(member.parent as IrClass)) return true + // TODO: we can, probably, maintain a privacy bit while traversing the tree + // instead of running the parent hierarchy for isExported every time. + return !(member.isFakeOverride && declarationTable.isExportedDeclaration(member)) + } fun serializeIrFile(file: IrFile): SerializedIrFile { val topLevelDeclarations = mutableListOf() 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 93fdb37311c..c0810af731e 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 @@ -50,13 +50,17 @@ abstract class IrModuleDeserializer(val moduleDescriptor: ModuleDescriptor) { open fun deserializeReachableDeclarations() { error("Unsupported Operation") } - open fun postProcess() {} + open fun postProcess(postProcessor: (IrModuleFragment) -> Unit) { + postProcessor(moduleFragment) + } abstract val moduleFragment: IrModuleFragment abstract val moduleDependencies: Collection open val strategy: DeserializationStrategy = DeserializationStrategy.ONLY_DECLARATION_HEADERS + + open val isCurrent = false } // Used to resolve built in symbols like `kotlin.ir.internal.*` or `kotlin.FunctionN` @@ -178,8 +182,8 @@ class IrModuleDeserializerWithBuiltIns( else delegate.declareIrSymbol(symbol) } - override fun postProcess() { - delegate.postProcess() + override fun postProcess(postProcessor: (IrModuleFragment) -> Unit) { + delegate.postProcess(postProcessor) } override fun init() { @@ -198,6 +202,7 @@ class IrModuleDeserializerWithBuiltIns( override val moduleFragment: IrModuleFragment get() = delegate.moduleFragment override val moduleDependencies: Collection get() = delegate.moduleDependencies + override val isCurrent get() = delegate.isCurrent } open class CurrentModuleDeserializer( @@ -211,4 +216,8 @@ open class CurrentModuleDeserializer( } override fun declareIrSymbol(symbol: IrSymbol) {} -} \ No newline at end of file + + override fun postProcess(postProcessor: (IrModuleFragment) -> Unit) {} + + override val isCurrent = true +} 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 e9fa0d28843..2465d2efb97 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 @@ -23,6 +23,10 @@ import org.jetbrains.kotlin.ir.symbols.* import org.jetbrains.kotlin.ir.symbols.impl.* import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.impl.IrErrorTypeImpl +import org.jetbrains.kotlin.ir.util.IdSignature +import org.jetbrains.kotlin.ir.util.IrDeserializer +import org.jetbrains.kotlin.ir.util.NaiveSourceBasedFileEntryImpl +import org.jetbrains.kotlin.ir.util.SymbolTable import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.library.IrLibrary import org.jetbrains.kotlin.library.KotlinLibrary @@ -57,6 +61,10 @@ abstract class KotlinIrLinker( protected val deserializersForModules = mutableMapOf() + abstract val fakeOverrideBuilderImpl: FakeOverrideBuilderImpl + + private val haveSeen = mutableSetOf() + abstract inner class BasicIrModuleDeserializer(moduleDescriptor: ModuleDescriptor, override val klib: IrLibrary, override val strategy: DeserializationStrategy) : IrModuleDeserializer(moduleDescriptor) { @@ -133,8 +141,6 @@ abstract class KotlinIrLinker( } } - override fun postProcess() {} - override val moduleFragment: IrModuleFragment = IrModuleFragmentImpl(moduleDescriptor, builtIns, emptyList()) private fun deserializeIrFile(fileProto: ProtoFile, fileIndex: Int, moduleDeserializer: IrModuleDeserializer): IrFile { @@ -144,7 +150,13 @@ abstract class KotlinIrLinker( val fileEntry = NaiveSourceBasedFileEntryImpl(fileName, fileProto.fileEntry.lineStartOffsetsList.toIntArray()) val fileDeserializer = - IrDeserializerForFile(fileProto.annotationList, fileProto.actualsList, fileIndex, !strategy.needBodies, strategy.inlineBodies, moduleDeserializer).apply { + IrDeserializerForFile(fileProto.annotationList, + fileProto.actualsList, + fileIndex, + !strategy.needBodies, + strategy.inlineBodies, + !strategy.fakeOverrides, + moduleDeserializer).apply { // Explicitly exported declarations (e.g. top-level initializers) must be deserialized before all other declarations. // Thus we schedule their deserialization in deserializer's constructor. @@ -205,8 +217,9 @@ abstract class KotlinIrLinker( private val fileIndex: Int, onlyHeaders: Boolean, inlineBodies: Boolean, - private val moduleDeserializer: IrModuleDeserializer - ) : IrFileDeserializer(logger, builtIns, symbolTable, !onlyHeaders) { + constructFakeOverrrides: Boolean, + private val moduleDeserializer: IrModuleDeserializer, + ) : IrFileDeserializer(logger, builtIns, symbolTable, constructFakeOverrrides, !onlyHeaders) { private var fileLoops = mutableMapOf() @@ -338,7 +351,9 @@ abstract class KotlinIrLinker( private fun deserializeIrSymbolData(idSignature: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol { if (idSignature.isLocal) return deserializeIrLocalSymbolData(idSignature, symbolKind) - return findModuleDeserializer(idSignature).deserializeIrSymbol(idSignature, symbolKind) + return findModuleDeserializer(idSignature).deserializeIrSymbol(idSignature, symbolKind).also { + haveSeen.add(it) + } } override fun deserializeIrSymbolToDeclare(code: Long): Pair { @@ -482,6 +497,11 @@ abstract class KotlinIrLinker( private fun findDeserializedDeclarationForSymbol(symbol: IrSymbol): DeclarationDescriptor? { assert(symbol.isPublicApi || symbol.descriptor.module === currentModule || platformSpecificSymbol(symbol)) + if (haveSeen.contains(symbol)) { + return null + } + haveSeen.add(symbol) + val descriptor = symbol.descriptor val moduleDeserializer = resolveModuleDeserializer(descriptor.module) @@ -518,9 +538,11 @@ abstract class KotlinIrLinker( if (!symbol.isBound && symbol.owner.isExpectMember()) return null - assert(symbol.isBound) { - "getDeclaration: symbol $symbol is unbound, descriptor = ${symbol.descriptor}, signature = ${symbol.signature}" - } + if (!symbol.isBound) return null + + //assert(symbol.isBound) { + // "getDeclaration: symbol $symbol is unbound, descriptor = ${symbol.descriptor}, signature = ${symbol.signature}" + //} return symbol.owner as IrDeclaration } @@ -541,8 +563,15 @@ abstract class KotlinIrLinker( } override fun postProcess() { - deserializersForModules.values.forEach { it.postProcess() } finalizeExpectActualLinker() + + deserializersForModules.values.forEach { + it.postProcess { + fakeOverrideBuilderImpl.provideFakeOverrides(it) + } + } + + symbolTable.noUnboundLeft("unbound after fake overrides:") } // The issue here is that an expect can not trigger its actual deserialization by reachability @@ -621,10 +650,20 @@ abstract class KotlinIrLinker( deserializeIrModuleHeader(moduleDescriptor, kotlinLibrary, DeserializationStrategy.WITH_INLINE_BODIES) } -enum class DeserializationStrategy(val needBodies: Boolean, val explicitlyExported: Boolean, val theWholeWorld: Boolean, val inlineBodies: Boolean) { +enum class DeserializationStrategy( + val needBodies: Boolean, + val explicitlyExported: Boolean, + val theWholeWorld: Boolean, + val inlineBodies: Boolean, + val fakeOverrides: Boolean = FakeOverrideControl.deserializeFakeOverrides +) { ONLY_REFERENCED(true, false, false, true), ALL(true, true, true, true), EXPLICITLY_EXPORTED(true, true, false, true), ONLY_DECLARATION_HEADERS(false, false, false, false), WITH_INLINE_BODIES(false, false, false, true) } + +interface FakeOverrideBuilder { + fun buildFakeOverridesForClass(clazz: IrClass) +} 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 868356b74cd..f482fa857a9 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 @@ -6,10 +6,8 @@ package org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir import org.jetbrains.kotlin.backend.common.LoggingContext -import org.jetbrains.kotlin.backend.common.serialization.CurrentModuleWithICDeserializer -import org.jetbrains.kotlin.backend.common.serialization.DeserializationStrategy -import org.jetbrains.kotlin.backend.common.serialization.IrModuleDeserializer -import org.jetbrains.kotlin.backend.common.serialization.KotlinIrLinker +import org.jetbrains.kotlin.backend.common.serialization.* +import org.jetbrains.kotlin.backend.common.serialization.signature.IdSignatureSerializer import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.ir.declarations.IrModuleFragment import org.jetbrains.kotlin.ir.descriptors.IrAbstractFunctionFactory @@ -19,12 +17,14 @@ import org.jetbrains.kotlin.library.IrLibrary import org.jetbrains.kotlin.library.SerializedIrFile class JsIrLinker( - currentModule: ModuleDescriptor?, logger: LoggingContext, builtIns: IrBuiltIns, symbolTable: SymbolTable, + private val currentModule: ModuleDescriptor?, logger: LoggingContext, builtIns: IrBuiltIns, symbolTable: SymbolTable, override val functionalInteraceFactory: IrAbstractFunctionFactory, private val icData: List? = null ) : KotlinIrLinker(currentModule, logger, builtIns, symbolTable, emptyList()) { + override val fakeOverrideBuilderImpl = FakeOverrideBuilderImpl(symbolTable, IdSignatureSerializer(JsManglerIr), builtIns) + override fun isBuiltInModule(moduleDescriptor: ModuleDescriptor): Boolean = moduleDescriptor === moduleDescriptor.builtIns.builtInsModule @@ -43,4 +43,8 @@ class JsIrLinker( } return currentModuleDeserializer } + val modules + get() = deserializersForModules.values + .map { it.moduleFragment } + .filter { it.descriptor !== currentModule } } 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 4ce0df6a4d0..5f67c1b8a53 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 @@ -8,25 +8,30 @@ package org.jetbrains.kotlin.ir.backend.jvm.serialization import org.jetbrains.kotlin.backend.common.LoggingContext import org.jetbrains.kotlin.backend.common.serialization.* import org.jetbrains.kotlin.backend.common.serialization.encodings.BinarySymbolData +import org.jetbrains.kotlin.backend.common.serialization.signature.IdSignatureSerializer import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.konan.KlibModuleOrigin import org.jetbrains.kotlin.ir.declarations.IrField import org.jetbrains.kotlin.ir.declarations.IrModuleFragment import org.jetbrains.kotlin.ir.declarations.impl.IrModuleFragmentImpl -import org.jetbrains.kotlin.ir.descriptors.* +import org.jetbrains.kotlin.ir.descriptors.IrAbstractFunctionFactory +import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol import org.jetbrains.kotlin.ir.symbols.IrSymbol import org.jetbrains.kotlin.ir.util.DeclarationStubGenerator import org.jetbrains.kotlin.ir.util.IdSignature import org.jetbrains.kotlin.ir.util.SymbolTable import org.jetbrains.kotlin.library.IrLibrary -import org.jetbrains.kotlin.load.java.descriptors.* +import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor +import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor import org.jetbrains.kotlin.load.java.lazy.descriptors.LazyJavaPackageFragment import org.jetbrains.kotlin.name.Name class JvmIrLinker(currentModule: ModuleDescriptor?, logger: LoggingContext, builtIns: IrBuiltIns, symbolTable: SymbolTable, override val functionalInteraceFactory: IrAbstractFunctionFactory, private val stubGenerator: DeclarationStubGenerator, private val manglerDesc: JvmManglerDesc) : KotlinIrLinker(currentModule, logger, builtIns, symbolTable, emptyList()) { + override val fakeOverrideBuilderImpl = FakeOverrideBuilderImpl(symbolTable, IdSignatureSerializer(JvmManglerIr), builtIns) + private val javaName = Name.identifier("java") override fun isBuiltInModule(moduleDescriptor: ModuleDescriptor): Boolean =