[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(
|
inline fun <reified T : IrElement> T.deepCopyWithSymbols(
|
||||||
initialParent: IrDeclarationParent? = null,
|
initialParent: IrDeclarationParent? = null,
|
||||||
createCopier: (SymbolRemapper, TypeRemapper) -> DeepCopyIrTreeWithSymbols = ::DeepCopyIrTreeWithSymbols
|
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 {
|
): T {
|
||||||
val symbolRemapper = DeepCopySymbolRemapper()
|
|
||||||
acceptVoid(symbolRemapper)
|
acceptVoid(symbolRemapper)
|
||||||
val typeRemapper = DeepCopyTypeRemapper(symbolRemapper)
|
val typeRemapper = DeepCopyTypeRemapper(symbolRemapper)
|
||||||
return transform(createCopier(symbolRemapper, typeRemapper), null).patchDeclarationParents(initialParent) as T
|
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
|
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.UnlinkedDeclarationsSupport.UnlinkedMarkerTypeHandler
|
||||||
|
import org.jetbrains.kotlin.descriptors.Modality
|
||||||
import org.jetbrains.kotlin.ir.IrBuiltIns
|
import org.jetbrains.kotlin.ir.IrBuiltIns
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
import org.jetbrains.kotlin.ir.IrStatement
|
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.IrSimpleType
|
||||||
import org.jetbrains.kotlin.ir.types.IrType
|
import org.jetbrains.kotlin.ir.types.IrType
|
||||||
import org.jetbrains.kotlin.ir.types.IrTypeProjection
|
import org.jetbrains.kotlin.ir.types.IrTypeProjection
|
||||||
import org.jetbrains.kotlin.ir.util.IrMessageLogger
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
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.visitors.IrElementTransformerVoid
|
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
|
||||||
internal class UnlinkedDeclarationsProcessor(
|
internal class UnlinkedDeclarationsProcessor(
|
||||||
private val builtIns: IrBuiltIns,
|
private val builtIns: IrBuiltIns,
|
||||||
@@ -33,7 +32,7 @@ internal class UnlinkedDeclarationsProcessor(
|
|||||||
) {
|
) {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val errorOrigin = object : IrStatementOriginImpl("LINKAGE ERROR") {}
|
private val errorOrigin = object : IrStatementOriginImpl("LINKAGE ERROR") {}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addLinkageErrorIntoUnlinkedClasses() {
|
fun addLinkageErrorIntoUnlinkedClasses() {
|
||||||
@@ -54,7 +53,7 @@ internal class UnlinkedDeclarationsProcessor(
|
|||||||
}
|
}
|
||||||
anonInitializer.body.statements.clear()
|
anonInitializer.body.statements.clear()
|
||||||
|
|
||||||
klass.reportWarning("Class", klass.fqNameForIrSerialization.asString())
|
klass.reportUnlinkedSymbolsWarning("Class", klass.fqNameForIrSerialization)
|
||||||
|
|
||||||
anonInitializer.body.statements.add(klass.throwLinkageError(klass.symbol))
|
anonInitializer.body.statements.add(klass.throwLinkageError(klass.symbol))
|
||||||
|
|
||||||
@@ -75,8 +74,8 @@ internal class UnlinkedDeclarationsProcessor(
|
|||||||
return IrMessageLogger.Location("$module @ $fileName", lineNumber, columnNumber)
|
return IrMessageLogger.Location("$module @ $fileName", lineNumber, columnNumber)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun IrDeclaration.reportWarning(kind: String, fqn: String) {
|
private fun IrDeclaration.reportUnlinkedSymbolsWarning(kind: String, fqn: FqName) {
|
||||||
reportWarning("$kind declaration $fqn contains unlinked symbols", location())
|
reportWarning("$kind declaration ${fqn.asString()} contains unlinked symbols", location())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun reportWarning(message: String, location: IrMessageLogger.Location?) {
|
private fun reportWarning(message: String, location: IrMessageLogger.Location?) {
|
||||||
@@ -86,54 +85,38 @@ internal class UnlinkedDeclarationsProcessor(
|
|||||||
fun signatureTransformer(): IrElementTransformerVoid = SignatureTransformer()
|
fun signatureTransformer(): IrElementTransformerVoid = SignatureTransformer()
|
||||||
|
|
||||||
private inner class SignatureTransformer : IrElementTransformerVoid() {
|
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 {
|
override fun visitFunction(declaration: IrFunction): IrStatement {
|
||||||
var linked = true
|
val newFunction = declaration.replaceIfUnimplementedFakeOverride()
|
||||||
fun IrValueParameter.fixType() {
|
val removedUnlinkedTypes = newFunction.fixUnlinkedTypes()
|
||||||
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())
|
|
||||||
|
|
||||||
declaration.body?.let { body ->
|
val isImplementedFakeOverride = newFunction != declaration || declaration.isAccessorOfImplementedFakeOverrideProperty
|
||||||
val bb = (body as IrBlockBody)
|
|
||||||
bb.statements.clear()
|
return newFunction.transformBodyIfNecessary(isImplementedFakeOverride, removedUnlinkedTypes)
|
||||||
bb.statements.add(declaration.throwLinkageError(unlinkedSymbol = null, "Unlinked type in IR function signature"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return declaration
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitField(declaration: IrField): IrStatement {
|
override fun visitField(declaration: IrField): IrStatement {
|
||||||
if (declaration.type.isUnlinked()) {
|
if (declaration.type.isUnlinked()) {
|
||||||
|
|
||||||
val fqn = declaration.correspondingPropertySymbol?.owner?.fqNameWhenAvailable ?: declaration.fqNameForIrSerialization
|
val fqn = declaration.correspondingPropertySymbol?.owner?.fqNameWhenAvailable ?: declaration.fqNameForIrSerialization
|
||||||
val kind = if (declaration.correspondingPropertySymbol != null) "Property" else "Field"
|
val kind = if (declaration.correspondingPropertySymbol != null) "Property" else "Field"
|
||||||
declaration.reportWarning(kind, fqn.asString())
|
declaration.reportUnlinkedSymbolsWarning(kind, fqn)
|
||||||
|
|
||||||
declaration.type = unlinkedMarkerTypeHandler.unlinkedMarkerType
|
declaration.type = unlinkedMarkerTypeHandler.unlinkedMarkerType
|
||||||
declaration.initializer = null
|
declaration.initializer = null
|
||||||
@@ -142,6 +125,98 @@ internal class UnlinkedDeclarationsProcessor(
|
|||||||
}
|
}
|
||||||
return declaration
|
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 {
|
private fun IrSymbol.isUnlinked(): Boolean {
|
||||||
|
|||||||
Reference in New Issue
Block a user