Edoardo Luppi
08/29/2023, 2:03 PMdmitriy.novozhilov
08/29/2023, 2:12 PMdmitriy.novozhilov
08/29/2023, 2:13 PM@OptIn(ExperimentalContracts::class)
fun test(block: () -> Unit) {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
invokeLater(block)
}
fun invokeLater(block: () -> Unit) {
// send `block` to thread pool
}
dmitriy.novozhilov
08/29/2023, 2:14 PMEdoardo Luppi
08/29/2023, 2:21 PMdmitriy.novozhilov
08/29/2023, 2:23 PMinline
but how you use passed lambda
This function is entirely correct
@OptIn(ExperimentalContracts::class)
fun notInlineRun(block: () -> Unit) {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
block()
}
block
is called inside function test
, caleed exactly once and not saved in any state which potentially may invoke this lambda laterdmitriy.novozhilov
08/29/2023, 2:24 PMinline
function (without noinline
or crossinline
modifier) automatically gets contract callsInPlace(block, InvocationKind.UNKNOWN)
Edoardo Luppi
08/29/2023, 2:25 PMpublic suspend fun <R> ZSocket.use(block: suspend (ZSocket) -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
var throwable: Throwable? = null
return try {
block(this) // Called here
} catch (t: Throwable) {
throwable = t
throw t
} finally {
...
}
}
This is where it was marking the warningdmitriy.novozhilov
08/29/2023, 2:30 PMtry/catch/finally
expression is try
block, including its very beginning, before call to block(this)
(well, technically OutOfMemoryError
actually can be thrown from anywhere). So compiler think that there is a way when function without invocation of block
dmitriy.novozhilov
08/29/2023, 2:32 PMdmitriy.novozhilov
08/29/2023, 2:33 PM@Suppress("WRONG_INVOCATION_KIND")
if warning annoys youEdoardo Luppi
08/29/2023, 2:33 PMkirillrakhman
08/31/2023, 7:41 AMEdoardo Luppi
08/31/2023, 8:21 AMkirillrakhman
08/31/2023, 8:23 AM