[IR] Fix removal-of-abstract-fun IR linkage case
^KT-50771
This commit is contained in:
@@ -24,8 +24,13 @@ import org.jetbrains.kotlin.name.Name
|
||||
inline fun <reified T : IrElement> T.deepCopyWithSymbols(
|
||||
initialParent: IrDeclarationParent? = null,
|
||||
createCopier: (SymbolRemapper, TypeRemapper) -> DeepCopyIrTreeWithSymbols = ::DeepCopyIrTreeWithSymbols
|
||||
): T = deepCopyWithSymbols(initialParent, DeepCopySymbolRemapper(), createCopier)
|
||||
|
||||
inline fun <reified T : IrElement> T.deepCopyWithSymbols(
|
||||
initialParent: IrDeclarationParent?,
|
||||
symbolRemapper: DeepCopySymbolRemapper,
|
||||
createCopier: (SymbolRemapper, TypeRemapper) -> DeepCopyIrTreeWithSymbols = ::DeepCopyIrTreeWithSymbols
|
||||
): T {
|
||||
val symbolRemapper = DeepCopySymbolRemapper()
|
||||
acceptVoid(symbolRemapper)
|
||||
val typeRemapper = DeepCopyTypeRemapper(symbolRemapper)
|
||||
return transform(createCopier(symbolRemapper, typeRemapper), null).patchDeclarationParents(initialParent) as T
|
||||
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* 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.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
|
||||
internal inline fun <reified T : IrOverridableDeclaration<*>> T.deepCopyWithImplementedFakeOverrides(): T {
|
||||
val clazz = parentAsClass
|
||||
|
||||
return deepCopyWithSymbols(clazz, DeepCopySymbolRemapperPreservingSignatures()) { symbolRemapper, typeRemapper ->
|
||||
ImplementedFakeOverrideCopier(clazz, symbolRemapper, typeRemapper)
|
||||
}
|
||||
}
|
||||
|
||||
internal class ImplementedFakeOverrideCopier(
|
||||
private val clazz: IrClass,
|
||||
private val symbolRemapper: SymbolRemapper,
|
||||
private val typeRemapper: TypeRemapper
|
||||
) : DeepCopyIrTreeWithSymbols(symbolRemapper, typeRemapper) {
|
||||
override fun visitProperty(declaration: IrProperty): IrProperty =
|
||||
declaration.factory.createProperty(
|
||||
startOffset = declaration.startOffset,
|
||||
endOffset = declaration.endOffset,
|
||||
origin = MISSING_ABSTRACT_CALLABLE_MEMBER_IMPLEMENTATION, // Customized.
|
||||
symbol = symbolRemapper.getDeclaredProperty(declaration.symbol),
|
||||
name = declaration.name,
|
||||
visibility = declaration.visibility,
|
||||
modality = clazz.modality, // Customized.
|
||||
isVar = declaration.isVar,
|
||||
isConst = declaration.isConst,
|
||||
isLateinit = declaration.isLateinit,
|
||||
isDelegated = declaration.isDelegated,
|
||||
isExternal = declaration.isExternal,
|
||||
isExpect = declaration.isExpect,
|
||||
isFakeOverride = false, // Customized.
|
||||
containerSource = declaration.containerSource,
|
||||
).apply {
|
||||
overriddenSymbols = declaration.overriddenSymbols.map { symbolRemapper.getReferencedProperty(it) }
|
||||
copyAttributes(declaration)
|
||||
transformAnnotations(declaration)
|
||||
backingField = declaration.backingField?.transform()?.also { it.correspondingPropertySymbol = symbol }
|
||||
getter = declaration.getter?.transform()?.also { it.correspondingPropertySymbol = symbol }
|
||||
setter = declaration.setter?.transform()?.also { it.correspondingPropertySymbol = symbol }
|
||||
}
|
||||
|
||||
override fun visitSimpleFunction(declaration: IrSimpleFunction): IrSimpleFunction =
|
||||
declaration.factory.createFunction(
|
||||
startOffset = declaration.startOffset,
|
||||
endOffset = declaration.endOffset,
|
||||
origin = MISSING_ABSTRACT_CALLABLE_MEMBER_IMPLEMENTATION, // Customized.
|
||||
symbol = symbolRemapper.getDeclaredFunction(declaration.symbol),
|
||||
name = declaration.name,
|
||||
visibility = declaration.visibility,
|
||||
modality = clazz.modality, // Customized.
|
||||
returnType = declaration.returnType,
|
||||
isInline = declaration.isInline,
|
||||
isExternal = declaration.isExternal,
|
||||
isTailrec = declaration.isTailrec,
|
||||
isSuspend = declaration.isSuspend,
|
||||
isOperator = declaration.isOperator,
|
||||
isInfix = declaration.isInfix,
|
||||
isExpect = declaration.isExpect,
|
||||
isFakeOverride = false, // Customized.
|
||||
containerSource = declaration.containerSource,
|
||||
).apply {
|
||||
overriddenSymbols = declaration.overriddenSymbols.map { symbolRemapper.getReferencedFunction(it) as IrSimpleFunctionSymbol }
|
||||
contextReceiverParametersCount = declaration.contextReceiverParametersCount
|
||||
copyAttributes(declaration)
|
||||
transformAnnotations(this)
|
||||
copyTypeParametersFrom(declaration)
|
||||
typeRemapper.withinScope(this) {
|
||||
dispatchReceiverParameter = declaration.dispatchReceiverParameter?.transform()
|
||||
extensionReceiverParameter = declaration.extensionReceiverParameter?.transform()
|
||||
returnType = typeRemapper.remapType(declaration.returnType)
|
||||
valueParameters = declaration.valueParameters.transform()
|
||||
body = factory.createBlockBody(
|
||||
declaration.body?.startOffset ?: declaration.startOffset,
|
||||
declaration.body?.endOffset ?: declaration.endOffset
|
||||
) // the body should be empty
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val MISSING_ABSTRACT_CALLABLE_MEMBER_IMPLEMENTATION =
|
||||
object : IrDeclarationOriginImpl("MISSING_ABSTRACT_CALLABLE_MEMBER_IMPLEMENTATION", isSynthetic = true) {}
|
||||
+122
-47
@@ -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.descriptors.Modality
|
||||
import org.jetbrains.kotlin.ir.IrBuiltIns
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
@@ -19,11 +20,9 @@ import org.jetbrains.kotlin.ir.symbols.impl.IrAnonymousInitializerSymbolImpl
|
||||
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.fileOrNull
|
||||
import org.jetbrains.kotlin.ir.util.fqNameForIrSerialization
|
||||
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
|
||||
internal class UnlinkedDeclarationsProcessor(
|
||||
private val builtIns: IrBuiltIns,
|
||||
@@ -33,7 +32,7 @@ internal class UnlinkedDeclarationsProcessor(
|
||||
) {
|
||||
|
||||
companion object {
|
||||
val errorOrigin = object : IrStatementOriginImpl("LINKAGE ERROR") {}
|
||||
private val errorOrigin = object : IrStatementOriginImpl("LINKAGE ERROR") {}
|
||||
}
|
||||
|
||||
fun addLinkageErrorIntoUnlinkedClasses() {
|
||||
@@ -54,7 +53,7 @@ internal class UnlinkedDeclarationsProcessor(
|
||||
}
|
||||
anonInitializer.body.statements.clear()
|
||||
|
||||
klass.reportWarning("Class", klass.fqNameForIrSerialization.asString())
|
||||
klass.reportUnlinkedSymbolsWarning("Class", klass.fqNameForIrSerialization)
|
||||
|
||||
anonInitializer.body.statements.add(klass.throwLinkageError(klass.symbol))
|
||||
|
||||
@@ -75,8 +74,8 @@ internal class UnlinkedDeclarationsProcessor(
|
||||
return IrMessageLogger.Location("$module @ $fileName", lineNumber, columnNumber)
|
||||
}
|
||||
|
||||
private fun IrDeclaration.reportWarning(kind: String, fqn: String) {
|
||||
reportWarning("$kind declaration $fqn contains unlinked symbols", location())
|
||||
private fun IrDeclaration.reportUnlinkedSymbolsWarning(kind: String, fqn: FqName) {
|
||||
reportWarning("$kind declaration ${fqn.asString()} contains unlinked symbols", location())
|
||||
}
|
||||
|
||||
private fun reportWarning(message: String, location: IrMessageLogger.Location?) {
|
||||
@@ -86,54 +85,38 @@ internal class UnlinkedDeclarationsProcessor(
|
||||
fun signatureTransformer(): IrElementTransformerVoid = SignatureTransformer()
|
||||
|
||||
private inner class SignatureTransformer : IrElementTransformerVoid() {
|
||||
private val implementedFakeOverrideProperties = hashSetOf<IrProperty>()
|
||||
|
||||
private val IrFunction.isAccessorOfImplementedFakeOverrideProperty: Boolean
|
||||
get() = (this as? IrSimpleFunction)?.correspondingPropertySymbol?.owner in implementedFakeOverrideProperties
|
||||
|
||||
override fun visitProperty(declaration: IrProperty): IrStatement {
|
||||
val newProperty = declaration.replaceIfUnimplementedFakeOverride()
|
||||
|
||||
val isImplementedFakeOverride = newProperty != declaration
|
||||
if (isImplementedFakeOverride) implementedFakeOverrideProperties += newProperty
|
||||
|
||||
newProperty.transformChildrenVoid()
|
||||
|
||||
if (isImplementedFakeOverride) implementedFakeOverrideProperties -= newProperty
|
||||
|
||||
return newProperty
|
||||
}
|
||||
|
||||
override fun visitFunction(declaration: IrFunction): IrStatement {
|
||||
var linked = true
|
||||
fun IrValueParameter.fixType() {
|
||||
if (type.isUnlinked()) {
|
||||
linked = false
|
||||
type = unlinkedMarkerTypeHandler.unlinkedMarkerType
|
||||
defaultValue = null
|
||||
}
|
||||
varargElementType?.let {
|
||||
if (it.isUnlinked()) {
|
||||
varargElementType = unlinkedMarkerTypeHandler.unlinkedMarkerType
|
||||
}
|
||||
}
|
||||
}
|
||||
declaration.dispatchReceiverParameter?.fixType()
|
||||
declaration.extensionReceiverParameter?.fixType()
|
||||
declaration.valueParameters.forEach { it.fixType() }
|
||||
if (declaration.returnType.isUnlinked()) {
|
||||
linked = false
|
||||
declaration.returnType = unlinkedMarkerTypeHandler.unlinkedMarkerType
|
||||
}
|
||||
declaration.typeParameters.forEach {
|
||||
if (it.superTypes.any { s -> s.isUnlinked() }) {
|
||||
linked = false
|
||||
it.superTypes = listOf(unlinkedMarkerTypeHandler.unlinkedMarkerType)
|
||||
}
|
||||
}
|
||||
if (linked) {
|
||||
declaration.transformChildrenVoid()
|
||||
} else {
|
||||
declaration.reportWarning("Function", declaration.fqNameForIrSerialization.asString())
|
||||
val newFunction = declaration.replaceIfUnimplementedFakeOverride()
|
||||
val removedUnlinkedTypes = newFunction.fixUnlinkedTypes()
|
||||
|
||||
declaration.body?.let { body ->
|
||||
val bb = (body as IrBlockBody)
|
||||
bb.statements.clear()
|
||||
bb.statements.add(declaration.throwLinkageError(unlinkedSymbol = null, "Unlinked type in IR function signature"))
|
||||
}
|
||||
}
|
||||
return declaration
|
||||
val isImplementedFakeOverride = newFunction != declaration || declaration.isAccessorOfImplementedFakeOverrideProperty
|
||||
|
||||
return newFunction.transformBodyIfNecessary(isImplementedFakeOverride, removedUnlinkedTypes)
|
||||
}
|
||||
|
||||
override fun visitField(declaration: IrField): IrStatement {
|
||||
if (declaration.type.isUnlinked()) {
|
||||
|
||||
val fqn = declaration.correspondingPropertySymbol?.owner?.fqNameWhenAvailable ?: declaration.fqNameForIrSerialization
|
||||
val kind = if (declaration.correspondingPropertySymbol != null) "Property" else "Field"
|
||||
declaration.reportWarning(kind, fqn.asString())
|
||||
declaration.reportUnlinkedSymbolsWarning(kind, fqn)
|
||||
|
||||
declaration.type = unlinkedMarkerTypeHandler.unlinkedMarkerType
|
||||
declaration.initializer = null
|
||||
@@ -142,6 +125,98 @@ internal class UnlinkedDeclarationsProcessor(
|
||||
}
|
||||
return declaration
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces an [IrProperty] or [IrSimpleFunction] that is abstract fake override in non-abstract class
|
||||
* by the corresponding non-abstract IR element.
|
||||
*/
|
||||
private fun <T : IrDeclaration> T.replaceIfUnimplementedFakeOverride(): T {
|
||||
if (this !is IrOverridableDeclaration<*> || !isFakeOverride || modality != Modality.ABSTRACT) return this
|
||||
|
||||
val clazz = parentAsClass
|
||||
if (clazz.modality == Modality.ABSTRACT || clazz.modality == Modality.SEALED) return this
|
||||
|
||||
return deepCopyWithImplementedFakeOverrides()
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the set of all unlinked types encountered during transformation of the given [IrFunction].
|
||||
* Or empty set if there were no unlinked types.
|
||||
*/
|
||||
private fun IrFunction.fixUnlinkedTypes(): Set<IrType> = buildSet {
|
||||
fun IrValueParameter.fixType() {
|
||||
if (type.isUnlinked()) {
|
||||
this@buildSet += type
|
||||
type = unlinkedMarkerTypeHandler.unlinkedMarkerType
|
||||
defaultValue = null
|
||||
}
|
||||
varargElementType?.let {
|
||||
if (it.isUnlinked()) {
|
||||
this@buildSet += it
|
||||
varargElementType = unlinkedMarkerTypeHandler.unlinkedMarkerType
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dispatchReceiverParameter?.fixType()
|
||||
extensionReceiverParameter?.fixType()
|
||||
valueParameters.forEach { it.fixType() }
|
||||
if (returnType.isUnlinked()) {
|
||||
this += returnType
|
||||
returnType = unlinkedMarkerTypeHandler.unlinkedMarkerType
|
||||
}
|
||||
typeParameters.forEach {
|
||||
val unlinkedSuperType = it.superTypes.firstOrNull { s -> s.isUnlinked() }
|
||||
if (unlinkedSuperType != null) {
|
||||
this += unlinkedSuperType
|
||||
it.superTypes = listOf(unlinkedMarkerTypeHandler.unlinkedMarkerType)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrFunction.transformBodyIfNecessary(
|
||||
isImplementedFakeOverride: Boolean,
|
||||
removedUnlinkedTypes: Set<IrType>
|
||||
): IrFunction {
|
||||
if (!isImplementedFakeOverride && removedUnlinkedTypes.isEmpty()) {
|
||||
transformChildrenVoid()
|
||||
} else {
|
||||
val functionKind = when {
|
||||
this@transformBodyIfNecessary is IrSimpleFunction && correspondingPropertySymbol != null -> "property accessor"
|
||||
this@transformBodyIfNecessary is IrConstructor -> "constructor"
|
||||
else -> "function"
|
||||
}
|
||||
|
||||
val errorMessages = listOfNotNull(
|
||||
if (isImplementedFakeOverride)
|
||||
buildString {
|
||||
append("Abstract ").append(functionKind).append(" ")
|
||||
append(fqNameForIrSerialization.asString())
|
||||
append(" is not implemented in non-abstract class ")
|
||||
append(parent.fqNameForIrSerialization.asString())
|
||||
}
|
||||
else null,
|
||||
if (removedUnlinkedTypes.isNotEmpty())
|
||||
buildString {
|
||||
append("The signature of ").append(functionKind).append(" ")
|
||||
append(fqNameForIrSerialization.asString())
|
||||
append(" contains unlinked symbols: ")
|
||||
removedUnlinkedTypes.joinTo(this) { it.render() }
|
||||
}
|
||||
else null
|
||||
)
|
||||
|
||||
errorMessages.forEach { reportWarning(it, location()) }
|
||||
|
||||
body?.let { body ->
|
||||
val bb = body as IrBlockBody
|
||||
bb.statements.clear()
|
||||
bb.statements.add(throwLinkageError(unlinkedSymbol = null, errorMessages.joinToString(separator = "; ")))
|
||||
}
|
||||
}
|
||||
|
||||
return this
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrSymbol.isUnlinked(): Boolean {
|
||||
|
||||
Reference in New Issue
Block a user