Repository: Kotlin/kotlinx.coroutines
File: kotlinx-coroutines-core/jvm/src/internal/ExceptionsConstructor.kt (Kotlin)

Code before:
    /*
     * Try to reflectively find constructor(message, cause), constructor(message), constructor(cause), or constructor()
     * Exceptions are shared among coroutines, so we should copy exception before recovering current stacktrace.
     *
     * By default, Java's reflection iterates over ctors in the source-code order and the sorting is stable,
     * so in comparator we are picking the message ctor over the cause one to break such implcit dependency on the source code.
     */
    val constructors = clz.constructors.sortedByDescending {
        // (m, c) -> 3
        // (m) -> 2
        // (c) -> 1
        // () -> 0
        val params = it.parameterTypes // cloned array
        when (params.size) {
            2 -> 3
            1 -> if (params[0] == String::class.java) 2 else 1
            0 -> 0
            else -> -1
        }

    }
    for (constructor in constructors) {
        val result = createSafeConstructor(constructor)
        if (result != null) return result
    }
    return nullResult
}

private fun createSafeConstructor(constructor: Constructor<*>): Ctor? {
    val p = constructor.parameterTypes
    return when (p.size) {
        2 -> when {
            p[0] == String::class.java && p[1] == Throwable::class.java ->
                safeCtor { e -> constructor.newInstance(e.message, e) as Throwable }
            else -> null
        }
        1 -> when (p[0]) {
            Throwable::class.java ->
                safeCtor { e -> constructor.newInstance(e) as Throwable }
            String::class.java ->
                safeCtor { e -> (constructor.newInstance(e.message) as Throwable).also { it.initCause(e) } }
            else -> null
        }
        0 -> safeCtor { e -> (constructor.newInstance() as Throwable).also { it.initCause(e) } }
        else -> null
    }
}

private inline fun safeCtor(crossinline block: (Throwable) -> Throwable): Ctor = { e ->
    runCatching {
        val result = block(e)

Review comment (suggestion):
I agree with the change, but I'd like to propose a stylistic edit: https://gist.github.com/dkhalanskyjb/2c2b4362920a01aafb3955216fd0e501 It makes the code more straightforward, in my view, but leads to calls to `safeCtor` even for constructors that don't get chosen in the end.

Code after:
    /*
     * Try to reflectively find constructor(message, cause), constructor(message), constructor(cause), or constructor(),
     * in that order of priority.
     * Exceptions are shared among coroutines, so we should copy exception before recovering current stacktrace.
     *
     * By default, Java's reflection iterates over ctors in the source-code order and the sorting is stable, so we can
     * not rely on the order of iteration. Instead, we assign a unique priority to each ctor type.
     */
    return clz.constructors.map { constructor ->
        val p = constructor.parameterTypes
        when (p.size) {
            2 -> when {
                p[0] == String::class.java && p[1] == Throwable::class.java ->
                    safeCtor { e -> constructor.newInstance(e.message, e) as Throwable } to 3
                else -> null to -1
            }
            1 -> when (p[0]) {
                String::class.java ->
                    safeCtor { e -> (constructor.newInstance(e.message) as Throwable).also { it.initCause(e) } } to 2
                Throwable::class.java ->
                    safeCtor { e -> constructor.newInstance(e) as Throwable } to 1
                else -> null to -1
            }
            0 -> safeCtor { e -> (constructor.newInstance() as Throwable).also { it.initCause(e) } } to 0
            else -> null to -1
        }
    }.maxByOrNull(Pair<*, Int>::second)?.first ?: nullResult
}

private fun safeCtor(block: (Throwable) -> Throwable): Ctor = { e ->
    runCatching {
        val result = block(e)
        /*
         * Verify that the new exception has the same message as the original one (bail out if not, see #1631)
         * or if the new message complies the contract from `Throwable(cause).message` contract.
         */
        if (e.message != result.message && result.message != e.toString()) null
        else result
    }.getOrNull()
}

private fun Class<*>.fieldsCountOrDefault(defaultValue: Int) =
    kotlin.runCatching { fieldsCount() }.getOrDefault(defaultValue)

private tailrec fun Class<*>.fieldsCount(accumulator: Int = 0): Int {
    val fieldsCount = declaredFields.count { !Modifier.isStatic(it.modifiers) }
    val totalFields = accumulator + fieldsCount
    val superClass = superclass ?: return totalFields
    return superClass.fieldsCount(totalFields)
}