Problem with inline functions with coroutines and exposed

Hi,

The following code does not compile. It is based on the pipeline example. The problem is in the produceNumbers function. The send call of the producer is embedded in a lambda. This works if the lambda is inline. (see someInlineLamda). The transaction call is not inline and gives a compile error (Error:(24, 13) Kotlin: Suspension functions can be called only within coroutine body).

If I move the transaction code to another inline lambda (see someInlineTransactionLambda) the lambda needs to be crossinline due to non-local returns but the error remains.

Any ideas on how to resolve this?

import kotlinx.coroutines.experimental.*
import kotlinx.coroutines.experimental.channels.*
import org.jetbrains.exposed.sql.transactions.transaction

inline fun <E> someInlineLambda(x: Int, function: (Int) -> E): Unit {
    for (i in 0..1) 
        function(x)
}

inline fun <E> someInlineTransactionLambda(x: Int, crossinline function: (Int) -> E): Unit {
    transaction {
        for (i in 0..1) {
            function(x)
        }
    }
}

fun produceNumbers() = produce<Int>(CommonPool) {
    var x = 1
    while (true) {
        someInlineLambda(x) {
            send(x++)     // OK - inline lambda
        }
        transaction {    // start transaction in exposed land
            send(x++)    // Error:(24, 13) Kotlin: Suspension functions can be called only within coroutine body
        }
        someInlineTransactionLamda {    // start transaction in exposed land, wrapped in inline lambda
            send(x++)    // did not work :(
        }
    }
}

fun square(numbers: ReceiveChannel<Int>) = produce<Int>(CommonPool) {
    for (x in numbers) send(x * x)
}

fun main(args: Array<String>) = runBlocking<Unit> {
    val numbers = produceNumbers() // produces integers from 1 and on
    val squares = square(numbers) // squares integers
    for (i in 1..5) println(squares.receive()) // print first five
    println("Done!") // we are done
    squares.cancel() // need to cancel these coroutines in a larger app
    numbers.cancel()
}

To make non-inline function work with suspensions you’ll have to explicitly mark the functions and their lambda arguments with suspend keyword.

Ok got it. Thanks.