JVM_IR KT-43440 private-to-this default interface funs are private
This commit is contained in:
+41
-28
@@ -150,39 +150,52 @@ class JvmCachedDeclarations(
|
|||||||
return defaultImplsMethods.getOrPut(interfaceFun) {
|
return defaultImplsMethods.getOrPut(interfaceFun) {
|
||||||
val defaultImpls = getDefaultImplsClass(interfaceFun.parentAsClass)
|
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(
|
context.irFactory.createStaticFunctionWithReceivers(
|
||||||
defaultImpls, interfaceFun.name, interfaceFun,
|
defaultImpls, interfaceFun.name, interfaceFun,
|
||||||
dispatchReceiverType = parent.defaultType,
|
dispatchReceiverType = parent.defaultType,
|
||||||
// If `interfaceFun` is not a real implementation, then we're generating stubs in a descendant
|
origin = defaultImplsOrigin,
|
||||||
// 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
|
|
||||||
},
|
|
||||||
// Old backend doesn't generate ACC_FINAL on DefaultImpls methods.
|
// Old backend doesn't generate ACC_FINAL on DefaultImpls methods.
|
||||||
modality = Modality.OPEN,
|
modality = Modality.OPEN,
|
||||||
|
visibility = defaultImplsVisibility,
|
||||||
// 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,
|
|
||||||
|
|
||||||
isFakeOverride = false,
|
isFakeOverride = false,
|
||||||
typeParametersFromContext = parent.typeParameters
|
typeParametersFromContext = parent.typeParameters
|
||||||
).also {
|
).also {
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
interface A<in T> {
|
||||||
|
private fun f(): T {
|
||||||
|
TODO()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface B<out T> {
|
||||||
|
private fun f(): T {
|
||||||
|
TODO()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
+5
@@ -119,6 +119,11 @@ public class BytecodeListingTestGenerated extends AbstractBytecodeListingTest {
|
|||||||
runTest("compiler/testData/codegen/bytecodeListing/kt43217.kt");
|
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")
|
@TestMetadata("localFunctionInInitBlock.kt")
|
||||||
public void testLocalFunctionInInitBlock() throws Exception {
|
public void testLocalFunctionInInitBlock() throws Exception {
|
||||||
runTest("compiler/testData/codegen/bytecodeListing/localFunctionInInitBlock.kt");
|
runTest("compiler/testData/codegen/bytecodeListing/localFunctionInInitBlock.kt");
|
||||||
|
|||||||
+5
@@ -119,6 +119,11 @@ public class IrBytecodeListingTestGenerated extends AbstractIrBytecodeListingTes
|
|||||||
runTest("compiler/testData/codegen/bytecodeListing/kt43217.kt");
|
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")
|
@TestMetadata("localFunctionInInitBlock.kt")
|
||||||
public void testLocalFunctionInInitBlock() throws Exception {
|
public void testLocalFunctionInInitBlock() throws Exception {
|
||||||
runTest("compiler/testData/codegen/bytecodeListing/localFunctionInInitBlock.kt");
|
runTest("compiler/testData/codegen/bytecodeListing/localFunctionInInitBlock.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user