From 6a41700689cd2f29f721478087a708abe738e205 Mon Sep 17 00:00:00 2001 From: Kristoffer Andersen Date: Mon, 4 Nov 2019 15:37:24 +0100 Subject: [PATCH] [JVM_IR] Fix interface method resolution The JVM IR was too agressive in delegating statically to $DefaultImpls class. Consider the following library, compiled separately, and then client, compiled against that library: ``` //library interface A { @JvmDefault fun foo() = "A" } interface Left : A { } interface Right : A { @JvmDefault override fun foo() = "Right" } //client interface C : Left, Right {} fun main() { val x = object : C {} println(x.foo()) } ``` Previously, the IR backend generates an overriding bridge in C, which calls C$DefaultImpls which calls statically into Right$DefaultImpls. When then library is recompilerd with an override of foo in Left, the existing binary of the client continues to run against the recompiled library erroneously running Right.foo(). The old backend throws an IncompatibleClassChange exception due to ambiguity of multiple inherited default implementations. kotlinc indeed rejects the client when recompiled against the new library. We have no tests constraining this behaviour, but we could conceivably strap something together in CustomBinaries tests. --- .../kotlin/backend/jvm/lower/InterfaceDelegationLowering.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 f3b0b80e2e7..b392925cc33 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 @@ -79,7 +79,7 @@ private class InterfaceDelegationLowering(val context: JvmBackendContext) : IrEl || Visibilities.isPrivate(implementation.visibility) || implementation.isDefinitelyNotDefaultImplsMethod() || implementation.isMethodOfAny() - || (!context.state.jvmDefaultMode.isCompatibility && implementation.hasJvmDefault()) + || implementation.hasJvmDefault() ) { return null }