JVM_IR: do not use invokedynamic for inline fun references
This commit is contained in:
+8
-4
@@ -29,7 +29,6 @@ import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.inline.INLINE_ONLY_ANNOTATION_FQ_NAME
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
|
||||
@@ -76,20 +75,25 @@ internal class LambdaMetafactoryArgumentsBuilder(
|
||||
if (samClass.requiresDelegationToDefaultImpls())
|
||||
return null
|
||||
|
||||
// TODO in cases where LambdaMetafactory is unusable directly due to problems with the implementation function,
|
||||
// we can still avoid generating an entire class by converting the function reference into a lambda first;
|
||||
// see `InlineCallableReferenceToLambdaPhase`
|
||||
val implFun = reference.symbol.owner
|
||||
|
||||
// Don't generate references to intrinsic functions as invokedynamic (no such method exists at run-time).
|
||||
if (context.irIntrinsics.getIntrinsic(implFun.symbol) != null)
|
||||
return null
|
||||
|
||||
// Don't generate reference to inlineOnly methods as those do not exist at runtime.
|
||||
if (implFun.hasAnnotation(INLINE_ONLY_ANNOTATION_FQ_NAME))
|
||||
// Can't use invokedynamic if the referenced function has to be inlined for correct semantics
|
||||
// Also in some cases like `private inline fun` we'd need accessors, which `SyntheticAccessorLowering`
|
||||
// won't generate under the assumption that the inline function will be inlined. Plus if the function
|
||||
// is in a different module we should probably copy it anyway (and regenerate all objects in it).
|
||||
if (implFun.isInline)
|
||||
return null
|
||||
|
||||
if (implFun is IrConstructor && implFun.visibility.isPrivate) {
|
||||
// Kotlin generates constructor accessors differently from Java.
|
||||
// TODO more precise accessibility check (see SyntheticAccessorLowering::isAccessible)
|
||||
// TODO wrap inaccessible constructor with a local function
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
@@ -10,11 +10,17 @@
|
||||
|
||||
import java.util.function.Consumer
|
||||
|
||||
fun call(c: Consumer<String>) {
|
||||
}
|
||||
inline fun <reified T> f(x: T) =
|
||||
println("${T::class.simpleName}($x)")
|
||||
|
||||
private inline fun g(x: String) = println(x)
|
||||
|
||||
fun call(c: Consumer<String>) = c.accept("")
|
||||
|
||||
fun box(): String {
|
||||
// println is inline only and therefore we cannot use invoke-dynamic to target it.
|
||||
call(::println)
|
||||
call(::println) // `println` is `@InlineOnly`
|
||||
call(::f) // `f` has a reified type parameter and thus isn't callable directly
|
||||
val obj = { call(::g) } // `g` is inaccessible in this scope
|
||||
obj()
|
||||
return "OK"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user