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 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()))
@@ -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) {
@@ -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