JVM_IR KT-43440 private-to-this default interface funs are private

This commit is contained in:
Dmitry Petrov
2020-11-23 11:27:38 +03:00
parent bf7fdcda6e
commit 551d0c1b64
5 changed files with 87 additions and 28 deletions
@@ -150,39 +150,52 @@ class JvmCachedDeclarations(
return defaultImplsMethods.getOrPut(interfaceFun) {
val defaultImpls = getDefaultImplsClass(interfaceFun.parentAsClass)
// If `interfaceFun` is not a real implementation, then we're generating stubs in a descendant
// interface's DefaultImpls. For example,
//
// interface I1 { fun f() { ... } }
// interface I2 : I1
//
// is supposed to allow using `I2.DefaultImpls.f` as if it was inherited from `I1.DefaultImpls`.
// The classes are not actually related and `I2.DefaultImpls.f` is not a fake override but a bridge.
val defaultImplsOrigin = when {
!forCompatibilityMode && !interfaceFun.isFakeOverride ->
when {
interfaceFun.origin == IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER ->
interfaceFun.origin
interfaceFun.origin.isSynthetic ->
JvmLoweredDeclarationOrigin.DEFAULT_IMPLS_WITH_MOVED_RECEIVERS_SYNTHETIC
else ->
JvmLoweredDeclarationOrigin.DEFAULT_IMPLS_WITH_MOVED_RECEIVERS
}
interfaceFun.resolveFakeOverride()!!.origin.isSynthetic ->
if (forCompatibilityMode)
JvmLoweredDeclarationOrigin.DEFAULT_IMPLS_BRIDGE_FOR_COMPATIBILITY_SYNTHETIC
else
JvmLoweredDeclarationOrigin.DEFAULT_IMPLS_BRIDGE_TO_SYNTHETIC
else ->
if (forCompatibilityMode)
JvmLoweredDeclarationOrigin.DEFAULT_IMPLS_BRIDGE_FOR_COMPATIBILITY
else
JvmLoweredDeclarationOrigin.DEFAULT_IMPLS_BRIDGE
}
// Interface functions are public or private, with one exception: clone in Cloneable, which is protected.
// However, Cloneable has no DefaultImpls, so this merely replicates the incorrect behavior of the old backend.
// We should rather not generate a bridge to clone when interface inherits from Cloneable at all.
val defaultImplsVisibility =
if (DescriptorVisibilities.isPrivate(interfaceFun.visibility))
DescriptorVisibilities.PRIVATE
else
DescriptorVisibilities.PUBLIC
context.irFactory.createStaticFunctionWithReceivers(
defaultImpls, interfaceFun.name, interfaceFun,
dispatchReceiverType = parent.defaultType,
// If `interfaceFun` is not a real implementation, then we're generating stubs in a descendant
// interface's DefaultImpls. For example,
//
// interface I1 { fun f() { ... } }
// interface I2 : I1
//
// is supposed to allow using `I2.DefaultImpls.f` as if it was inherited from `I1.DefaultImpls`.
// The classes are not actually related and `I2.DefaultImpls.f` is not a fake override but a bridge.
origin = when {
!forCompatibilityMode && !interfaceFun.isFakeOverride ->
when {
interfaceFun.origin == IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER -> interfaceFun.origin
interfaceFun.origin.isSynthetic -> JvmLoweredDeclarationOrigin.DEFAULT_IMPLS_WITH_MOVED_RECEIVERS_SYNTHETIC
else -> JvmLoweredDeclarationOrigin.DEFAULT_IMPLS_WITH_MOVED_RECEIVERS
}
interfaceFun.resolveFakeOverride()!!.origin.isSynthetic ->
if (forCompatibilityMode) JvmLoweredDeclarationOrigin.DEFAULT_IMPLS_BRIDGE_FOR_COMPATIBILITY_SYNTHETIC
else JvmLoweredDeclarationOrigin.DEFAULT_IMPLS_BRIDGE_TO_SYNTHETIC
else ->
if (forCompatibilityMode) JvmLoweredDeclarationOrigin.DEFAULT_IMPLS_BRIDGE_FOR_COMPATIBILITY
else JvmLoweredDeclarationOrigin.DEFAULT_IMPLS_BRIDGE
},
origin = defaultImplsOrigin,
// Old backend doesn't generate ACC_FINAL on DefaultImpls methods.
modality = Modality.OPEN,
// Interface functions are public or private, with one exception: clone in Cloneable, which is protected.
// However, Cloneable has no DefaultImpls, so this merely replicates the incorrect behavior of the old backend.
// We should rather not generate a bridge to clone when interface inherits from Cloneable at all.
visibility = if (interfaceFun.visibility == DescriptorVisibilities.PRIVATE) DescriptorVisibilities.PRIVATE else DescriptorVisibilities.PUBLIC,
visibility = defaultImplsVisibility,
isFakeOverride = false,
typeParametersFromContext = parent.typeParameters
).also {
+11
View File
@@ -0,0 +1,11 @@
interface A<in T> {
private fun f(): T {
TODO()
}
}
interface B<out T> {
private fun f(): T {
TODO()
}
}
+25
View File
@@ -0,0 +1,25 @@
@kotlin.Metadata
public final class A$DefaultImpls {
// source: 'kt43440.kt'
private static method f(p0: A): java.lang.Object
public final inner class A$DefaultImpls
}
@kotlin.Metadata
public interface A {
// source: 'kt43440.kt'
public final inner class A$DefaultImpls
}
@kotlin.Metadata
public final class B$DefaultImpls {
// source: 'kt43440.kt'
private static method f(p0: B): java.lang.Object
public final inner class B$DefaultImpls
}
@kotlin.Metadata
public interface B {
// source: 'kt43440.kt'
public final inner class B$DefaultImpls
}
@@ -119,6 +119,11 @@ public class BytecodeListingTestGenerated extends AbstractBytecodeListingTest {
runTest("compiler/testData/codegen/bytecodeListing/kt43217.kt");
}
@TestMetadata("kt43440.kt")
public void testKt43440() throws Exception {
runTest("compiler/testData/codegen/bytecodeListing/kt43440.kt");
}
@TestMetadata("localFunctionInInitBlock.kt")
public void testLocalFunctionInInitBlock() throws Exception {
runTest("compiler/testData/codegen/bytecodeListing/localFunctionInInitBlock.kt");
@@ -119,6 +119,11 @@ public class IrBytecodeListingTestGenerated extends AbstractIrBytecodeListingTes
runTest("compiler/testData/codegen/bytecodeListing/kt43217.kt");
}
@TestMetadata("kt43440.kt")
public void testKt43440() throws Exception {
runTest("compiler/testData/codegen/bytecodeListing/kt43440.kt");
}
@TestMetadata("localFunctionInInitBlock.kt")
public void testLocalFunctionInInitBlock() throws Exception {
runTest("compiler/testData/codegen/bytecodeListing/localFunctionInInitBlock.kt");