Closed

Description
When using channel with any buffer size, after filling full buffer with some elements, and then sending even more (those calls will suspend), after receiving first value from buffer, on first element, where send
suspends, onUndeliveredElement
will be called, and after next receive, onUndeliveredElement
will be called on next element and so on, so calling onUndeliveredElement
on all elements, that overflow buffer.
Reproducer:
class Resource(val i: Int) {
var closed = false
override fun toString(): String = "Resource($i, closed=$closed)"
}
@Test
fun testChannel() = test { //promise on js, runBlocking on jvm
val channel = Channel<Resource>(3) {
println("CLOSE: $it")
it.closed = true
}
val job = launch {
repeat(6) {
println("RECEIVE - ${channel.receive()}")
}
}
(0..5).map {
val r = Resource(it)
async {
println("SEND: $r")
channel.send(r)
println("SENT: $r")
}
}.awaitAll()
job.join()
}
JVM/Native output - expected:
SEND: Resource(0, closed=false)
SENT: Resource(0, closed=false)
SEND: Resource(1, closed=false)
SENT: Resource(1, closed=false)
SEND: Resource(2, closed=false)
SENT: Resource(2, closed=false)
SEND: Resource(3, closed=false)
SENT: Resource(3, closed=false)
SEND: Resource(4, closed=false)
SEND: Resource(5, closed=false)
RECEIVE - Resource(0, closed=false)
RECEIVE - Resource(1, closed=false)
RECEIVE - Resource(2, closed=false)
RECEIVE - Resource(3, closed=false)
RECEIVE - Resource(4, closed=false)
RECEIVE - Resource(5, closed=false)
SENT: Resource(4, closed=false)
SENT: Resource(5, closed=false)
JS (same for browser/node legacy/IR) output - wrong:
SEND: Resource(0, closed=false)
SENT: Resource(0, closed=false)
SEND: Resource(1, closed=false)
SENT: Resource(1, closed=false)
SEND: Resource(2, closed=false)
SENT: Resource(2, closed=false)
SEND: Resource(3, closed=false)
SENT: Resource(3, closed=false)
SEND: Resource(4, closed=false)
SEND: Resource(5, closed=false)
RECEIVE - Resource(0, closed=false)
CLOSE: Resource(4, closed=false)
RECEIVE - Resource(1, closed=false)
CLOSE: Resource(5, closed=false)
RECEIVE - Resource(2, closed=false)
RECEIVE - Resource(3, closed=false)
RECEIVE - Resource(4, closed=true)
RECEIVE - Resource(5, closed=true)
SENT: Resource(4, closed=true)
SENT: Resource(5, closed=true)
Expected result:
There should be no calls to onUndeliveredElement
in such case
Env:
kotlinVersion=1.5.21
kotlinxCoroutinesVersion=1.5.1-native-mt