JVM IR: fix InterfaceLowering for $default methods from base interfaces

The first change here is swapping the isCompatibility and hasJvmDefault
checks. Otherwise behavior could be different depending on -Xjvm-default
mode even for non-JvmDefault declarations, which makes little sense.

Another change is avoiding generating $default stubs for fake overrides
in interfaces, which replicates the behavior of the current backend.
(Note that this change also fixes the first problem on the newly added
tests, but the first change seems useful anyway.)
This commit is contained in:
Alexander Udalov
2019-12-27 23:24:04 +01:00
parent 3848ac9cac
commit b48d7f4ba7
9 changed files with 70 additions and 10 deletions
@@ -71,12 +71,13 @@ internal class InterfaceLowering(val context: JvmBackendContext) : IrElementTran
continue@loop
/**
* 2) They inherit a default implementation from an interface this interface
* extends: create a bridge from companion to companion, unless
* - the implementation is private or belongs to java.lang.Object
* - we're in JVM Compatibility Default mode, in which case we go via
* 2) They inherit a default implementation from an interface this interface extends:
* create a bridge from DefaultImpls of derived to DefaultImpls of base, unless
* - the implementation is private, or belongs to java.lang.Object,
* or is a stub for function with default parameters ($default)
* - we're in -Xjvm-default=compatibility mode, in which case we go via
* accessors on the parent class rather than the DefaultImpls
* - we're in JVM Default mode, and we have that default implementation,
* - we're in -Xjvm-default=enable mode, and we have that default implementation,
* in which case we simply leave it.
*
* ```
@@ -95,18 +96,20 @@ internal class InterfaceLowering(val context: JvmBackendContext) : IrElementTran
val implementation = function.resolveFakeOverride()!!
when {
Visibilities.isPrivate(implementation.visibility) || implementation.isMethodOfAny() ->
Visibilities.isPrivate(implementation.visibility) ||
implementation.isMethodOfAny() ||
implementation.origin == IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER ->
continue@loop
context.state.jvmDefaultMode.isCompatibility -> {
val defaultImpl = createDefaultImpl(function)
defaultImpl.bridgeViaAccessorTo(function)
}
!implementation.hasJvmDefault() -> {
val defaultImpl = createDefaultImpl(function)
context.declarationFactory.getDefaultImplsFunction(implementation).also {
defaultImpl.bridgeToStatic(it)
}
}
context.state.jvmDefaultMode.isCompatibility -> {
val defaultImpl = createDefaultImpl(function)
defaultImpl.bridgeViaAccessorTo(function)
}
// else -> Do nothing.
}
}
@@ -0,0 +1,12 @@
// !JVM_DEFAULT_MODE: compatibility
// TARGET_BACKEND: JVM
interface I {
fun foo(x: String = "OK"): String = x
}
interface J : I
object O : J
fun box(): String = O.foo()
@@ -0,0 +1,15 @@
// FILE: I.kt
interface I {
fun foo(x: String = "OK"): String = x
}
// FILE: J.kt
interface J : I
// @I$DefaultImpls.class:
// 1 foo\$default
// @J$DefaultImpls.class:
// 0 foo\$default
@@ -15104,6 +15104,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/jvm8/defaults/compatibility/defaultArgsViaAnonymousObject.kt");
}
@TestMetadata("inheritedFunctionWithDefaultParameters.kt")
public void testInheritedFunctionWithDefaultParameters() throws Exception {
runTest("compiler/testData/codegen/box/jvm8/defaults/compatibility/inheritedFunctionWithDefaultParameters.kt");
}
@TestMetadata("inheritedJvmDefault.kt")
public void testInheritedJvmDefault() throws Exception {
runTest("compiler/testData/codegen/box/jvm8/defaults/compatibility/inheritedJvmDefault.kt");
@@ -1560,6 +1560,11 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/bytecodeText/defaultArguments"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
}
@TestMetadata("inheritedInterfaceFunction.kt")
public void testInheritedInterfaceFunction() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/defaultArguments/inheritedInterfaceFunction.kt");
}
@TestMetadata("kt11962.kt")
public void testKt11962() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/defaultArguments/kt11962.kt");
@@ -15104,6 +15104,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/jvm8/defaults/compatibility/defaultArgsViaAnonymousObject.kt");
}
@TestMetadata("inheritedFunctionWithDefaultParameters.kt")
public void testInheritedFunctionWithDefaultParameters() throws Exception {
runTest("compiler/testData/codegen/box/jvm8/defaults/compatibility/inheritedFunctionWithDefaultParameters.kt");
}
@TestMetadata("inheritedJvmDefault.kt")
public void testInheritedJvmDefault() throws Exception {
runTest("compiler/testData/codegen/box/jvm8/defaults/compatibility/inheritedJvmDefault.kt");
@@ -13954,6 +13954,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/jvm8/defaults/compatibility/defaultArgsViaAnonymousObject.kt");
}
@TestMetadata("inheritedFunctionWithDefaultParameters.kt")
public void testInheritedFunctionWithDefaultParameters() throws Exception {
runTest("compiler/testData/codegen/box/jvm8/defaults/compatibility/inheritedFunctionWithDefaultParameters.kt");
}
@TestMetadata("inheritedJvmDefault.kt")
public void testInheritedJvmDefault() throws Exception {
runTest("compiler/testData/codegen/box/jvm8/defaults/compatibility/inheritedJvmDefault.kt");
@@ -13954,6 +13954,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/jvm8/defaults/compatibility/defaultArgsViaAnonymousObject.kt");
}
@TestMetadata("inheritedFunctionWithDefaultParameters.kt")
public void testInheritedFunctionWithDefaultParameters() throws Exception {
runTest("compiler/testData/codegen/box/jvm8/defaults/compatibility/inheritedFunctionWithDefaultParameters.kt");
}
@TestMetadata("inheritedJvmDefault.kt")
public void testInheritedJvmDefault() throws Exception {
runTest("compiler/testData/codegen/box/jvm8/defaults/compatibility/inheritedJvmDefault.kt");
@@ -1515,6 +1515,11 @@ public class IrBytecodeTextTestGenerated extends AbstractIrBytecodeTextTest {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/bytecodeText/defaultArguments"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
}
@TestMetadata("inheritedInterfaceFunction.kt")
public void testInheritedInterfaceFunction() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/defaultArguments/inheritedInterfaceFunction.kt");
}
@TestMetadata("kt11962.kt")
public void testKt11962() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/defaultArguments/kt11962.kt");