Fixed a bug when onUndeliveredElement was invoked for normally-receive elements on JS (#2828)
Fixes #2826
diff --git a/kotlinx-coroutines-core/common/test/channels/ChannelUndeliveredElementTest.kt b/kotlinx-coroutines-core/common/test/channels/ChannelUndeliveredElementTest.kt
index 9915d38..f26361f 100644
--- a/kotlinx-coroutines-core/common/test/channels/ChannelUndeliveredElementTest.kt
+++ b/kotlinx-coroutines-core/common/test/channels/ChannelUndeliveredElementTest.kt
@@ -123,4 +123,19 @@
check(!_cancelled.getAndSet(true)) { "Already cancelled" }
}
}
+
+ @Test
+ fun testHandlerIsNotInvoked() = runTest { // #2826
+ val channel = Channel<Unit> {
+ expectUnreached()
+ }
+
+ expect(1)
+ launch {
+ expect(2)
+ channel.receive()
+ }
+ channel.send(Unit)
+ finish(3)
+ }
}
diff --git a/kotlinx-coroutines-core/js/src/internal/LinkedList.kt b/kotlinx-coroutines-core/js/src/internal/LinkedList.kt
index f2711f5..147b31d 100644
--- a/kotlinx-coroutines-core/js/src/internal/LinkedList.kt
+++ b/kotlinx-coroutines-core/js/src/internal/LinkedList.kt
@@ -32,7 +32,18 @@
this._prev = node
}
+ /*
+ * Remove that is invoked as a virtual function with a
+ * potentially augmented behaviour.
+ * I.g. `LockFreeLinkedListHead` throws, while `SendElementWithUndeliveredHandler`
+ * invokes handler on remove
+ */
public open fun remove(): Boolean {
+ return removeImpl()
+ }
+
+ @PublishedApi
+ internal fun removeImpl(): Boolean {
if (_removed) return false
val prev = this._prev
val next = this._next
@@ -76,7 +87,7 @@
public fun removeFirstOrNull(): Node? {
val next = _next
if (next === this) return null
- check(next.remove()) { "Should remove" }
+ check(next.removeImpl()) { "Should remove" }
return next
}
@@ -85,7 +96,7 @@
if (next === this) return null
if (next !is T) return null
if (predicate(next)) return next
- check(next.remove()) { "Should remove" }
+ check(next.removeImpl()) { "Should remove" }
return next
}
}