Skip to content

Commit 0f519a2

Browse files
committed
Get rid of NonRecoverableThrowable, mention way to opt-out stacktrace recovery in debugging.md
1 parent a3763e8 commit 0f519a2

File tree

4 files changed

+16
-21
lines changed

4 files changed

+16
-21
lines changed

docs/debugging.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ It is easy to demonstrate with actual stacktraces of the same program that await
4545

4646
The only downside of this approach is losing referential transparency of the exception.
4747

48-
### Stacktrace recovery machinery
48+
### Stacktrace recovery machinery
4949

5050
This section explains the inner mechanism of stacktrace recovery and can be skipped.
5151

@@ -56,6 +56,7 @@ and then throws the resulting exception instead of the original one.
5656

5757
Exception copy logic is straightforward:
5858
1) If the exception class implements [CopyableThrowable], [CopyableThrowable.createCopy] is used.
59+
`null` can be returned from `createCopy` to opt-out specific exception from being recovered.
5960
2) If the exception class has class-specific fields not inherited from Throwable, the exception is not copied.
6061
3) Otherwise, one of the public exception's constructor is invoked reflectively with an optional `initCause` call.
6162

kotlinx-coroutines-core/common/src/internal/StackTraceRecovery.common.kt

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,3 @@ internal expect interface CoroutineStackFrame {
4242
public val callerFrame: CoroutineStackFrame?
4343
public fun getStackTraceElement(): StackTraceElement?
4444
}
45-
46-
/**
47-
* Marker that indicates that stacktrace of the exception should not be recovered.
48-
* Currently internal, but may become public in the future
49-
*/
50-
internal interface NonRecoverableThrowable

kotlinx-coroutines-core/common/test/TestBase.common.kt

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@
22
* Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
33
*/
44

5+
@file:Suppress("unused")
6+
57
package kotlinx.coroutines
68

79
import kotlinx.coroutines.flow.*
810
import kotlin.coroutines.*
9-
import kotlinx.coroutines.internal.*
1011
import kotlin.test.*
1112

1213
public expect open class TestBase constructor() {
@@ -56,12 +57,14 @@ public suspend inline fun <reified T : Throwable> assertFailsWith(flow: Flow<*>)
5657
public suspend fun Flow<Int>.sum() = fold(0) { acc, value -> acc + value }
5758
public suspend fun Flow<Long>.longSum() = fold(0L) { acc, value -> acc + value }
5859

59-
public class TestException(message: String? = null) : Throwable(message), NonRecoverableThrowable
60-
public class TestException1(message: String? = null) : Throwable(message), NonRecoverableThrowable
61-
public class TestException2(message: String? = null) : Throwable(message), NonRecoverableThrowable
62-
public class TestException3(message: String? = null) : Throwable(message), NonRecoverableThrowable
63-
public class TestCancellationException(message: String? = null) : CancellationException(message), NonRecoverableThrowable
64-
public class TestRuntimeException(message: String? = null) : RuntimeException(message), NonRecoverableThrowable
60+
61+
// data is added to avoid stacktrace recovery because CopyableThrowable is not accessible from common modules
62+
public class TestException(message: String? = null, private val data: Any? = null) : Throwable(message)
63+
public class TestException1(message: String? = null, private val data: Any? = null) : Throwable(message)
64+
public class TestException2(message: String? = null, private val data: Any? = null) : Throwable(message)
65+
public class TestException3(message: String? = null, private val data: Any? = null) : Throwable(message)
66+
public class TestCancellationException(message: String? = null, private val data: Any? = null) : CancellationException(message)
67+
public class TestRuntimeException(message: String? = null, private val data: Any? = null) : RuntimeException(message)
6568
public class RecoverableTestException(message: String? = null) : RuntimeException(message)
6669
public class RecoverableTestCancellationException(message: String? = null) : CancellationException(message)
6770

kotlinx-coroutines-core/jvm/src/internal/StackTraceRecovery.kt

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import kotlin.coroutines.*
1212
import kotlin.coroutines.intrinsics.*
1313

1414
internal actual fun <E : Throwable> recoverStackTrace(exception: E): E {
15-
if (recoveryDisabled(exception)) return exception
15+
if (!RECOVER_STACK_TRACES) return exception
1616
// No unwrapping on continuation-less path: exception is not reported multiple times via slow paths
1717
val copy = tryCopyException(exception) ?: return exception
1818
return copy.sanitizeStackTrace()
@@ -39,7 +39,7 @@ private fun <E : Throwable> E.sanitizeStackTrace(): E {
3939
}
4040

4141
internal actual fun <E : Throwable> recoverStackTrace(exception: E, continuation: Continuation<*>): E {
42-
if (recoveryDisabled(exception) || continuation !is CoroutineStackFrame) return exception
42+
if (!RECOVER_STACK_TRACES || continuation !is CoroutineStackFrame) return exception
4343
return recoverFromStackFrame(exception, continuation)
4444
}
4545

@@ -133,15 +133,15 @@ private fun mergeRecoveredTraces(recoveredStacktrace: Array<StackTraceElement>,
133133

134134
@Suppress("NOTHING_TO_INLINE")
135135
internal actual suspend inline fun recoverAndThrow(exception: Throwable): Nothing {
136-
if (recoveryDisabled(exception)) throw exception
136+
if (!RECOVER_STACK_TRACES) throw exception
137137
suspendCoroutineUninterceptedOrReturn<Nothing> {
138138
if (it !is CoroutineStackFrame) throw exception
139139
throw recoverFromStackFrame(exception, it)
140140
}
141141
}
142142

143143
internal actual fun <E : Throwable> unwrap(exception: E): E {
144-
if (recoveryDisabled(exception)) return exception
144+
if (!RECOVER_STACK_TRACES) return exception
145145
val cause = exception.cause
146146
// Fast-path to avoid array cloning
147147
if (cause == null || cause.javaClass != exception.javaClass) {
@@ -156,9 +156,6 @@ internal actual fun <E : Throwable> unwrap(exception: E): E {
156156
}
157157
}
158158

159-
private fun <E : Throwable> recoveryDisabled(exception: E) =
160-
!RECOVER_STACK_TRACES || exception is NonRecoverableThrowable
161-
162159
private fun createStackTrace(continuation: CoroutineStackFrame): ArrayDeque<StackTraceElement> {
163160
val stack = ArrayDeque<StackTraceElement>()
164161
continuation.getStackTraceElement()?.let { stack.add(it) }

0 commit comments

Comments
 (0)