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 53620210698..9b8ca7b7b17 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 @@ -280,6 +280,7 @@ private val jvmFilePhases = interfaceDelegationPhase then interfaceSuperCallsPhase then interfaceDefaultCallsPhase then + interfaceObjectCallsPhase then addContinuationPhase 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 e76713c2da3..a0d8c60ffa4 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 @@ -127,11 +127,11 @@ private class InterfaceDelegationLowering(val context: JvmBackendContext) : IrEl super.visitSimpleFunction(declaration) } } - - private fun IrSimpleFunction.hasInterfaceParent() = - (parent as? IrClass)?.isInterface == true } +private fun IrSimpleFunction.hasInterfaceParent() = + (parent as? IrClass)?.isInterface == true + internal val interfaceSuperCallsPhase = makeIrFilePhase( lowering = ::InterfaceSuperCallsLowering, name = "InterfaceSuperCalls", @@ -145,7 +145,7 @@ private class InterfaceSuperCallsLowering(val context: JvmBackendContext) : IrEl } override fun visitCall(expression: IrCall): IrExpression { - if (expression.superQualifierSymbol?.owner?.isInterface != true) { + if (expression.superQualifierSymbol?.owner?.isInterface != true || expression.isSuperToAny()) { return super.visitCall(expression) } @@ -201,3 +201,26 @@ private fun IrSimpleFunction.isDefinitelyNotDefaultImplsMethod() = (name.asString() == "clone" && parent.safeAs()?.fqNameWhenAvailable?.asString() == "kotlin.Cloneable" && valueParameters.isEmpty()) + +internal val interfaceObjectCallsPhase = makeIrFilePhase( + lowering = ::InterfaceObjectCallsLowering, + name = "InterfaceObjectCalls", + description = "Resolve calls to Object methods on interface types to virtual methods" +) + +private class InterfaceObjectCallsLowering(val context: JvmBackendContext) : IrElementTransformerVoid(), FileLoweringPass { + override fun lower(irFile: IrFile) = irFile.transformChildrenVoid(this) + + override fun visitCall(expression: IrCall): IrExpression { + if (expression.superQualifierSymbol != null && !expression.isSuperToAny()) + return super.visitCall(expression) + val callee = expression.symbol.owner + if (callee !is IrSimpleFunction || !callee.hasInterfaceParent()) + return super.visitCall(expression) + val resolved = callee.resolveFakeOverride() + if (resolved?.isMethodOfAny() != true) + return super.visitCall(expression) + val newSuperQualifierSymbol = context.irBuiltIns.anyClass.takeIf { expression.superQualifierSymbol != null } + return super.visitCall(irCall(expression, resolved, newSuperQualifierSymbol = newSuperQualifierSymbol)) + } +} diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt index eb9cc6b06a2..6800c8635d4 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt @@ -499,20 +499,23 @@ fun irCall( call: IrFunctionAccessExpression, newFunction: IrFunction, receiversAsArguments: Boolean = false, - argumentsAsReceivers: Boolean = false + argumentsAsReceivers: Boolean = false, + newSuperQualifierSymbol: IrClassSymbol? = null ): IrCall = irCall( call, newFunction.symbol, receiversAsArguments, - argumentsAsReceivers + argumentsAsReceivers, + newSuperQualifierSymbol ) fun irCall( call: IrFunctionAccessExpression, newSymbol: IrFunctionSymbol, receiversAsArguments: Boolean = false, - argumentsAsReceivers: Boolean = false + argumentsAsReceivers: Boolean = false, + newSuperQualifierSymbol: IrClassSymbol? = null ): IrCall = call.run { IrCallImpl( @@ -521,7 +524,8 @@ fun irCall( type, newSymbol, typeArgumentsCount, - origin + origin, + newSuperQualifierSymbol ).apply { copyTypeAndValueArgumentsFrom( call, diff --git a/compiler/testData/codegen/box/super/interfaceHashCode.kt b/compiler/testData/codegen/box/super/interfaceHashCode.kt new file mode 100644 index 00000000000..7a6aeff7fa3 --- /dev/null +++ b/compiler/testData/codegen/box/super/interfaceHashCode.kt @@ -0,0 +1,8 @@ +// IGNORE_BACKEND_FIR: JVM_IR +interface I +class C : I { fun foo() = super.hashCode() } + +fun box(): String { + C().foo() + return "OK" +} diff --git a/compiler/testData/codegen/bytecodeText/hashCode/interfaceHashCode.kt b/compiler/testData/codegen/bytecodeText/hashCode/interfaceHashCode.kt new file mode 100644 index 00000000000..c236203d714 --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/hashCode/interfaceHashCode.kt @@ -0,0 +1,5 @@ +val x: () -> Unit = {} +val y = x.hashCode() + +// 1 INVOKEVIRTUAL java/lang/Object.hashCode \(\)I +// 0 INVOKEINTERFACE diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 6f5c0c689fe..a83914aa312 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -26722,6 +26722,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/super/innerClassQualifiedPropertyAccess.kt"); } + @TestMetadata("interfaceHashCode.kt") + public void testInterfaceHashCode() throws Exception { + runTest("compiler/testData/codegen/box/super/interfaceHashCode.kt"); + } + @TestMetadata("kt14243.kt") public void testKt14243() throws Exception { runTest("compiler/testData/codegen/box/super/kt14243.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java index 18f53aad313..90dd2cafd4d 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java @@ -2299,6 +2299,11 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest { public void testHashCode() throws Exception { runTest("compiler/testData/codegen/bytecodeText/hashCode/hashCode.kt"); } + + @TestMetadata("interfaceHashCode.kt") + public void testInterfaceHashCode() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/hashCode/interfaceHashCode.kt"); + } } @TestMetadata("compiler/testData/codegen/bytecodeText/ieee754") diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index da486c67a36..946b76ef531 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -25539,6 +25539,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/super/innerClassQualifiedPropertyAccess.kt"); } + @TestMetadata("interfaceHashCode.kt") + public void testInterfaceHashCode() throws Exception { + runTest("compiler/testData/codegen/box/super/interfaceHashCode.kt"); + } + @TestMetadata("kt14243.kt") public void testKt14243() throws Exception { runTest("compiler/testData/codegen/box/super/kt14243.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java index c6596c00216..63c91503405 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java @@ -25221,6 +25221,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/super/innerClassQualifiedPropertyAccess.kt"); } + @TestMetadata("interfaceHashCode.kt") + public void testInterfaceHashCode() throws Exception { + runTest("compiler/testData/codegen/box/super/interfaceHashCode.kt"); + } + @TestMetadata("kt14243.kt") public void testKt14243() throws Exception { runTest("compiler/testData/codegen/box/super/kt14243.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index cc646d3867d..ce9df8f07a1 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -25221,6 +25221,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/super/innerClassQualifiedPropertyAccess.kt"); } + @TestMetadata("interfaceHashCode.kt") + public void testInterfaceHashCode() throws Exception { + runTest("compiler/testData/codegen/box/super/interfaceHashCode.kt"); + } + @TestMetadata("kt14243.kt") public void testKt14243() throws Exception { runTest("compiler/testData/codegen/box/super/kt14243.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeTextTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeTextTestGenerated.java index e87d2303f54..2b8b407a594 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeTextTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeTextTestGenerated.java @@ -2344,6 +2344,11 @@ public class IrBytecodeTextTestGenerated extends AbstractIrBytecodeTextTest { public void testHashCode() throws Exception { runTest("compiler/testData/codegen/bytecodeText/hashCode/hashCode.kt"); } + + @TestMetadata("interfaceHashCode.kt") + public void testInterfaceHashCode() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/hashCode/interfaceHashCode.kt"); + } } @TestMetadata("compiler/testData/codegen/bytecodeText/ieee754") diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java index 0363bfa2cb1..0d3a6beafc7 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java @@ -20747,6 +20747,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { runTest("compiler/testData/codegen/box/super/innerClassQualifiedPropertyAccess.kt"); } + @TestMetadata("interfaceHashCode.kt") + public void testInterfaceHashCode() throws Exception { + runTest("compiler/testData/codegen/box/super/interfaceHashCode.kt"); + } + @TestMetadata("kt14243.kt") public void testKt14243() throws Exception { runTest("compiler/testData/codegen/box/super/kt14243.kt"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index 6120f5044a7..e143359e6d2 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -21882,6 +21882,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { runTest("compiler/testData/codegen/box/super/innerClassQualifiedPropertyAccess.kt"); } + @TestMetadata("interfaceHashCode.kt") + public void testInterfaceHashCode() throws Exception { + runTest("compiler/testData/codegen/box/super/interfaceHashCode.kt"); + } + @TestMetadata("kt14243.kt") public void testKt14243() throws Exception { runTest("compiler/testData/codegen/box/super/kt14243.kt");