Restore overriddenSymbols consistency in InterfaceDelegationLowering

This commit is contained in:
Georgy Bronnikov
2018-12-24 12:04:17 +03:00
parent 68f9f4b3b5
commit c9b8f58a10
3 changed files with 71 additions and 35 deletions
@@ -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()))
@@ -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) {
@@ -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