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.load.java.JvmAnnotationNames
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.name.Name
|
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.types.Variance
|
||||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||||
|
|
||||||
@@ -76,20 +75,25 @@ internal class LambdaMetafactoryArgumentsBuilder(
|
|||||||
if (samClass.requiresDelegationToDefaultImpls())
|
if (samClass.requiresDelegationToDefaultImpls())
|
||||||
return null
|
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
|
val implFun = reference.symbol.owner
|
||||||
|
|
||||||
// Don't generate references to intrinsic functions as invokedynamic (no such method exists at run-time).
|
// Don't generate references to intrinsic functions as invokedynamic (no such method exists at run-time).
|
||||||
if (context.irIntrinsics.getIntrinsic(implFun.symbol) != null)
|
if (context.irIntrinsics.getIntrinsic(implFun.symbol) != null)
|
||||||
return null
|
return null
|
||||||
|
|
||||||
// Don't generate reference to inlineOnly methods as those do not exist at runtime.
|
// Can't use invokedynamic if the referenced function has to be inlined for correct semantics
|
||||||
if (implFun.hasAnnotation(INLINE_ONLY_ANNOTATION_FQ_NAME))
|
// 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
|
return null
|
||||||
|
|
||||||
if (implFun is IrConstructor && implFun.visibility.isPrivate) {
|
if (implFun is IrConstructor && implFun.visibility.isPrivate) {
|
||||||
// Kotlin generates constructor accessors differently from Java.
|
// Kotlin generates constructor accessors differently from Java.
|
||||||
// TODO more precise accessibility check (see SyntheticAccessorLowering::isAccessible)
|
// TODO more precise accessibility check (see SyntheticAccessorLowering::isAccessible)
|
||||||
// TODO wrap inaccessible constructor with a local function
|
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,11 +10,17 @@
|
|||||||
|
|
||||||
import java.util.function.Consumer
|
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 {
|
fun box(): String {
|
||||||
// println is inline only and therefore we cannot use invoke-dynamic to target it.
|
call(::println) // `println` is `@InlineOnly`
|
||||||
call(::println)
|
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"
|
return "OK"
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user