Do not generate beforeInlineMarker on tailrec jump
Before this change, the codegen used to generate beforeInlineMarker in order to spill variables later. However, since the tailrec call is replaced with jump, no afterInlineMarker is generated, leading to inconsistency of these markers. Thus, the spilling fails. This change disables generating of beforeInlineMarker. #KT-21521: Fixed
This commit is contained in:
+41
@@ -0,0 +1,41 @@
|
||||
// WITH_RUNTIME
|
||||
// WITH_COROUTINES
|
||||
|
||||
import helpers.*
|
||||
import kotlin.coroutines.experimental.*
|
||||
|
||||
class CompilerKillingIterator<T, out R>(private val underlying: Iterator<T>, private val transform: suspend (e: T) -> Iterator<R>) {
|
||||
private var currentIt: Iterator<R> = object : Iterator<R> {
|
||||
override fun hasNext() = false
|
||||
|
||||
override fun next(): R = null!!
|
||||
}
|
||||
|
||||
suspend tailrec fun next(): R {
|
||||
return if (currentIt.hasNext()) {
|
||||
currentIt.next()
|
||||
} else if (underlying.hasNext()) {
|
||||
currentIt = transform(underlying.next())
|
||||
next()
|
||||
} else {
|
||||
throw IllegalArgumentException("Cannot call next() on the empty iterator")
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun hasNext() = currentIt.hasNext() || underlying.hasNext()
|
||||
}
|
||||
|
||||
fun builder(c: suspend () -> Unit) {
|
||||
c.startCoroutine(EmptyContinuation)
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
var res = ""
|
||||
builder {
|
||||
val iter = CompilerKillingIterator("ok".asIterable().iterator()) { ("" + it.toUpperCase()).asIterable().iterator() }
|
||||
while (iter.hasNext()) {
|
||||
res += iter.next()
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
// WITH_RUNTIME
|
||||
// WITH_COROUTINES
|
||||
|
||||
import helpers.*
|
||||
import kotlin.coroutines.experimental.*
|
||||
|
||||
class CompilerKillingIterator<T, out R>(private val underlying: Iterator<T>, private val transform: suspend (e: T) -> Iterator<R>) {
|
||||
private var currentIt: Iterator<R> = object : Iterator<R> {
|
||||
override fun hasNext() = false
|
||||
|
||||
override fun next(): R = null!!
|
||||
}
|
||||
|
||||
suspend tailrec fun next(): R {
|
||||
return when {
|
||||
currentIt.hasNext() -> currentIt.next()
|
||||
underlying.hasNext() -> {
|
||||
currentIt = transform(underlying.next())
|
||||
next()
|
||||
}
|
||||
else -> throw IllegalArgumentException("Cannot call next() on the empty iterator")
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun hasNext() = currentIt.hasNext() || underlying.hasNext()
|
||||
}
|
||||
|
||||
fun builder(c: suspend () -> Unit) {
|
||||
c.startCoroutine(EmptyContinuation)
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
var res = ""
|
||||
builder {
|
||||
val iter = CompilerKillingIterator("ok".asIterable().iterator()) { ("" + it.toUpperCase()).asIterable().iterator() }
|
||||
while (iter.hasNext()) {
|
||||
res += iter.next()
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
// WITH_RUNTIME
|
||||
// WITH_COROUTINES
|
||||
// IGNORE_BACKEND_WITHOUT_CHECK: JS
|
||||
|
||||
import helpers.*
|
||||
import kotlin.coroutines.experimental.*
|
||||
|
||||
tailrec suspend infix fun Int.test(x : Int) : Int {
|
||||
if (this > 1) {
|
||||
return (this - 1) test x
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
fun builder(c: suspend () -> Unit) {
|
||||
c.startCoroutine(EmptyContinuation)
|
||||
}
|
||||
|
||||
fun box() : String {
|
||||
var res = ""
|
||||
builder {
|
||||
res = if (1000000.test(1000000) == 1) "OK" else "FAIL"
|
||||
}
|
||||
return res
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
// WITH_RUNTIME
|
||||
// WITH_COROUTINES
|
||||
// IGNORE_BACKEND_WITHOUT_CHECK: JS
|
||||
|
||||
import helpers.*
|
||||
import kotlin.coroutines.experimental.*
|
||||
|
||||
tailrec suspend infix fun Int.foo(x: Int) {
|
||||
if (x == 0) return
|
||||
val xx = x - 1
|
||||
return 1 foo xx
|
||||
}
|
||||
|
||||
fun builder(c: suspend () -> Unit) {
|
||||
c.startCoroutine(EmptyContinuation)
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
builder {
|
||||
1 foo 1000000
|
||||
}
|
||||
return "OK"
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
// WITH_RUNTIME
|
||||
// WITH_COROUTINES
|
||||
// IGNORE_BACKEND_WITHOUT_CHECK: JS
|
||||
import helpers.*
|
||||
import kotlin.coroutines.experimental.*
|
||||
|
||||
tailrec suspend fun <T, A> Iterator<T>.foldl(acc : A, foldFunction : (e : T, acc : A) -> A) : A =
|
||||
if (!hasNext()) acc
|
||||
else foldl(foldFunction(next(), acc), foldFunction)
|
||||
|
||||
fun builder(c: suspend () -> Unit) {
|
||||
c.startCoroutine(EmptyContinuation)
|
||||
}
|
||||
|
||||
fun box() : String {
|
||||
var sum = 0L
|
||||
builder {
|
||||
sum = (1..1000000).iterator().foldl(0) { e : Int, acc : Long ->
|
||||
acc + e
|
||||
}
|
||||
}
|
||||
|
||||
return if (sum == 500000500000) "OK" else "FAIL: $sum"
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
// WITH_RUNTIME
|
||||
// WITH_COROUTINES
|
||||
import helpers.*
|
||||
import kotlin.coroutines.experimental.*
|
||||
|
||||
suspend fun escapeChar(c : Char) : String? = when (c) {
|
||||
'\\' -> "\\\\"
|
||||
'\n' -> "\\n"
|
||||
'"' -> "\\\""
|
||||
else -> "" + c
|
||||
}
|
||||
|
||||
tailrec suspend fun String.escape(i : Int = 0, result : StringBuilder = StringBuilder()) : String =
|
||||
if (i == length) result.toString()
|
||||
else escape(i + 1, result.append(escapeChar(get(i))))
|
||||
|
||||
fun builder(c: suspend () -> Unit) {
|
||||
c.startCoroutine(EmptyContinuation)
|
||||
}
|
||||
|
||||
fun box() : String {
|
||||
var res = ""
|
||||
builder {
|
||||
res = "test me not \\".escape()
|
||||
}
|
||||
return if (res == "test me not \\\\") "OK" else res
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
// WITH_RUNTIME
|
||||
// WITH_COROUTINES
|
||||
// IGNORE_BACKEND_WITHOUT_CHECK: JS
|
||||
import helpers.*
|
||||
import kotlin.coroutines.experimental.*
|
||||
|
||||
tailrec suspend fun String.repeat(num : Int, acc : StringBuilder = StringBuilder()) : String =
|
||||
if (num == 0) acc.toString()
|
||||
else repeat(num - 1, acc.append(this))
|
||||
|
||||
fun builder(c: suspend () -> Unit) {
|
||||
c.startCoroutine(EmptyContinuation)
|
||||
}
|
||||
|
||||
fun box() : String {
|
||||
var s: String = ""
|
||||
builder {
|
||||
s = "a".repeat(10000)
|
||||
}
|
||||
return if (s.length == 10000) "OK" else "FAIL: ${s.length}"
|
||||
}
|
||||
Vendored
+21
@@ -0,0 +1,21 @@
|
||||
// WITH_RUNTIME
|
||||
// WITH_COROUTINES
|
||||
// IGNORE_BACKEND_WITHOUT_CHECK: JS
|
||||
import helpers.*
|
||||
import kotlin.coroutines.experimental.*
|
||||
|
||||
tailrec suspend fun foo(x: Int) {
|
||||
if (x == 0) return
|
||||
(return foo(x - 1))
|
||||
}
|
||||
|
||||
fun builder(c: suspend () -> Unit) {
|
||||
c.startCoroutine(EmptyContinuation)
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
builder {
|
||||
foo(1000000)
|
||||
}
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
// WITH_RUNTIME
|
||||
// WITH_COROUTINES
|
||||
// IGNORE_BACKEND_WITHOUT_CHECK: JS
|
||||
import helpers.*
|
||||
import kotlin.coroutines.experimental.*
|
||||
|
||||
tailrec suspend fun sum(x: Long, sum: Long): Long {
|
||||
if (x == 0.toLong()) return sum
|
||||
return sum(x - 1, sum + x)
|
||||
}
|
||||
|
||||
fun builder(c: suspend () -> Unit) {
|
||||
c.startCoroutine(EmptyContinuation)
|
||||
}
|
||||
|
||||
fun box() : String {
|
||||
var sum: Long = 0L
|
||||
builder {
|
||||
sum = sum(1000000, 0)
|
||||
}
|
||||
if (sum != 500000500000.toLong()) return "Fail $sum"
|
||||
return "OK"
|
||||
}
|
||||
compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/tailCallInBlockInParentheses.kt
Vendored
+23
@@ -0,0 +1,23 @@
|
||||
// WITH_RUNTIME
|
||||
// WITH_COROUTINES
|
||||
// IGNORE_BACKEND_WITHOUT_CHECK: JS
|
||||
import helpers.*
|
||||
import kotlin.coroutines.experimental.*
|
||||
|
||||
tailrec suspend fun foo(x: Int) {
|
||||
return if (x > 0) {
|
||||
(foo(x - 1))
|
||||
}
|
||||
else Unit
|
||||
}
|
||||
|
||||
fun builder(c: suspend () -> Unit) {
|
||||
c.startCoroutine(EmptyContinuation)
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
builder {
|
||||
foo(1000000)
|
||||
}
|
||||
return "OK"
|
||||
}
|
||||
Vendored
+21
@@ -0,0 +1,21 @@
|
||||
// WITH_RUNTIME
|
||||
// WITH_COROUTINES
|
||||
// IGNORE_BACKEND_WITHOUT_CHECK: JS
|
||||
import helpers.*
|
||||
import kotlin.coroutines.experimental.*
|
||||
|
||||
tailrec suspend fun foo(x: Int) {
|
||||
if (x == 0) return
|
||||
return (foo(x - 1))
|
||||
}
|
||||
|
||||
fun builder(c: suspend () -> Unit) {
|
||||
c.startCoroutine(EmptyContinuation)
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
builder {
|
||||
foo(1000000)
|
||||
}
|
||||
return "OK"
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
// WITH_RUNTIME
|
||||
// WITH_COROUTINES
|
||||
// IGNORE_BACKEND_WITHOUT_CHECK: JS
|
||||
import helpers.*
|
||||
import kotlin.coroutines.experimental.*
|
||||
|
||||
tailrec suspend fun withWhen(counter : Int, d : Any) : Int =
|
||||
if (counter == 0) {
|
||||
0
|
||||
}
|
||||
else if (counter == 5) {
|
||||
withWhen(counter - 1, 999)
|
||||
}
|
||||
else
|
||||
when (d) {
|
||||
is String -> withWhen(counter - 1, "is String")
|
||||
is Number -> withWhen(counter, "is Number")
|
||||
else -> throw IllegalStateException()
|
||||
}
|
||||
|
||||
fun builder(c: suspend () -> Unit) {
|
||||
c.startCoroutine(EmptyContinuation)
|
||||
}
|
||||
|
||||
fun box() : String {
|
||||
var res = -1
|
||||
builder {
|
||||
res = withWhen(100000, "test")
|
||||
}
|
||||
return if (res == 0) "OK" else "FAIL"
|
||||
}
|
||||
Reference in New Issue
Block a user