Skip to content

Commit 38c3e9a

Browse files
committed
Recover stacktrace on the fast-path of receiveOrNull
1 parent 7f1a927 commit 38c3e9a

File tree

3 files changed

+21
-3
lines changed

3 files changed

+21
-3
lines changed

kotlinx-coroutines-core/common/src/channels/AbstractChannel.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -590,7 +590,8 @@ internal abstract class AbstractChannel<E> : AbstractSendChannel<E>(), Channel<E
590590
public final override suspend fun receiveOrNull(): E? {
591591
// fast path -- try poll non-blocking
592592
val result = pollInternal()
593-
if (result !== POLL_FAILED) return receiveOrNullResult(result)
593+
@Suppress("UNCHECKED_CAST")
594+
if (result !== POLL_FAILED && result !is Closed<*>) return result as E
594595
// slow-path does suspend
595596
return receiveSuspend(RECEIVE_NULL_ON_CLOSE)
596597
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
kotlinx.coroutines.RecoverableTestException
2+
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest$testReceiveOrNullFromClosedChannel$1.invokeSuspend(StackTraceRecoveryChannelsTest.kt:43)
3+
(Coroutine boundary)
4+
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest.channelReceiveOrNull(StackTraceRecoveryChannelsTest.kt:70)
5+
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest$testReceiveOrNullFromClosedChannel$1.invokeSuspend(StackTraceRecoveryChannelsTest.kt:44)
6+
Caused by: kotlinx.coroutines.RecoverableTestException
7+
at kotlinx.coroutines.exceptions.StackTraceRecoveryChannelsTest$testReceiveOrNullFromClosedChannel$1.invokeSuspend(StackTraceRecoveryChannelsTest.kt:43)
8+
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)

kotlinx-coroutines-core/jvm/test/exceptions/StackTraceRecoveryChannelsTest.kt

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,12 @@ class StackTraceRecoveryChannelsTest : TestBase() {
3737
channelReceive(channel)
3838
}
3939

40+
@Test
41+
fun testReceiveOrNullFromClosedChannel() = runTest {
42+
val channel = Channel<Int>()
43+
channel.close(RecoverableTestException())
44+
channelReceiveOrNull(channel)
45+
}
4046

4147
@Test
4248
fun testSendToClosedChannel() = runTest {
@@ -60,10 +66,13 @@ class StackTraceRecoveryChannelsTest : TestBase() {
6066
finish(4)
6167
}
6268

63-
private suspend fun channelReceive(channel: Channel<Int>) {
69+
private suspend fun channelReceive(channel: Channel<Int>) = channelOp { channel.receive() }
70+
private suspend fun channelReceiveOrNull(channel: Channel<Int>) = channelOp { channel.receiveOrNull() }
71+
72+
private suspend inline fun channelOp(block: () -> Unit) {
6473
try {
6574
yield()
66-
channel.receive()
75+
block()
6776
expectUnreached()
6877
} catch (e: RecoverableTestException) {
6978
verifyStackTrace("channels/${name.methodName}", e)

0 commit comments

Comments
 (0)