IC: call JvmDefault method of inline class using boxed receiver

#KT-43698 Fixed
This commit is contained in:
Ilmir Usmanov
2020-12-07 15:13:54 +01:00
parent d6330337a9
commit 0dc5f3ac00
19 changed files with 227 additions and 78 deletions
@@ -29,7 +29,8 @@ class CallableMethod(
override val generateCalleeType: Type?,
override val returnKotlinType: KotlinType?,
val isInterfaceMethod: Boolean,
private val isDefaultMethodInInterface: Boolean
private val isDefaultMethodInInterface: Boolean,
private val boxInlineClassBeforeInvoke: Boolean
) : Callable {
private val defaultImplMethod: Method by lazy(LazyThreadSafetyMode.PUBLICATION, computeDefaultMethod)
@@ -49,6 +50,9 @@ class CallableMethod(
get() = getAsmMethod().argumentTypes
override fun genInvokeInstruction(v: InstructionAdapter) {
if (boxInlineClassBeforeInvoke) {
StackValue.boxInlineClass(dispatchReceiverKotlinType!!, v)
}
v.visitMethodInsn(
invokeOpcode,
owner.internalName,
@@ -379,7 +379,8 @@ class KotlinTypeMapper @JvmOverloads constructor(
val originalDescriptor = descriptor.original
return CallableMethod(
owner, owner, { mapDefaultMethod(originalDescriptor, OwnerKind.IMPLEMENTATION) }, method, INVOKESPECIAL,
null, null, null, null, null, originalDescriptor.returnType, isInterfaceMethod = false, isDefaultMethodInInterface = false
null, null, null, null, null, originalDescriptor.returnType, isInterfaceMethod = false, isDefaultMethodInInterface = false,
boxInlineClassBeforeInvoke = false
)
}
@@ -402,6 +403,7 @@ class KotlinTypeMapper @JvmOverloads constructor(
val dispatchReceiverKotlinType: KotlinType?
var isInterfaceMember = false
var isDefaultMethodInInterface = false
var boxInlineClassBeforeInvoke = false
if (functionParent is ClassDescriptor) {
val declarationFunctionDescriptor = findAnyDeclaration(functionDescriptor)
@@ -452,11 +454,15 @@ class KotlinTypeMapper @JvmOverloads constructor(
functionDescriptor = descriptor
}
val isStaticInvocation =
isStaticDeclaration(functionDescriptor) && functionDescriptor !is ImportedFromObjectCallableDescriptor<*> ||
isStaticAccessor(functionDescriptor) ||
functionDescriptor.isJvmStaticInObjectOrClassOrInterface() ||
toInlinedErasedClass
val isFakeOverrideOfJvmDefault = toInlinedErasedClass &&
functionDescriptor.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE &&
functionDescriptor.overridesJvmDefault()
val isStaticInvocation = !isFakeOverrideOfJvmDefault &&
(isStaticDeclaration(functionDescriptor) && functionDescriptor !is ImportedFromObjectCallableDescriptor<*> ||
isStaticAccessor(functionDescriptor) ||
functionDescriptor.isJvmStaticInObjectOrClassOrInterface() ||
toInlinedErasedClass)
when {
isStaticInvocation -> {
invokeOpcode = INVOKESTATIC
@@ -466,8 +472,13 @@ class KotlinTypeMapper @JvmOverloads constructor(
invokeOpcode = INVOKEINTERFACE
isInterfaceMember = true
}
isFakeOverrideOfJvmDefault -> {
invokeOpcode = INVOKEVIRTUAL
boxInlineClassBeforeInvoke = true
}
else -> {
val isPrivateFunInvocation = DescriptorVisibilities.isPrivate(functionDescriptor.visibility) && !functionDescriptor.isSuspend
val isPrivateFunInvocation =
DescriptorVisibilities.isPrivate(functionDescriptor.visibility) && !functionDescriptor.isSuspend
invokeOpcode = if (superCall || isPrivateFunInvocation) INVOKESPECIAL else INVOKEVIRTUAL
isInterfaceMember = false
}
@@ -479,7 +490,7 @@ class KotlinTypeMapper @JvmOverloads constructor(
else
functionDescriptor.original
signature = if (toInlinedErasedClass)
signature = if (toInlinedErasedClass && !isFakeOverrideOfJvmDefault)
mapSignatureForInlineErasedClassSkipGeneric(functionToCall)
else
mapSignature(
@@ -547,10 +558,18 @@ class KotlinTypeMapper @JvmOverloads constructor(
signature, invokeOpcode, thisClass, dispatchReceiverKotlinType, receiverParameterType, extensionReceiverKotlinType,
calleeType, returnKotlinType,
if (jvmTarget >= JvmTarget.JVM_1_8) isInterfaceMember else invokeOpcode == INVOKEINTERFACE,
isDefaultMethodInInterface
isDefaultMethodInInterface, boxInlineClassBeforeInvoke
)
}
private fun CallableMemberDescriptor.overridesJvmDefault(): Boolean {
if (kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
return overriddenDescriptors.any { it.overridesJvmDefault() }
}
if (isCompiledToJvmDefault(jvmDefaultMode)) return true
return (containingDeclaration as? JavaClassDescriptor)?.kind == ClassKind.INTERFACE && modality != Modality.ABSTRACT
}
fun mapFunctionName(descriptor: FunctionDescriptor, kind: OwnerKind?): String {
if (descriptor !is JavaCallableMemberDescriptor) {
val platformName = getJvmName(descriptor)
@@ -15235,6 +15235,26 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
public void testJvmDefaultEnableProperty() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/jvm8DefaultInterfaceMethods/jvmDefaultEnableProperty.kt");
}
@TestMetadata("jvmDefaultGeneric.kt")
public void testJvmDefaultGeneric() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/jvm8DefaultInterfaceMethods/jvmDefaultGeneric.kt");
}
@TestMetadata("jvmDefaultSafeCall.kt")
public void testJvmDefaultSafeCall() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/jvm8DefaultInterfaceMethods/jvmDefaultSafeCall.kt");
}
@TestMetadata("jvmDefaultSmartCast.kt")
public void testJvmDefaultSmartCast() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/jvm8DefaultInterfaceMethods/jvmDefaultSmartCast.kt");
}
@TestMetadata("jvmDefaultSuspend.kt")
public void testJvmDefaultSuspend() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/jvm8DefaultInterfaceMethods/jvmDefaultSuspend.kt");
}
}
@TestMetadata("compiler/testData/codegen/box/inlineClasses/propertyDelegation")
@@ -1,7 +1,4 @@
// TARGET_BACKEND: JVM
// IGNORE_LIGHT_ANALYSIS
// IGNORE_BACKEND: JVM
// ^ KT-43698, fixed in JVM_IR
// JVM_TARGET: 1.8
// FILE: javaDefaultMethod.kt
inline class K(val k: String) : J {
@@ -1,7 +1,4 @@
// TARGET_BACKEND: JVM
// IGNORE_LIGHT_ANALYSIS
// IGNORE_BACKEND: JVM
// ^ KT-43698, fixed in JVM_IR
// JVM_TARGET: 1.8
// FILE: javaDefaultMethod.kt
interface K2 : J {
@@ -1,8 +1,5 @@
// !JVM_DEFAULT_MODE: all
// TARGET_BACKEND: JVM
// IGNORE_LIGHT_ANALYSIS
// IGNORE_BACKEND: JVM
// ^ KT-43698, fixed in JVM_IR
// WITH_RUNTIME
// JVM_TARGET: 1.8
// FILE: jvmDefaultAll.kt
@@ -1,8 +1,5 @@
// !JVM_DEFAULT_MODE: all
// TARGET_BACKEND: JVM
// IGNORE_LIGHT_ANALYSIS
// IGNORE_BACKEND: JVM
// ^ KT-43698, fixed in JVM_IR
// WITH_RUNTIME
// JVM_TARGET: 1.8
// FILE: jvmDefaultAll.kt
@@ -1,8 +1,5 @@
// !JVM_DEFAULT_MODE: all
// TARGET_BACKEND: JVM
// IGNORE_LIGHT_ANALYSIS
// IGNORE_BACKEND: JVM
// ^ KT-43698, fixed in JVM_IR
// WITH_RUNTIME
// JVM_TARGET: 1.8
// FILE: jvmDefaultAll.kt
@@ -1,8 +1,5 @@
// !JVM_DEFAULT_MODE: enable
// TARGET_BACKEND: JVM
// IGNORE_LIGHT_ANALYSIS
// IGNORE_BACKEND: JVM
// ^ KT-43698, fixed in JVM_IR
// WITH_RUNTIME
// JVM_TARGET: 1.8
// FILE: jvmDefaultEnable.kt
@@ -1,8 +1,5 @@
// !JVM_DEFAULT_MODE: enable
// TARGET_BACKEND: JVM
// IGNORE_LIGHT_ANALYSIS
// IGNORE_BACKEND: JVM
// ^ KT-43698, fixed in JVM_IR
// WITH_RUNTIME
// JVM_TARGET: 1.8
// FILE: jvmDefaultEnable.kt
@@ -1,8 +1,5 @@
// !JVM_DEFAULT_MODE: enable
// TARGET_BACKEND: JVM
// IGNORE_LIGHT_ANALYSIS
// IGNORE_BACKEND: JVM
// ^ KT-43698, fixed in JVM_IR
// WITH_RUNTIME
// JVM_TARGET: 1.8
// FILE: jvmDefaultEnable.kt
@@ -0,0 +1,16 @@
// !JVM_DEFAULT_MODE: all
// TARGET_BACKEND: JVM
// WITH_RUNTIME
// JVM_TARGET: 1.8
class Cell<T>(val x: T)
interface IOk {
fun ok(): String = "OK"
}
inline class InlineClass(val s: String) : IOk
fun test(cell: Cell<InlineClass>): String = cell.x.ok()
fun box() = test(Cell(InlineClass("FAIL")))
@@ -0,0 +1,14 @@
// !JVM_DEFAULT_MODE: all
// TARGET_BACKEND: JVM
// WITH_RUNTIME
// JVM_TARGET: 1.8
interface IOk {
fun ok(): String = "OK"
}
inline class InlineClass(val s: String) : IOk
fun test(x: InlineClass?) = x?.ok() ?: "Failed"
fun box() = test(InlineClass(""))
@@ -0,0 +1,16 @@
// !JVM_DEFAULT_MODE: all
// TARGET_BACKEND: JVM
// WITH_RUNTIME
// JVM_TARGET: 1.8
interface IOk {
fun ok(): String = "OK"
}
inline class InlineClass(val s: String) : IOk
fun test(x: Any): String {
return if (x is InlineClass) x.ok() else "FAIL"
}
fun box() = test(InlineClass("Dummy"))
@@ -0,0 +1,28 @@
// !JVM_DEFAULT_MODE: all
// TARGET_BACKEND: JVM
// WITH_RUNTIME
// JVM_TARGET: 1.8
import kotlin.coroutines.*
interface IOk {
fun ok(): String = "OK"
}
inline class InlineClass(val s: String) : IOk
suspend fun returnsUnboxed() = InlineClass("")
suspend fun test(): String = returnsUnboxed().ok()
fun builder(c: suspend () -> Unit) {
c.startCoroutine(Continuation(EmptyCoroutineContext) {})
}
fun box(): String {
var res = "FAIL"
builder {
res = test()
}
return res
}
@@ -1,9 +1,5 @@
// !LANGUAGE: +InlineClasses
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JVM
// The JVM backend does not generate the g-impl method, but ends up calling it from box.
// !JVM_DEFAULT_MODE: enable
// JVM_TARGET: 1.8
// FILE: test.kt
@@ -16635,6 +16635,26 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
public void testJvmDefaultEnableProperty() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/jvm8DefaultInterfaceMethods/jvmDefaultEnableProperty.kt");
}
@TestMetadata("jvmDefaultGeneric.kt")
public void testJvmDefaultGeneric() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/jvm8DefaultInterfaceMethods/jvmDefaultGeneric.kt");
}
@TestMetadata("jvmDefaultSafeCall.kt")
public void testJvmDefaultSafeCall() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/jvm8DefaultInterfaceMethods/jvmDefaultSafeCall.kt");
}
@TestMetadata("jvmDefaultSmartCast.kt")
public void testJvmDefaultSmartCast() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/jvm8DefaultInterfaceMethods/jvmDefaultSmartCast.kt");
}
@TestMetadata("jvmDefaultSuspend.kt")
public void testJvmDefaultSuspend() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/jvm8DefaultInterfaceMethods/jvmDefaultSuspend.kt");
}
}
@TestMetadata("compiler/testData/codegen/box/inlineClasses/propertyDelegation")
@@ -16588,46 +16588,6 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Jvm8DefaultInterfaceMethods extends AbstractLightAnalysisModeTest {
@TestMetadata("javaDefaultMethod.kt")
public void ignoreJavaDefaultMethod() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/jvm8DefaultInterfaceMethods/javaDefaultMethod.kt");
}
@TestMetadata("javaDefaultMethodOverriddenByKotlin.kt")
public void ignoreJavaDefaultMethodOverriddenByKotlin() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/jvm8DefaultInterfaceMethods/javaDefaultMethodOverriddenByKotlin.kt");
}
@TestMetadata("jvmDefaultAll.kt")
public void ignoreJvmDefaultAll() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/jvm8DefaultInterfaceMethods/jvmDefaultAll.kt");
}
@TestMetadata("jvmDefaultAllPrimaryProperty.kt")
public void ignoreJvmDefaultAllPrimaryProperty() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/jvm8DefaultInterfaceMethods/jvmDefaultAllPrimaryProperty.kt");
}
@TestMetadata("jvmDefaultAllProperty.kt")
public void ignoreJvmDefaultAllProperty() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/jvm8DefaultInterfaceMethods/jvmDefaultAllProperty.kt");
}
@TestMetadata("jvmDefaultEnable.kt")
public void ignoreJvmDefaultEnable() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/jvm8DefaultInterfaceMethods/jvmDefaultEnable.kt");
}
@TestMetadata("jvmDefaultEnablePrimaryProperty.kt")
public void ignoreJvmDefaultEnablePrimaryProperty() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/jvm8DefaultInterfaceMethods/jvmDefaultEnablePrimaryProperty.kt");
}
@TestMetadata("jvmDefaultEnableProperty.kt")
public void ignoreJvmDefaultEnableProperty() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/jvm8DefaultInterfaceMethods/jvmDefaultEnableProperty.kt");
}
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath);
}
@@ -16635,6 +16595,66 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
public void testAllFilesPresentInJvm8DefaultInterfaceMethods() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/inlineClasses/jvm8DefaultInterfaceMethods"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
}
@TestMetadata("javaDefaultMethod.kt")
public void testJavaDefaultMethod() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/jvm8DefaultInterfaceMethods/javaDefaultMethod.kt");
}
@TestMetadata("javaDefaultMethodOverriddenByKotlin.kt")
public void testJavaDefaultMethodOverriddenByKotlin() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/jvm8DefaultInterfaceMethods/javaDefaultMethodOverriddenByKotlin.kt");
}
@TestMetadata("jvmDefaultAll.kt")
public void testJvmDefaultAll() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/jvm8DefaultInterfaceMethods/jvmDefaultAll.kt");
}
@TestMetadata("jvmDefaultAllPrimaryProperty.kt")
public void testJvmDefaultAllPrimaryProperty() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/jvm8DefaultInterfaceMethods/jvmDefaultAllPrimaryProperty.kt");
}
@TestMetadata("jvmDefaultAllProperty.kt")
public void testJvmDefaultAllProperty() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/jvm8DefaultInterfaceMethods/jvmDefaultAllProperty.kt");
}
@TestMetadata("jvmDefaultEnable.kt")
public void testJvmDefaultEnable() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/jvm8DefaultInterfaceMethods/jvmDefaultEnable.kt");
}
@TestMetadata("jvmDefaultEnablePrimaryProperty.kt")
public void testJvmDefaultEnablePrimaryProperty() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/jvm8DefaultInterfaceMethods/jvmDefaultEnablePrimaryProperty.kt");
}
@TestMetadata("jvmDefaultEnableProperty.kt")
public void testJvmDefaultEnableProperty() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/jvm8DefaultInterfaceMethods/jvmDefaultEnableProperty.kt");
}
@TestMetadata("jvmDefaultGeneric.kt")
public void testJvmDefaultGeneric() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/jvm8DefaultInterfaceMethods/jvmDefaultGeneric.kt");
}
@TestMetadata("jvmDefaultSafeCall.kt")
public void testJvmDefaultSafeCall() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/jvm8DefaultInterfaceMethods/jvmDefaultSafeCall.kt");
}
@TestMetadata("jvmDefaultSmartCast.kt")
public void testJvmDefaultSmartCast() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/jvm8DefaultInterfaceMethods/jvmDefaultSmartCast.kt");
}
@TestMetadata("jvmDefaultSuspend.kt")
public void testJvmDefaultSuspend() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/jvm8DefaultInterfaceMethods/jvmDefaultSuspend.kt");
}
}
@TestMetadata("compiler/testData/codegen/box/inlineClasses/propertyDelegation")
@@ -15235,6 +15235,26 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
public void testJvmDefaultEnableProperty() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/jvm8DefaultInterfaceMethods/jvmDefaultEnableProperty.kt");
}
@TestMetadata("jvmDefaultGeneric.kt")
public void testJvmDefaultGeneric() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/jvm8DefaultInterfaceMethods/jvmDefaultGeneric.kt");
}
@TestMetadata("jvmDefaultSafeCall.kt")
public void testJvmDefaultSafeCall() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/jvm8DefaultInterfaceMethods/jvmDefaultSafeCall.kt");
}
@TestMetadata("jvmDefaultSmartCast.kt")
public void testJvmDefaultSmartCast() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/jvm8DefaultInterfaceMethods/jvmDefaultSmartCast.kt");
}
@TestMetadata("jvmDefaultSuspend.kt")
public void testJvmDefaultSuspend() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/jvm8DefaultInterfaceMethods/jvmDefaultSuspend.kt");
}
}
@TestMetadata("compiler/testData/codegen/box/inlineClasses/propertyDelegation")