diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt index 8760bbd80b7..defef17b8f4 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt @@ -76,6 +76,7 @@ val jvmPhases = namedIrFilePhase( interfacePhase then interfaceDelegationPhase then + interfaceSuperCallsPhase then sharedVariablesPhase then makePatchParentsPhase(1) then 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 adccac27840..bea0e5b095c 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 @@ -24,11 +24,14 @@ import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET 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.expressions.IrCall +import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.visitors.* import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.utils.addToStdlib.safeAs import java.util.function.UnaryOperator internal val interfaceDelegationPhase = makeIrFilePhase( @@ -171,9 +174,39 @@ private class InterfaceDelegationLowering(val context: JvmBackendContext) : IrEl private fun IrSimpleFunction.hasInterfaceParent() = (parent as? IrClass)?.isInterface == true - - private fun IrSimpleFunction.isDefinitelyNotDefaultImplsMethod() = - resolveFakeOverride()?.let { origin == IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB } == true || - origin == IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER || - hasAnnotation(PLATFORM_DEPENDENT_ANNOTATION_FQ_NAME) } + +internal val interfaceSuperCallsPhase = makeIrFilePhase( + lowering = ::InterfaceSuperCallsLowering, + name = "InterfaceSuperCalls", + description = "Redirect super interface calls to DefaultImpls" +) + +private class InterfaceSuperCallsLowering(val context: JvmBackendContext) : IrElementTransformerVoid(), FileLoweringPass { + + override fun lower(irFile: IrFile) { + irFile.transformChildrenVoid(this) + } + + override fun visitCall(expression: IrCall): IrExpression { + if (expression.superQualifierSymbol?.owner?.isInterface != true) { + return super.visitCall(expression) + } + val superCallee = (expression.symbol.owner as IrSimpleFunction).resolveFakeOverride()!! + if (superCallee.isDefinitelyNotDefaultImplsMethod()) return super.visitCall(expression) + + val redirectTarget = context.declarationFactory.getDefaultImplsFunction(superCallee) + val newCall = irCall(expression, redirectTarget, dispatchReceiverAsFirstArgument = true) + + return super.visitCall(newCall) + } +} + + +private fun IrSimpleFunction.isDefinitelyNotDefaultImplsMethod() = + resolveFakeOverride()?.let { origin == IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB } == true || + origin == IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER || + hasAnnotation(PLATFORM_DEPENDENT_ANNOTATION_FQ_NAME) || + (name.asString() == "clone" && + parent.safeAs()?.fqNameWhenAvailable?.asString() == "kotlin.Cloneable" && + valueParameters.isEmpty()) diff --git a/compiler/testData/codegen/box/javaInterop/objectMethods/cloneableClassWithoutClone.kt b/compiler/testData/codegen/box/javaInterop/objectMethods/cloneableClassWithoutClone.kt index 8e4cbdebbc6..261c6f41fde 100644 --- a/compiler/testData/codegen/box/javaInterop/objectMethods/cloneableClassWithoutClone.kt +++ b/compiler/testData/codegen/box/javaInterop/objectMethods/cloneableClassWithoutClone.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR // IGNORE_BACKEND: JS_IR // TODO: muted automatically, investigate should it be ran for JS or not // IGNORE_BACKEND: JS, NATIVE diff --git a/compiler/testData/codegen/box/jvm8/defaults/capturedSuperCall.kt b/compiler/testData/codegen/box/jvm8/defaults/capturedSuperCall.kt index e11d497002b..63d0599b2d2 100644 --- a/compiler/testData/codegen/box/jvm8/defaults/capturedSuperCall.kt +++ b/compiler/testData/codegen/box/jvm8/defaults/capturedSuperCall.kt @@ -1,5 +1,4 @@ // !JVM_DEFAULT_MODE: enable -// IGNORE_BACKEND: JVM_IR // TARGET_BACKEND: JVM // JVM_TARGET: 1.8 // WITH_RUNTIME diff --git a/compiler/testData/codegen/box/jvm8/defaults/superCall.kt b/compiler/testData/codegen/box/jvm8/defaults/superCall.kt index 4842e0d367d..320ee85fb91 100644 --- a/compiler/testData/codegen/box/jvm8/defaults/superCall.kt +++ b/compiler/testData/codegen/box/jvm8/defaults/superCall.kt @@ -1,5 +1,4 @@ // !JVM_DEFAULT_MODE: enable -// IGNORE_BACKEND: JVM_IR // TARGET_BACKEND: JVM // JVM_TARGET: 1.8 // WITH_RUNTIME diff --git a/compiler/testData/compileKotlinAgainstKotlin/jvm8/defaults/superCall.kt b/compiler/testData/compileKotlinAgainstKotlin/jvm8/defaults/superCall.kt index 874e7ed3897..18329abfac4 100644 --- a/compiler/testData/compileKotlinAgainstKotlin/jvm8/defaults/superCall.kt +++ b/compiler/testData/compileKotlinAgainstKotlin/jvm8/defaults/superCall.kt @@ -1,5 +1,4 @@ // !JVM_DEFAULT_MODE: enable -// IGNORE_BACKEND: JVM_IR // JVM_TARGET: 1.8 // WITH_RUNTIME // FILE: 1.kt diff --git a/compiler/testData/compileKotlinAgainstKotlin/jvm8/defaults/superCallFromInterface.kt b/compiler/testData/compileKotlinAgainstKotlin/jvm8/defaults/superCallFromInterface.kt index c5020e7677f..18d9fd5ad8b 100644 --- a/compiler/testData/compileKotlinAgainstKotlin/jvm8/defaults/superCallFromInterface.kt +++ b/compiler/testData/compileKotlinAgainstKotlin/jvm8/defaults/superCallFromInterface.kt @@ -1,5 +1,4 @@ // !JVM_DEFAULT_MODE: enable -// IGNORE_BACKEND: JVM_IR // JVM_TARGET: 1.8 // WITH_RUNTIME // FILE: 1.kt diff --git a/compiler/testData/compileKotlinAgainstKotlin/jvm8/defaults/superCallFromInterface2.kt b/compiler/testData/compileKotlinAgainstKotlin/jvm8/defaults/superCallFromInterface2.kt index 11f20fc16b6..694274ca7f0 100644 --- a/compiler/testData/compileKotlinAgainstKotlin/jvm8/defaults/superCallFromInterface2.kt +++ b/compiler/testData/compileKotlinAgainstKotlin/jvm8/defaults/superCallFromInterface2.kt @@ -1,5 +1,4 @@ // !JVM_DEFAULT_MODE: enable -// IGNORE_BACKEND: JVM_IR // JVM_TARGET: 1.8 // WITH_RUNTIME // FILE: 1.kt diff --git a/compiler/testData/compileKotlinAgainstKotlin/jvm8/jvm8against6/delegation/diamond.kt b/compiler/testData/compileKotlinAgainstKotlin/jvm8/jvm8against6/delegation/diamond.kt index 69166c0a131..15e6faacc1d 100644 --- a/compiler/testData/compileKotlinAgainstKotlin/jvm8/jvm8against6/delegation/diamond.kt +++ b/compiler/testData/compileKotlinAgainstKotlin/jvm8/jvm8against6/delegation/diamond.kt @@ -1,5 +1,4 @@ // !JVM_DEFAULT_MODE: enable -// IGNORE_BACKEND: JVM_IR // FILE: 1.kt interface Test { fun test(): String { diff --git a/compiler/testData/compileKotlinAgainstKotlin/jvm8/jvm8against6/delegation/diamond3.kt b/compiler/testData/compileKotlinAgainstKotlin/jvm8/jvm8against6/delegation/diamond3.kt index 6ffdcff2e57..0abbf2d98ea 100644 --- a/compiler/testData/compileKotlinAgainstKotlin/jvm8/jvm8against6/delegation/diamond3.kt +++ b/compiler/testData/compileKotlinAgainstKotlin/jvm8/jvm8against6/delegation/diamond3.kt @@ -1,5 +1,4 @@ // !JVM_DEFAULT_MODE: enable -// IGNORE_BACKEND: JVM_IR // FILE: 1.kt interface Test { fun test(): String {