JVM_IR: partially fix inline methods using captured crossinline lambdas

The fields containing crossinline lambdas should be package-private to
avoid generating synthetic accessors, which break object regeneration.

Note that the inline methods cannot actually be called, as call sites
will attempt to read the captured lambda from a field through a *copy*
of the local containing the object, so these reads will not be inlined,
causing an exception at runtime:

    inline fun f(crossinline g: () -> Unit) = object : I {
        inline fun h() = g()
        // effectively `val tmp = this; return tmp.$g()`:
        override fun run() = h()
    }

    f {}.run() // NoSuchFieldError: $g

This particular example can be fixed by reusing locals for receiver
parameters in IrInlineCodegen, but explicitly assigning `this` to
another variable and calling an inline method on it will break it again.
(This is only applicable to the JVM_IR backend, as the non-IR one fails
to generate `f` at all for some other reason.)
This commit is contained in:
pyos
2020-02-07 11:17:32 +01:00
committed by max-kammerer
parent dd27b3d4f1
commit 2c06503311
14 changed files with 69 additions and 10 deletions
@@ -1,5 +1,4 @@
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JVM_IR
// TARGET_BACKEND: JVM
// COMMON_COROUTINES_TEST
// WITH_RUNTIME
@@ -89,7 +89,7 @@ public final class CrossinlineKt$consumeEach$2$send$1 {
@kotlin.Metadata
public final class CrossinlineKt$consumeEach$2 {
private synthetic final field $action: kotlin.jvm.functions.Function2
synthetic final @org.jetbrains.annotations.NotNull field $action: kotlin.jvm.functions.Function2
inner class CrossinlineKt$consumeEach$2
inner class CrossinlineKt$consumeEach$2$send$1
public method <init>(p0: kotlin.jvm.functions.Function2): void
@@ -355,7 +355,7 @@ public final class CrossinlineKt$source$1$consume$1 {
@kotlin.Metadata
public final class CrossinlineKt$source$1 {
private synthetic final field $action: kotlin.jvm.functions.Function2
synthetic final @org.jetbrains.annotations.NotNull field $action: kotlin.jvm.functions.Function2
inner class CrossinlineKt$source$1
inner class CrossinlineKt$source$1$consume$1
public method <init>(p0: kotlin.jvm.functions.Function2): void
@@ -65,7 +65,7 @@ public final class flow/InnerObjectRetransformationKt$collect$2$emit$1 {
@kotlin.Metadata
public final class flow/InnerObjectRetransformationKt$collect$2 {
private synthetic final field $action: kotlin.jvm.functions.Function2
synthetic final @org.jetbrains.annotations.NotNull field $action: kotlin.jvm.functions.Function2
inner class flow/InnerObjectRetransformationKt$collect$2
inner class flow/InnerObjectRetransformationKt$collect$2$emit$1
public method <init>(p0: kotlin.jvm.functions.Function2): void
@@ -86,7 +86,7 @@ public final class flow/InnerObjectRetransformationKt$flow$1$collect$1 {
@kotlin.Metadata
public final class flow/InnerObjectRetransformationKt$flow$1 {
private synthetic final field $block: kotlin.jvm.functions.Function2
synthetic final @org.jetbrains.annotations.NotNull field $block: kotlin.jvm.functions.Function2
inner class flow/InnerObjectRetransformationKt$flow$1
inner class flow/InnerObjectRetransformationKt$flow$1$collect$1
public method <init>(p0: kotlin.jvm.functions.Function2): void
@@ -48,7 +48,7 @@ public final class Override5Kt$inlineMe$1$generic$2 {
@kotlin.Metadata
public final class Override5Kt$inlineMe$1 {
private synthetic final field $c: kotlin.jvm.functions.Function1
synthetic final @org.jetbrains.annotations.NotNull field $c: kotlin.jvm.functions.Function1
inner class Override5Kt$inlineMe$1
inner class Override5Kt$inlineMe$1$generic$1
inner class Override5Kt$inlineMe$1$generic$2
@@ -0,0 +1,20 @@
// FILE: 1.kt
package test
interface I {
fun f(): String
}
inline fun test(crossinline h: () -> String) = object : I {
// TODO: actually call g() in f() -- currently, the inliner fails to detect
// an inlined read of h's field because it uses a copy of `this`
// as a receiver
override fun f(): String = h()
inline fun g(): String = h()
}
// FILE: 2.kt
import test.*
fun box(): String = test { "OK" }.f()
@@ -21,7 +21,7 @@ public final class TcoContinuationKt$collect$2$emit$1 {
@kotlin.Metadata
public final class TcoContinuationKt$collect$2 {
private synthetic final field $action: kotlin.jvm.functions.Function2
synthetic final @org.jetbrains.annotations.NotNull field $action: kotlin.jvm.functions.Function2
inner class TcoContinuationKt$collect$2
inner class TcoContinuationKt$collect$2$emit$1
public method <init>(p0: kotlin.jvm.functions.Function2): void
@@ -42,7 +42,7 @@ public final class TcoContinuationKt$flow$1$collect$1 {
@kotlin.Metadata
public final class TcoContinuationKt$flow$1 {
private synthetic final field $block: kotlin.jvm.functions.Function2
synthetic final @org.jetbrains.annotations.NotNull field $block: kotlin.jvm.functions.Function2
inner class TcoContinuationKt$flow$1
inner class TcoContinuationKt$flow$1$collect$1
public method <init>(p0: kotlin.jvm.functions.Function2): void