diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/descriptors/JvmDeclarationFactory.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/descriptors/JvmDeclarationFactory.kt index d1867a4bf23..34d97280c02 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/descriptors/JvmDeclarationFactory.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/descriptors/JvmDeclarationFactory.kt @@ -10,6 +10,7 @@ import org.jetbrains.kotlin.backend.common.ir.DeclarationFactory import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin import org.jetbrains.kotlin.backend.jvm.lower.createStaticFunctionWithReceivers import org.jetbrains.kotlin.builtins.CompanionObjectMapping.isMappedIntrinsicCompanionObject +import org.jetbrains.kotlin.codegen.OwnerKind import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.Annotations @@ -191,7 +192,7 @@ class JvmDeclarationFactory( return defaultImplsMethods.getOrPut(interfaceFun) { val defaultImpls = getDefaultImplsClass(interfaceFun.parentAsClass) - val name = Name.identifier(state.typeMapper.mapAsmMethod(interfaceFun.descriptor.original).name) + val name = Name.identifier(state.typeMapper.mapFunctionName(interfaceFun.descriptor.original, OwnerKind.IMPLEMENTATION)) createStaticFunctionWithReceivers( defaultImpls, name, interfaceFun, dispatchReceiverType = parent.defaultType, diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InterfaceDelegationLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InterfaceDelegationLowering.kt index 4529e17399e..9e68124bcd2 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InterfaceDelegationLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InterfaceDelegationLowering.kt @@ -6,29 +6,35 @@ package org.jetbrains.kotlin.backend.jvm.lower import org.jetbrains.kotlin.backend.common.ClassLoweringPass -import org.jetbrains.kotlin.backend.common.CodegenUtil import org.jetbrains.kotlin.backend.common.makePhase +import org.jetbrains.kotlin.backend.common.descriptors.WrappedSimpleFunctionDescriptor +import org.jetbrains.kotlin.backend.common.ir.copyParameterDeclarationsFrom import org.jetbrains.kotlin.backend.jvm.JvmBackendContext import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin import org.jetbrains.kotlin.backend.jvm.JvmLoweredStatementOrigin import org.jetbrains.kotlin.backend.jvm.codegen.isJvmInterface -import org.jetbrains.kotlin.backend.jvm.descriptors.DefaultImplsClassDescriptor -import org.jetbrains.kotlin.codegen.FunctionCodegen -import org.jetbrains.kotlin.codegen.isDefinitelyNotDefaultImplsMethod +import org.jetbrains.kotlin.codegen.OwnerKind import org.jetbrains.kotlin.codegen.state.GenerationState -import org.jetbrains.kotlin.descriptors.FunctionDescriptor +import org.jetbrains.kotlin.descriptors.Visibilities +import org.jetbrains.kotlin.descriptors.deserialization.PLATFORM_DEPENDENT_ANNOTATION_FQ_NAME import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET 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.expressions.impl.IrBlockBodyImpl import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl import org.jetbrains.kotlin.ir.expressions.impl.IrReturnImpl -import org.jetbrains.kotlin.ir.util.createParameterDeclarations +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.load.java.descriptors.JavaCallableMemberDescriptor +import org.jetbrains.kotlin.name.Name class InterfaceDelegationLowering(val context: JvmBackendContext) : IrElementTransformerVoid(), ClassLoweringPass { @@ -43,44 +49,67 @@ class InterfaceDelegationLowering(val context: JvmBackendContext) : IrElementTra private fun generateInterfaceMethods(irClass: IrClass) { - val irClassDescriptor = irClass.descriptor - val actualClassDescriptor = (irClass.takeIf { it.origin == JvmLoweredDeclarationOrigin.DEFAULT_IMPLS }?.parent as? IrClass)?.descriptor ?: irClassDescriptor - val isDefaultImplsGeneration = actualClassDescriptor !== irClassDescriptor - for ((interfaceFun, value) in CodegenUtil.getNonPrivateTraitMethods(actualClassDescriptor, !isDefaultImplsGeneration)) { + val (actualClass, isDefaultImplsGeneration) = if (irClass.origin == JvmLoweredDeclarationOrigin.DEFAULT_IMPLS) { + Pair(irClass.parent as IrClass, true) + } else { + Pair(irClass, false) + } + for ((interfaceFun, value) in actualClass.getNonPrivateInterfaceMethods()) { //skip java 8 default methods - if (!interfaceFun.isDefinitelyNotDefaultImplsMethod() && !FunctionCodegen.isMethodOfAny(interfaceFun)) { - generateDelegationToDefaultImpl( - irClass, context.ir.symbols.externalSymbolTable.referenceSimpleFunction( - interfaceFun.original - ).owner, value, isDefaultImplsGeneration - ) + if (!interfaceFun.isDefinitelyNotDefaultImplsMethod() && !interfaceFun.isMethodOfAny()) { + generateDelegationToDefaultImpl(irClass, interfaceFun, value, isDefaultImplsGeneration) } } + +// CodegenUtil.getNonPrivateTraitMethods(actualClass.descriptor, !isDefaultImplsGeneration)) { +// //skip java 8 default methods +// if (!interfaceFun.isDefinitelyNotDefaultImplsMethod() && !FunctionCodegen.isMethodOfAny(interfaceFun)) { +// generateDelegationToDefaultImpl( +// irClass, context.ir.symbols.externalSymbolTable.referenceSimpleFunction( +// interfaceFun.original +// ).owner, value, isDefaultImplsGeneration +// ) +// } +// } } private fun generateDelegationToDefaultImpl( irClass: IrClass, interfaceFun: IrFunction, - inheritedFun: FunctionDescriptor, + inheritedFun: IrSimpleFunction, isDefaultImplsGeneration: Boolean ) { val defaultImplFun = context.declarationFactory.getDefaultImplsFunction(interfaceFun) val irFunction = - if (!isDefaultImplsGeneration) IrFunctionImpl( - UNDEFINED_OFFSET, - UNDEFINED_OFFSET, - IrDeclarationOrigin.DEFINED, - inheritedFun, - defaultImplFun.returnType - ).also { - it.createParameterDeclarations() - } - else context.declarationFactory.getDefaultImplsFunction( - context.ir.symbols.externalSymbolTable.referenceSimpleFunction( - inheritedFun.original - ).owner - ) + if (!isDefaultImplsGeneration) { + val descriptor = WrappedSimpleFunctionDescriptor(inheritedFun.descriptor.annotations, inheritedFun.descriptor.source) + /* + By using WrappedDescriptor, we lose information whether the function is an accessor. + `KotlinTypeMapper` needs that info to generate JVM name. + TODO: streamline name generation. + */ + val name = Name.identifier(context.state.typeMapper.mapFunctionName(inheritedFun.descriptor, OwnerKind.IMPLEMENTATION)) + IrFunctionImpl( + UNDEFINED_OFFSET, + UNDEFINED_OFFSET, + IrDeclarationOrigin.DEFINED, + IrSimpleFunctionSymbolImpl(descriptor), + name, + Visibilities.PUBLIC, + inheritedFun.modality, + isInline = inheritedFun.isInline, + isExternal = false, + isTailrec = false, + isSuspend = inheritedFun.isSuspend + ).apply { + descriptor.bind(this) + parent = inheritedFun.parent + returnType = inheritedFun.returnType + overriddenSymbols.addAll(inheritedFun.overriddenSymbols) + copyParameterDeclarationsFrom(inheritedFun) + } + } else context.declarationFactory.getDefaultImplsFunction(inheritedFun) val irBody = IrBlockBodyImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET) irFunction.body = irBody irClass.declarations.add(irFunction) @@ -126,4 +155,25 @@ class InterfaceDelegationLowering(val context: JvmBackendContext) : IrElementTra } } + 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 fun IrSimpleFunction.isDefinitelyNotDefaultImplsMethod() = + resolveFakeOverride()?.let { + origin == IrDeclarationOrigin.IR_EXTERNAL_DECLARATION_STUB && descriptor is JavaCallableMemberDescriptor + } == true || + hasAnnotation(PLATFORM_DEPENDENT_ANNOTATION_FQ_NAME) + + private fun IrClass.getNonPrivateInterfaceMethods(): List> { + return declarations.filterIsInstance().mapNotNull { function -> + val resolved = function.resolveFakeOverride() + resolved?.takeIf { + resolved !== function && // TODO: take a better look + (resolved.parent as? IrClass)?.isInterface == true && + !Visibilities.isPrivate(resolved.visibility) && + resolved.visibility != Visibilities.INVISIBLE_FAKE + }?.let { Pair(resolved, function) } + } + } }