diff --git a/plugins/jvm-abi-gen/src/org/jetbrains/kotlin/jvm/abi/asm/AbiClassBuilder.kt b/plugins/jvm-abi-gen/src/org/jetbrains/kotlin/jvm/abi/asm/AbiClassBuilder.kt index de13108cc0f..541672be7df 100644 --- a/plugins/jvm-abi-gen/src/org/jetbrains/kotlin/jvm/abi/asm/AbiClassBuilder.kt +++ b/plugins/jvm-abi-gen/src/org/jetbrains/kotlin/jvm/abi/asm/AbiClassBuilder.kt @@ -8,6 +8,8 @@ package org.jetbrains.kotlin.jvm.abi.asm import com.intellij.psi.PsiElement import org.jetbrains.kotlin.codegen.AbstractClassBuilder import org.jetbrains.kotlin.descriptors.FunctionDescriptor +import org.jetbrains.kotlin.descriptors.MemberDescriptor +import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin import org.jetbrains.org.objectweb.asm.* @@ -22,10 +24,15 @@ internal class AbiClassBuilder(private val cv: ClassVisitor) : AbstractClassBuil signature: String?, exceptions: Array? ): MethodVisitor { - if (isPrivate(access) || isClinit(name, access)) return EMPTY_METHOD_VISITOR + // if both descriptor's and access's visibilities are private, we can generate an empty method + // 1. we need to check a descriptor, because inline reified functions + // might have a non-private visibility in ABI, but they are private in bytecode + // 2. we need to check an access, because synthetic methods + // for default parameters have private visibility, but public in bytecode + val descriptor = origin.descriptor as? MemberDescriptor + if (isPrivate(access) && descriptor != null && isPrivate(descriptor) || isClinit(name, access)) return EMPTY_METHOD_VISITOR val mv = super.newMethod(origin, access, name, desc, signature, exceptions) - val descriptor = origin.descriptor // inline function bodies are part of ABI, // but non-inline functions can be thrown out if (descriptor is FunctionDescriptor && descriptor.isInline) return mv @@ -67,6 +74,9 @@ internal class AbiClassBuilder(private val cv: ClassVisitor) : AbstractClassBuil super.defineClass(origin, version, access, name, signature, superName, interfaces) } + private fun isPrivate(descriptor: MemberDescriptor): Boolean = + descriptor.visibility == Visibilities.PRIVATE + private fun isPrivate(access: Int): Boolean = (access and Opcodes.ACC_PRIVATE) == Opcodes.ACC_PRIVATE diff --git a/plugins/jvm-abi-gen/test/org/jetbrains/kotlin/jvm/abi/CompileAgainstJvmAbiTestGenerated.java b/plugins/jvm-abi-gen/test/org/jetbrains/kotlin/jvm/abi/CompileAgainstJvmAbiTestGenerated.java index 2bcdc189302..17b2b2fc3b1 100644 --- a/plugins/jvm-abi-gen/test/org/jetbrains/kotlin/jvm/abi/CompileAgainstJvmAbiTestGenerated.java +++ b/plugins/jvm-abi-gen/test/org/jetbrains/kotlin/jvm/abi/CompileAgainstJvmAbiTestGenerated.java @@ -44,6 +44,11 @@ public class CompileAgainstJvmAbiTestGenerated extends AbstractCompileAgainstJvm runTest("plugins/jvm-abi-gen/testData/compile/clinit/"); } + @TestMetadata("inlineReifiedFunction") + public void testInlineReifiedFunction() throws Exception { + runTest("plugins/jvm-abi-gen/testData/compile/inlineReifiedFunction/"); + } + @TestMetadata("privateOnlyConstructors") public void testPrivateOnlyConstructors() throws Exception { runTest("plugins/jvm-abi-gen/testData/compile/privateOnlyConstructors/"); diff --git a/plugins/jvm-abi-gen/testData/compile/inlineReifiedFunction/app/app.kt b/plugins/jvm-abi-gen/testData/compile/inlineReifiedFunction/app/app.kt new file mode 100644 index 00000000000..292d620a0ab --- /dev/null +++ b/plugins/jvm-abi-gen/testData/compile/inlineReifiedFunction/app/app.kt @@ -0,0 +1,13 @@ +package app + +import lib.* + +fun runAppAndReturnOk(): String { + val a = safeCall(10) { it * it } + if (a != 100) error("a is '$a', but is expected to be '100'") + + val b = safeCall(null) { it * it } + if (b != null) error("b is '$b', but is expected to be 'null'") + + return "OK" +} \ No newline at end of file diff --git a/plugins/jvm-abi-gen/testData/compile/inlineReifiedFunction/lib/utils.kt b/plugins/jvm-abi-gen/testData/compile/inlineReifiedFunction/lib/utils.kt new file mode 100644 index 00000000000..1d71238bc81 --- /dev/null +++ b/plugins/jvm-abi-gen/testData/compile/inlineReifiedFunction/lib/utils.kt @@ -0,0 +1,4 @@ +package lib + +inline fun safeCall(x: Any?, fn: (T) -> T): T? = + if (x is T) fn(x) else null \ No newline at end of file