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