Support tailrec suspend functions in JVM backend
The main problem is that inside a state machine for a named suspend function parameters of it's owner are available as a usual captured closure parameters (i.e. through synthetic fields), while TailRecursion codegen expects that parameters are straight local variables. So, the solution is just to define local var for each of real parameters (all but the last continuation parameters) for tailrec functions. #KT-15759 Fixed
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
// WITH_RUNTIME
|
||||
// WITH_COROUTINES
|
||||
// IGNORE_BACKEND: JS
|
||||
import kotlin.coroutines.experimental.*
|
||||
import kotlin.coroutines.experimental.intrinsics.*
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
suspend fun ArrayList<Int>.yield(v: Int): Unit = suspendCoroutineOrReturn { x ->
|
||||
this.add(v)
|
||||
x.resume(Unit)
|
||||
COROUTINE_SUSPENDED
|
||||
}
|
||||
|
||||
tailrec suspend fun ArrayList<Int>.fromTo(from: Int, to: Int) {
|
||||
if (from > to) return
|
||||
yield(from)
|
||||
return fromTo(from + 1, to)
|
||||
}
|
||||
|
||||
fun builder(c: suspend () -> Unit) {
|
||||
c.startCoroutine(EmptyContinuation)
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val result = arrayListOf<Int>()
|
||||
|
||||
builder {
|
||||
result.fromTo(1, 5)
|
||||
}
|
||||
|
||||
assertEquals(listOf(1, 2, 3, 4, 5), result)
|
||||
|
||||
return "OK"
|
||||
}
|
||||
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
@kotlin.Metadata
|
||||
public final class CoroutineUtilKt {
|
||||
public final static @org.jetbrains.annotations.NotNull method handleExceptionContinuation(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function1): kotlin.coroutines.experimental.Continuation
|
||||
public final static @org.jetbrains.annotations.NotNull method handleResultContinuation(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function1): kotlin.coroutines.experimental.Continuation
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public class EmptyContinuation {
|
||||
public final static field Companion: EmptyContinuation.Companion
|
||||
private final @org.jetbrains.annotations.NotNull field context: kotlin.coroutines.experimental.CoroutineContext
|
||||
inner class EmptyContinuation/Companion
|
||||
public @synthetic.kotlin.jvm.GeneratedByJvmOverloads method <init>(): void
|
||||
public method <init>(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.experimental.CoroutineContext): void
|
||||
public synthetic method <init>(p0: kotlin.coroutines.experimental.CoroutineContext, p1: int, p2: kotlin.jvm.internal.DefaultConstructorMarker): void
|
||||
public @org.jetbrains.annotations.NotNull method getContext(): kotlin.coroutines.experimental.CoroutineContext
|
||||
public method resume(@org.jetbrains.annotations.Nullable p0: java.lang.Object): void
|
||||
public method resumeWithException(@org.jetbrains.annotations.NotNull p0: java.lang.Throwable): void
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public final static class EmptyContinuation/Companion {
|
||||
inner class EmptyContinuation/Companion
|
||||
private method <init>(): void
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public final class TailrecKt {
|
||||
public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String
|
||||
public final static method builder(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function1): void
|
||||
public final static @org.jetbrains.annotations.Nullable method fromTo(@org.jetbrains.annotations.NotNull p0: java.util.ArrayList, p1: int, p2: int, @org.jetbrains.annotations.NotNull p3: kotlin.coroutines.experimental.Continuation): java.lang.Object
|
||||
public final static @org.jetbrains.annotations.Nullable method yield(@org.jetbrains.annotations.NotNull p0: java.util.ArrayList, p1: int, @org.jetbrains.annotations.NotNull p2: kotlin.coroutines.experimental.Continuation): java.lang.Object
|
||||
}
|
||||
Reference in New Issue
Block a user