Restore overriddenSymbols consistency in InterfaceDelegationLowering
This commit is contained in:
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.jetbrains.kotlin.backend.common.ir
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.BackendContext
|
||||
import org.jetbrains.kotlin.backend.common.DumpIrTreeWithDescriptorsVisitor
|
||||
import org.jetbrains.kotlin.backend.common.deepCopyWithVariables
|
||||
import org.jetbrains.kotlin.backend.common.descriptors.WrappedClassConstructorDescriptor
|
||||
@@ -35,6 +34,7 @@ import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpressionBody
|
||||
import org.jetbrains.kotlin.ir.expressions.IrFunctionReference
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrBlockBodyImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrDelegatingConstructorCallImpl
|
||||
@@ -162,7 +162,10 @@ fun IrValueParameter.copyTo(
|
||||
(parent as IrTypeParametersContainer).classIfConstructor,
|
||||
irFunction.classIfConstructor
|
||||
),
|
||||
varargElementType: IrType? = this.varargElementType
|
||||
varargElementType: IrType? = this.varargElementType,
|
||||
defaultValue: IrExpressionBody? = this.defaultValue,
|
||||
isCrossinline: Boolean = this.isCrossinline,
|
||||
isNoinline: Boolean = this.isNoinline
|
||||
): IrValueParameter {
|
||||
val descriptor = WrappedValueParameterDescriptor(symbol.descriptor.annotations, symbol.descriptor.source)
|
||||
val symbol = IrValueParameterSymbolImpl(descriptor)
|
||||
@@ -382,3 +385,7 @@ fun IrClass.createImplicitParameterDeclarationWithWrappedDescriptor() {
|
||||
assert(typeParameters.isEmpty())
|
||||
assert(descriptor.declaredTypeParameters.isEmpty())
|
||||
}
|
||||
|
||||
fun IrSimpleFunction.isMethodOfAny() =
|
||||
((valueParameters.size == 0 && name.asString().let { it == "hashCode" || it == "toString" }) ||
|
||||
(valueParameters.size == 1 && name.asString() == "equals" && valueParameters[0].type.isNullableAny()))
|
||||
|
||||
+4
-3
@@ -44,7 +44,7 @@ class JvmDeclarationFactory(
|
||||
private val outerThisDeclarations = HashMap<IrClass, IrField>()
|
||||
private val innerClassConstructors = HashMap<IrConstructor, IrConstructor>()
|
||||
|
||||
private val defaultImplsMethods = HashMap<IrFunction, IrFunction>()
|
||||
private val defaultImplsMethods = HashMap<IrSimpleFunction, IrSimpleFunction>()
|
||||
private val defaultImplsClasses = HashMap<IrClass, IrClass>()
|
||||
|
||||
override fun getFieldForEnumEntry(enumEntry: IrEnumEntry, type: IrType): IrField =
|
||||
@@ -108,7 +108,8 @@ class JvmDeclarationFactory(
|
||||
newValueParameters,
|
||||
oldDescriptor.returnType,
|
||||
oldDescriptor.modality,
|
||||
oldDescriptor.visibility)
|
||||
oldDescriptor.visibility
|
||||
)
|
||||
val symbol = IrConstructorSymbolImpl(newDescriptor)
|
||||
return IrConstructorImpl(
|
||||
oldConstructor.startOffset,
|
||||
@@ -188,7 +189,7 @@ class JvmDeclarationFactory(
|
||||
).initialize(objectDescriptor.defaultType)
|
||||
}
|
||||
|
||||
fun getDefaultImplsFunction(interfaceFun: IrFunction): IrFunction {
|
||||
fun getDefaultImplsFunction(interfaceFun: IrSimpleFunction): IrSimpleFunction {
|
||||
val parent = interfaceFun.parentAsClass
|
||||
assert(parent.isInterface) { "Parent of ${interfaceFun.dump()} should be interface" }
|
||||
return defaultImplsMethods.getOrPut(interfaceFun) {
|
||||
|
||||
+58
-30
@@ -5,36 +5,30 @@
|
||||
|
||||
package org.jetbrains.kotlin.backend.jvm.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.ClassLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.descriptors.WrappedSimpleFunctionDescriptor
|
||||
import org.jetbrains.kotlin.backend.common.ir.copyParameterDeclarationsFrom
|
||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||
import org.jetbrains.kotlin.backend.common.CodegenUtil
|
||||
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
|
||||
import org.jetbrains.kotlin.backend.jvm.codegen.isJvmInterface
|
||||
import org.jetbrains.kotlin.codegen.OwnerKind
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.descriptors.deserialization.PLATFORM_DEPENDENT_ANNOTATION_FQ_NAME
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.builders.irBlockBody
|
||||
import org.jetbrains.kotlin.ir.builders.irCall
|
||||
import org.jetbrains.kotlin.ir.builders.irGet
|
||||
import org.jetbrains.kotlin.ir.builders.irReturn
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.ir.builders.*
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.util.hasAnnotation
|
||||
import org.jetbrains.kotlin.ir.util.isInterface
|
||||
import org.jetbrains.kotlin.ir.util.resolveFakeOverride
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.*
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import java.util.function.UnaryOperator
|
||||
|
||||
internal val interfaceDelegationPhase = makeIrFilePhase(
|
||||
::InterfaceDelegationLowering,
|
||||
@@ -42,17 +36,28 @@ internal val interfaceDelegationPhase = makeIrFilePhase(
|
||||
description = "Delegate calls to interface members with default implementations to DefaultImpls"
|
||||
)
|
||||
|
||||
private class InterfaceDelegationLowering(val context: JvmBackendContext) : IrElementTransformerVoid(), ClassLoweringPass {
|
||||
private class InterfaceDelegationLowering(val context: JvmBackendContext) : IrElementVisitorVoid, FileLoweringPass {
|
||||
|
||||
val state: GenerationState = context.state
|
||||
|
||||
override fun lower(irClass: IrClass) {
|
||||
if (irClass.isJvmInterface) return
|
||||
val replacementMap = mutableMapOf<IrSimpleFunctionSymbol, IrSimpleFunctionSymbol>()
|
||||
|
||||
irClass.transformChildrenVoid(this)
|
||||
generateInterfaceMethods(irClass)
|
||||
override fun lower(irFile: IrFile) {
|
||||
irFile.acceptChildrenVoid(this)
|
||||
// TODO: Replacer should be run on whole module, not on a single file.
|
||||
irFile.acceptVoid(OverriddenSymbolsReplacer(replacementMap))
|
||||
}
|
||||
|
||||
override fun visitElement(element: IrElement) {
|
||||
element.acceptChildrenVoid(this)
|
||||
}
|
||||
|
||||
override fun visitClass(declaration: IrClass) {
|
||||
super.visitClass(declaration)
|
||||
if (declaration.isJvmInterface) return
|
||||
|
||||
generateInterfaceMethods(declaration)
|
||||
}
|
||||
|
||||
private fun generateInterfaceMethods(irClass: IrClass) {
|
||||
val (actualClass, isDefaultImplsGeneration) = if (irClass.origin == JvmLoweredDeclarationOrigin.DEFAULT_IMPLS) {
|
||||
@@ -61,11 +66,21 @@ private class InterfaceDelegationLowering(val context: JvmBackendContext) : IrEl
|
||||
Pair(irClass, false)
|
||||
}
|
||||
|
||||
val newDeclarations = mutableListOf<IrFunction>()
|
||||
for (function in actualClass.declarations) {
|
||||
if (function !is IrSimpleFunction) continue
|
||||
val toRemove = mutableListOf<IrSimpleFunction>()
|
||||
for (function in actualClass.functions.toList()) { // Copy the list, because we are adding new declarations from the loop
|
||||
if (function.origin !== IrDeclarationOrigin.FAKE_OVERRIDE) continue
|
||||
|
||||
// In classes, only generate interface delegation for functions immediately inherited from am interface.
|
||||
// (Otherwise, delegation will be present in the parent class)
|
||||
if (!isDefaultImplsGeneration &&
|
||||
function.overriddenSymbols.any {
|
||||
!it.owner.parentAsClass.isInterface &&
|
||||
it.owner.modality != Modality.ABSTRACT
|
||||
}
|
||||
) {
|
||||
continue
|
||||
}
|
||||
|
||||
val implementation = function.resolveFakeOverride() ?: continue
|
||||
if (!implementation.hasInterfaceParent() ||
|
||||
Visibilities.isPrivate(implementation.visibility) ||
|
||||
@@ -74,17 +89,19 @@ private class InterfaceDelegationLowering(val context: JvmBackendContext) : IrEl
|
||||
continue
|
||||
}
|
||||
|
||||
newDeclarations.add(generateDelegationToDefaultImpl(implementation, function, isDefaultImplsGeneration))
|
||||
val delegation = generateDelegationToDefaultImpl(irClass, implementation, function, isDefaultImplsGeneration)
|
||||
toRemove.add(function)
|
||||
replacementMap[function.symbol] = delegation.symbol
|
||||
}
|
||||
|
||||
irClass.declarations.addAll(newDeclarations)
|
||||
irClass.declarations.removeAll(toRemove)
|
||||
}
|
||||
|
||||
private fun generateDelegationToDefaultImpl(
|
||||
irClass: IrClass,
|
||||
interfaceFun: IrSimpleFunction,
|
||||
inheritedFun: IrSimpleFunction,
|
||||
isDefaultImplsGeneration: Boolean
|
||||
): IrFunction {
|
||||
): IrSimpleFunction {
|
||||
val defaultImplFun = context.declarationFactory.getDefaultImplsFunction(interfaceFun)
|
||||
|
||||
val irFunction =
|
||||
@@ -117,6 +134,8 @@ private class InterfaceDelegationLowering(val context: JvmBackendContext) : IrEl
|
||||
}
|
||||
} else context.declarationFactory.getDefaultImplsFunction(inheritedFun)
|
||||
|
||||
irClass.declarations.add(irFunction)
|
||||
|
||||
context.createIrBuilder(irFunction.symbol, UNDEFINED_OFFSET, UNDEFINED_OFFSET).apply {
|
||||
irFunction.body = irBlockBody {
|
||||
+irReturn(
|
||||
@@ -133,9 +152,18 @@ private class InterfaceDelegationLowering(val context: JvmBackendContext) : IrEl
|
||||
return irFunction
|
||||
}
|
||||
|
||||
private fun IrSimpleFunction.isMethodOfAny() =
|
||||
((valueParameters.size == 0 && name.asString() in setOf("hashCode", "toString")) ||
|
||||
(valueParameters.size == 1 && name.asString() == "equals" && valueParameters[0].type == context.irBuiltIns.anyType))
|
||||
private class OverriddenSymbolsReplacer(val replacementMap: Map<IrSimpleFunctionSymbol, IrSimpleFunctionSymbol>) :
|
||||
IrElementVisitorVoid {
|
||||
|
||||
override fun visitElement(element: IrElement) {
|
||||
element.acceptChildrenVoid(this)
|
||||
}
|
||||
|
||||
override fun visitSimpleFunction(declaration: IrSimpleFunction) {
|
||||
declaration.overriddenSymbols.replaceAll(UnaryOperator { symbol -> replacementMap[symbol] ?: symbol })
|
||||
super.visitSimpleFunction(declaration)
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrSimpleFunction.hasInterfaceParent() =
|
||||
(parent as? IrClass)?.isInterface == true
|
||||
|
||||
Reference in New Issue
Block a user