From 1ff7f5f2ecfc5739d4c898365f86bc29f09cbc95 Mon Sep 17 00:00:00 2001 From: Youssef Shoaib Date: Sat, 18 May 2024 02:19:51 +0100 Subject: [PATCH 1/5] Clean up AutoCloseScope and ResourceScope and add inline to them --- .../commonMain/kotlin/arrow/AutoCloseScope.kt | 64 ++++---- .../src/jvmMain/kotlin/arrow/throwIfFatal.kt | 4 +- .../kotlin/arrow/fx/coroutines/Bracket.kt | 25 +-- .../kotlin/arrow/fx/coroutines/Resource.kt | 154 ++++++------------ .../arrow/fx/coroutines/ResourceTest.kt | 9 +- .../kotlin/examples/example-resource-04.kt | 1 + .../kotlin/examples/example-resource-05.kt | 1 + .../kotlin/examples/example-resource-06.kt | 1 + .../kotlin/examples/example-resource-07.kt | 1 + 9 files changed, 104 insertions(+), 156 deletions(-) diff --git a/arrow-libs/core/arrow-autoclose/src/commonMain/kotlin/arrow/AutoCloseScope.kt b/arrow-libs/core/arrow-autoclose/src/commonMain/kotlin/arrow/AutoCloseScope.kt index d42f23cd54d..7ecb6073c0f 100644 --- a/arrow-libs/core/arrow-autoclose/src/commonMain/kotlin/arrow/AutoCloseScope.kt +++ b/arrow-libs/core/arrow-autoclose/src/commonMain/kotlin/arrow/AutoCloseScope.kt @@ -2,7 +2,8 @@ package arrow import arrow.atomic.Atomic import arrow.atomic.update -import kotlin.coroutines.cancellation.CancellationException +import arrow.atomic.value +import kotlin.jvm.JvmInline /** * The [AutoCloseScope] DSL allows for elegantly working with close-ables, @@ -61,53 +62,46 @@ import kotlin.coroutines.cancellation.CancellationException * ``` * */ -public inline fun autoCloseScope(block: AutoCloseScope.() -> A): A { - val scope = DefaultAutoCloseScope() - return try { - block(scope) - .also { scope.close(null) } - } catch (e: CancellationException) { - scope.close(e) ?: throw e +public inline fun autoCloseScope(block: AutoCloseScope.() -> A): A = with(DefaultAutoCloseScope()) { + try { + block() } catch (e: Throwable) { - scope.close(e.throwIfFatal()) ?: throw e - } + closeAll(e.throwIfFatal()) + error("Unreachable, closeAll should throw the exception passed to it. Please report this bug to the Arrow team.") + }.also { closeAll(null) } } public interface AutoCloseScope { - public fun autoClose( - acquire: () -> A, - release: (A, Throwable?) -> Unit - ): A + public fun onClose(release: (Throwable?) -> Unit) - @ExperimentalStdlibApi public fun install(autoCloseable: A): A = - autoClose({ autoCloseable }) { a, _ -> a.close() } + autoCloseable.also { onClose { autoCloseable.close() } } } -@PublishedApi -internal class DefaultAutoCloseScope : AutoCloseScope { - private val finalizers = Atomic(emptyList<(Throwable?) -> Unit>()) +public inline fun AutoCloseScope.autoClose( + acquire: () -> A, + crossinline release: (A, Throwable?) -> Unit +): A = acquire().also { a -> onClose { e -> release(a, e) } } - override fun autoClose(acquire: () -> A, release: (A, Throwable?) -> Unit): A = - try { - acquire().also { a -> - finalizers.update { it + { e -> release(a, e) } } - } - } catch (e: Throwable) { - throw e - } +@JvmInline +@PublishedApi +internal value class DefaultAutoCloseScope( + private val finalizers: Atomic Unit>> = Atomic(emptyList()) +) : AutoCloseScope { + override fun onClose(release: (Throwable?) -> Unit) = + finalizers.update { listOf(release) + it } - fun close(error: Throwable?): Nothing? { - return finalizers.get().asReversed().fold(error) { acc, function -> - acc.add(runCatching { function.invoke(error) }.exceptionOrNull()) + fun closeAll(error: Throwable?) { + finalizers.value.fold(error) { acc, function -> + acc.add(runCatching { function(error) }.exceptionOrNull()) }?.let { throw it } } - - private fun Throwable?.add(other: Throwable?): Throwable? = - this?.apply { - other?.let { addSuppressed(it) } - } ?: other } +private fun Throwable?.add(other: Throwable?): Throwable? = + this?.apply { + other?.let { addSuppressed(it) } + } ?: other + @PublishedApi internal expect fun Throwable.throwIfFatal(): Throwable diff --git a/arrow-libs/core/arrow-autoclose/src/jvmMain/kotlin/arrow/throwIfFatal.kt b/arrow-libs/core/arrow-autoclose/src/jvmMain/kotlin/arrow/throwIfFatal.kt index c9a3ed4ce17..1df21689738 100644 --- a/arrow-libs/core/arrow-autoclose/src/jvmMain/kotlin/arrow/throwIfFatal.kt +++ b/arrow-libs/core/arrow-autoclose/src/jvmMain/kotlin/arrow/throwIfFatal.kt @@ -1,10 +1,8 @@ package arrow -import kotlin.coroutines.cancellation.CancellationException - @PublishedApi internal actual fun Throwable.throwIfFatal(): Throwable = when(this) { - is VirtualMachineError, is ThreadDeath, is InterruptedException, is LinkageError, is CancellationException -> throw this + is VirtualMachineError, is ThreadDeath, is InterruptedException, is LinkageError -> throw this else -> this } diff --git a/arrow-libs/fx/arrow-fx-coroutines/src/commonMain/kotlin/arrow/fx/coroutines/Bracket.kt b/arrow-libs/fx/arrow-fx-coroutines/src/commonMain/kotlin/arrow/fx/coroutines/Bracket.kt index 983dc48e558..bf80c839faa 100644 --- a/arrow-libs/fx/arrow-fx-coroutines/src/commonMain/kotlin/arrow/fx/coroutines/Bracket.kt +++ b/arrow-libs/fx/arrow-fx-coroutines/src/commonMain/kotlin/arrow/fx/coroutines/Bracket.kt @@ -5,21 +5,26 @@ import kotlinx.coroutines.CancellationException import kotlinx.coroutines.NonCancellable import kotlinx.coroutines.withContext -public sealed class ExitCase { - public object Completed : ExitCase() { - override fun toString(): String = - "ExitCase.Completed" - } - - public data class Cancelled(val exception: CancellationException) : ExitCase() - public data class Failure(val failure: Throwable) : ExitCase() +public sealed interface ExitCase { + public data object Completed : ExitCase + public data class Cancelled(val exception: CancellationException) : ExitCase + public data class Failure(val failure: Throwable) : ExitCase public companion object { - public fun ExitCase(error: Throwable): ExitCase = - if (error is CancellationException) Cancelled(error) else Failure(error) + public fun ExitCase(error: Throwable?): ExitCase = when (error) { + null -> Completed + is CancellationException -> Cancelled(error) + else -> Failure(error) + } } } +public val ExitCase.throwableOrNull: Throwable? get() = when (this) { + ExitCase.Completed -> null + is ExitCase.Cancelled -> exception + is ExitCase.Failure -> failure +} + /** * Registers an [onCancel] handler after [fa]. * [onCancel] is guaranteed to be called in case of cancellation, otherwise it's ignored. diff --git a/arrow-libs/fx/arrow-fx-coroutines/src/commonMain/kotlin/arrow/fx/coroutines/Resource.kt b/arrow-libs/fx/arrow-fx-coroutines/src/commonMain/kotlin/arrow/fx/coroutines/Resource.kt index 618b06634b8..24205f240cd 100644 --- a/arrow-libs/fx/arrow-fx-coroutines/src/commonMain/kotlin/arrow/fx/coroutines/Resource.kt +++ b/arrow-libs/fx/arrow-fx-coroutines/src/commonMain/kotlin/arrow/fx/coroutines/Resource.kt @@ -4,13 +4,9 @@ import arrow.AutoCloseScope import arrow.atomic.update import arrow.atomic.Atomic import arrow.atomic.value -import arrow.core.identity import arrow.core.prependTo -import arrow.fx.coroutines.ExitCase.Cancelled import arrow.fx.coroutines.ExitCase.Companion.ExitCase import arrow.fx.coroutines.ExitCase.Completed -import arrow.fx.coroutines.ExitCase.Failure -import kotlinx.coroutines.CancellationException import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.NonCancellable import kotlinx.coroutines.flow.Flow @@ -179,6 +175,7 @@ public annotation class ResourceDSL * */ @ScopeDSL -public suspend fun resourceScope(action: suspend ResourceScope.() -> A): A { - val scope = ResourceScopeImpl() - val a: A = try { - action(scope) +public suspend inline fun resourceScope(action: ResourceScope.() -> A): A = with(ResourceScopeImpl()) { + try { + action() } catch (e: Throwable) { - val ex = if (e is CancellationException) ExitCase.Cancelled(e) else ExitCase.Failure(e) - val ee = withContext(NonCancellable) { - scope.cancelAll(ex, e) ?: e - } - throw ee - } - withContext(NonCancellable) { - scope.cancelAll(ExitCase.Completed)?.let { throw it } - } - return a + cancelAll(ExitCase(e)) + error("Unreachable, cancelAll should throw the exception passed to it. Please report this bug to the Arrow team.") + }.also { cancelAll(Completed) } +} + +/** + * Install [A] into the [ResourceScope]. + * It's [release] function will be called with the appropriate [ExitCase] if this [ResourceScope] finishes. + * It results either in [ExitCase.Completed], [ExitCase.Cancelled] or [ExitCase.Failure] depending on the terminal state of [Resource] lambda. + */ +@ResourceDSL +public suspend inline fun ResourceScope.install( + crossinline acquire: suspend AcquireStep.() -> A, + crossinline release: suspend (A, ExitCase) -> Unit, +): A = withContext(NonCancellable) { + acquire(AcquireStep).also { onRelease { ex -> release(it, ex) } } } public suspend infix fun Resource.use(f: suspend (A) -> B): B = @@ -381,6 +372,7 @@ public suspend infix fun Resource.use(f: suspend (A) -> B): B = * Construct a [Resource] from an allocating function [acquire] and a release function [release]. * * ```kotlin + * import arrow.fx.coroutines.install * import arrow.fx.coroutines.resource * import arrow.fx.coroutines.resourceScope * @@ -397,9 +389,9 @@ public suspend infix fun Resource.use(f: suspend (A) -> B): B = * ``` * */ -public fun resource( - acquire: suspend () -> A, - release: suspend (A, ExitCase) -> Unit, +public inline fun resource( + crossinline acquire: suspend () -> A, + crossinline release: suspend (A, ExitCase) -> Unit, ): Resource = resource { install({ acquire() }, release) } @@ -470,71 +462,29 @@ public fun Resource.asFlow(): Flow = * This API is useful for building inter-op APIs between [Resource] and non-suspending code, such as Java libraries. */ @DelicateCoroutinesApi -public suspend fun Resource.allocated(): Pair Unit> { - val effect = ResourceScopeImpl() - val allocated: A = invoke(effect) - val release: suspend (ExitCase) -> Unit = { e -> - val suppressed: Throwable? = effect.cancelAll(e) - val original: Throwable? = when(e) { - ExitCase.Completed -> null - is ExitCase.Cancelled -> e.exception - is ExitCase.Failure -> e.failure - } - original?.apply { - suppressed?.let(::addSuppressed) - }?.let { throw it } - } - return Pair(allocated, release) +public suspend fun Resource.allocated(): Pair Unit> = with(ResourceScopeImpl()){ + // TODO: Should we cancelAll if bind fails? + bind() to ::cancelAll } @JvmInline -private value class ResourceScopeImpl( +@PublishedApi +internal value class ResourceScopeImpl( private val finalizers: Atomic Unit>> = Atomic(emptyList()), ) : ResourceScope { - override suspend fun Resource.bind(): A = invoke(this@ResourceScopeImpl) - - override suspend fun install(acquire: suspend AcquireStep.() -> A, release: suspend (A, ExitCase) -> Unit): A = - bracketCase({ - val a = acquire(AcquireStep) - val finalizer: suspend (ExitCase) -> Unit = { ex: ExitCase -> release(a, ex) } - finalizers.update(finalizer::prependTo) - a - }, ::identity, { a, ex -> - // Only if ExitCase.Failure, or ExitCase.Cancelled during acquire we cancel - // Otherwise we've saved the finalizer, and it will be called from somewhere else. - if (ex != ExitCase.Completed) { - val e = cancelAll(ex) - val e2 = kotlin.runCatching { release(a, ex) }.exceptionOrNull() - e?.apply { - e2?.let(::addSuppressed) - }?.let { throw it } - } - }) - - override fun autoClose(acquire: () -> A, release: (A, Throwable?) -> Unit): A = - try { - acquire().also { a -> - val finalizer: suspend (ExitCase) -> Unit = { exitCase -> - val errorOrNull = when (exitCase) { - Completed -> null - is Cancelled -> exitCase.exception - is Failure -> exitCase.failure - } - release(a, errorOrNull) - } - finalizers.update { prev -> prev + finalizer } - } - } catch (e: Throwable) { - throw e - } + override fun onRelease(release: suspend (ExitCase) -> Unit) = + finalizers.update(release::prependTo) - suspend fun cancelAll( - exitCase: ExitCase, - first: Throwable? = null, - ): Throwable? = finalizers.value.fold(first) { acc, finalizer -> - val other = kotlin.runCatching { finalizer(exitCase) }.exceptionOrNull() - other?.let { - acc?.apply { addSuppressed(other) } ?: other - } ?: acc + suspend fun cancelAll(exitCase: ExitCase): Unit = withContext(NonCancellable) { + finalizers.value.fold(exitCase.throwableOrNull) { acc, finalizer -> + val e = runCatching { finalizer(exitCase) }.exceptionOrNull() + println("Adding $e with $acc") + acc.add(e) + }?.let { throw it } } } + +private fun Throwable?.add(other: Throwable?): Throwable? = + this?.apply { + other?.let(::addSuppressed) + } ?: other diff --git a/arrow-libs/fx/arrow-fx-coroutines/src/commonTest/kotlin/arrow/fx/coroutines/ResourceTest.kt b/arrow-libs/fx/arrow-fx-coroutines/src/commonTest/kotlin/arrow/fx/coroutines/ResourceTest.kt index 80d9dbac273..e5149a79a54 100644 --- a/arrow-libs/fx/arrow-fx-coroutines/src/commonTest/kotlin/arrow/fx/coroutines/ResourceTest.kt +++ b/arrow-libs/fx/arrow-fx-coroutines/src/commonTest/kotlin/arrow/fx/coroutines/ResourceTest.kt @@ -1,15 +1,13 @@ package arrow.fx.coroutines -import arrow.autoCloseScope import arrow.core.Either import arrow.core.left import arrow.core.raise.either import arrow.fx.coroutines.ExitCase.Companion.ExitCase import io.kotest.assertions.fail import io.kotest.assertions.throwables.shouldThrow -import io.kotest.assertions.throwables.shouldThrow import io.kotest.matchers.collections.shouldContainExactly -import io.kotest.matchers.nulls.shouldNotBeNull +import io.kotest.matchers.collections.shouldHaveSingleElement import io.kotest.matchers.should import io.kotest.matchers.shouldBe import io.kotest.matchers.types.shouldBeInstanceOf @@ -31,7 +29,6 @@ import kotlinx.coroutines.awaitCancellation import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.toList import kotlinx.coroutines.test.runTest -import kotlin.random.Random import kotlin.test.Test class ResourceTest { @@ -599,7 +596,7 @@ class ResourceTest { } exception shouldBe original - exception.suppressedExceptions.firstOrNull().shouldNotBeNull() shouldBe suppressed + exception.suppressedExceptions.shouldHaveSingleElement(suppressed) released.await().shouldBeTypeOf() } } @@ -629,7 +626,7 @@ class ResourceTest { } exception shouldBe cancellation - exception.suppressedExceptions.firstOrNull().shouldNotBeNull() shouldBe suppressed + exception.suppressedExceptions.shouldHaveSingleElement(suppressed) released.await().shouldBeTypeOf() } } diff --git a/arrow-libs/fx/arrow-fx-coroutines/src/jvmTest/kotlin/examples/example-resource-04.kt b/arrow-libs/fx/arrow-fx-coroutines/src/jvmTest/kotlin/examples/example-resource-04.kt index aab22cf814e..b64cde02384 100644 --- a/arrow-libs/fx/arrow-fx-coroutines/src/jvmTest/kotlin/examples/example-resource-04.kt +++ b/arrow-libs/fx/arrow-fx-coroutines/src/jvmTest/kotlin/examples/example-resource-04.kt @@ -3,6 +3,7 @@ package arrow.fx.coroutines.examples.exampleResource04 import arrow.fx.coroutines.ResourceScope import arrow.fx.coroutines.Resource +import arrow.fx.coroutines.install import arrow.fx.coroutines.resource import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext diff --git a/arrow-libs/fx/arrow-fx-coroutines/src/jvmTest/kotlin/examples/example-resource-05.kt b/arrow-libs/fx/arrow-fx-coroutines/src/jvmTest/kotlin/examples/example-resource-05.kt index ce20f638266..d75ef0520cc 100644 --- a/arrow-libs/fx/arrow-fx-coroutines/src/jvmTest/kotlin/examples/example-resource-05.kt +++ b/arrow-libs/fx/arrow-fx-coroutines/src/jvmTest/kotlin/examples/example-resource-05.kt @@ -2,6 +2,7 @@ package arrow.fx.coroutines.examples.exampleResource05 import arrow.fx.coroutines.ResourceScope +import arrow.fx.coroutines.install import arrow.fx.coroutines.resourceScope import arrow.fx.coroutines.parZip import kotlinx.coroutines.Dispatchers diff --git a/arrow-libs/fx/arrow-fx-coroutines/src/jvmTest/kotlin/examples/example-resource-06.kt b/arrow-libs/fx/arrow-fx-coroutines/src/jvmTest/kotlin/examples/example-resource-06.kt index 9a1bd665e14..52ef7f0036d 100644 --- a/arrow-libs/fx/arrow-fx-coroutines/src/jvmTest/kotlin/examples/example-resource-06.kt +++ b/arrow-libs/fx/arrow-fx-coroutines/src/jvmTest/kotlin/examples/example-resource-06.kt @@ -1,6 +1,7 @@ // This file was automatically generated from Resource.kt by Knit tool. Do not edit. package arrow.fx.coroutines.examples.exampleResource06 +import arrow.fx.coroutines.install import arrow.fx.coroutines.resourceScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext diff --git a/arrow-libs/fx/arrow-fx-coroutines/src/jvmTest/kotlin/examples/example-resource-07.kt b/arrow-libs/fx/arrow-fx-coroutines/src/jvmTest/kotlin/examples/example-resource-07.kt index 161326cdab0..5783224d774 100644 --- a/arrow-libs/fx/arrow-fx-coroutines/src/jvmTest/kotlin/examples/example-resource-07.kt +++ b/arrow-libs/fx/arrow-fx-coroutines/src/jvmTest/kotlin/examples/example-resource-07.kt @@ -1,6 +1,7 @@ // This file was automatically generated from Resource.kt by Knit tool. Do not edit. package arrow.fx.coroutines.examples.exampleResource07 +import arrow.fx.coroutines.install import arrow.fx.coroutines.resource import arrow.fx.coroutines.resourceScope From a1303b6d1afe17bb599db308b24d2623987ee5f1 Mon Sep 17 00:00:00 2001 From: Youssef Shoaib Date: Sat, 18 May 2024 02:26:26 +0100 Subject: [PATCH 2/5] Add back opt-in requirement for AutoCloseable --- .../src/commonMain/kotlin/arrow/AutoCloseScope.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/arrow-libs/core/arrow-autoclose/src/commonMain/kotlin/arrow/AutoCloseScope.kt b/arrow-libs/core/arrow-autoclose/src/commonMain/kotlin/arrow/AutoCloseScope.kt index 7ecb6073c0f..ebc572bc1bc 100644 --- a/arrow-libs/core/arrow-autoclose/src/commonMain/kotlin/arrow/AutoCloseScope.kt +++ b/arrow-libs/core/arrow-autoclose/src/commonMain/kotlin/arrow/AutoCloseScope.kt @@ -74,6 +74,7 @@ public inline fun autoCloseScope(block: AutoCloseScope.() -> A): A = with(De public interface AutoCloseScope { public fun onClose(release: (Throwable?) -> Unit) + @ExperimentalStdlibApi public fun install(autoCloseable: A): A = autoCloseable.also { onClose { autoCloseable.close() } } } From 4bf201e318c646faf050b3fb6c65ddc5eca4d60b Mon Sep 17 00:00:00 2001 From: Youssef Shoaib Date: Sat, 18 May 2024 05:39:46 +0100 Subject: [PATCH 3/5] Remove debugging println --- .../src/commonMain/kotlin/arrow/fx/coroutines/Resource.kt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/arrow-libs/fx/arrow-fx-coroutines/src/commonMain/kotlin/arrow/fx/coroutines/Resource.kt b/arrow-libs/fx/arrow-fx-coroutines/src/commonMain/kotlin/arrow/fx/coroutines/Resource.kt index 24205f240cd..0da44288256 100644 --- a/arrow-libs/fx/arrow-fx-coroutines/src/commonMain/kotlin/arrow/fx/coroutines/Resource.kt +++ b/arrow-libs/fx/arrow-fx-coroutines/src/commonMain/kotlin/arrow/fx/coroutines/Resource.kt @@ -477,9 +477,7 @@ internal value class ResourceScopeImpl( suspend fun cancelAll(exitCase: ExitCase): Unit = withContext(NonCancellable) { finalizers.value.fold(exitCase.throwableOrNull) { acc, finalizer -> - val e = runCatching { finalizer(exitCase) }.exceptionOrNull() - println("Adding $e with $acc") - acc.add(e) + acc.add(runCatching { finalizer(exitCase) }.exceptionOrNull()) }?.let { throw it } } } From 49ec9fcb2bffa5514d2e21fdcc4c17a814d4f330 Mon Sep 17 00:00:00 2001 From: kyay10 Date: Sat, 18 May 2024 04:42:53 +0000 Subject: [PATCH 4/5] Auto-update API files --- .../arrow-autoclose/api/arrow-autoclose.api | 21 ++++++++-- .../api/arrow-fx-coroutines.api | 42 ++++++++++++++++--- 2 files changed, 54 insertions(+), 9 deletions(-) diff --git a/arrow-libs/core/arrow-autoclose/api/arrow-autoclose.api b/arrow-libs/core/arrow-autoclose/api/arrow-autoclose.api index 76d49898115..7f47cf2fa58 100644 --- a/arrow-libs/core/arrow-autoclose/api/arrow-autoclose.api +++ b/arrow-libs/core/arrow-autoclose/api/arrow-autoclose.api @@ -1,6 +1,6 @@ public abstract interface class arrow/AutoCloseScope { - public abstract fun autoClose (Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object; public abstract fun install (Ljava/lang/AutoCloseable;)Ljava/lang/AutoCloseable; + public abstract fun onClose (Lkotlin/jvm/functions/Function1;)V } public final class arrow/AutoCloseScope$DefaultImpls { @@ -8,6 +8,7 @@ public final class arrow/AutoCloseScope$DefaultImpls { } public final class arrow/AutoCloseScopeKt { + public static final fun autoClose (Larrow/AutoCloseScope;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object; public static final fun autoCloseScope (Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; } @@ -16,10 +17,22 @@ public final class arrow/AutoCloseableExtensionsKt { } public final class arrow/DefaultAutoCloseScope : arrow/AutoCloseScope { - public fun ()V - public fun autoClose (Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object; - public final fun close (Ljava/lang/Throwable;)Ljava/lang/Void; + public static final synthetic fun box-impl (Ljava/util/concurrent/atomic/AtomicReference;)Larrow/DefaultAutoCloseScope; + public static final fun closeAll-impl (Ljava/util/concurrent/atomic/AtomicReference;Ljava/lang/Throwable;)V + public static fun constructor-impl (Ljava/util/concurrent/atomic/AtomicReference;)Ljava/util/concurrent/atomic/AtomicReference; + public static synthetic fun constructor-impl$default (Ljava/util/concurrent/atomic/AtomicReference;ILkotlin/jvm/internal/DefaultConstructorMarker;)Ljava/util/concurrent/atomic/AtomicReference; + public fun equals (Ljava/lang/Object;)Z + public static fun equals-impl (Ljava/util/concurrent/atomic/AtomicReference;Ljava/lang/Object;)Z + public static final fun equals-impl0 (Ljava/util/concurrent/atomic/AtomicReference;Ljava/util/concurrent/atomic/AtomicReference;)Z + public fun hashCode ()I + public static fun hashCode-impl (Ljava/util/concurrent/atomic/AtomicReference;)I public fun install (Ljava/lang/AutoCloseable;)Ljava/lang/AutoCloseable; + public static fun install-impl (Ljava/util/concurrent/atomic/AtomicReference;Ljava/lang/AutoCloseable;)Ljava/lang/AutoCloseable; + public fun onClose (Lkotlin/jvm/functions/Function1;)V + public static fun onClose-impl (Ljava/util/concurrent/atomic/AtomicReference;Lkotlin/jvm/functions/Function1;)V + public fun toString ()Ljava/lang/String; + public static fun toString-impl (Ljava/util/concurrent/atomic/AtomicReference;)Ljava/lang/String; + public final synthetic fun unbox-impl ()Ljava/util/concurrent/atomic/AtomicReference; } public final class arrow/ThrowIfFatalKt { diff --git a/arrow-libs/fx/arrow-fx-coroutines/api/arrow-fx-coroutines.api b/arrow-libs/fx/arrow-fx-coroutines/api/arrow-fx-coroutines.api index f02721af9ec..b0ef3d851a8 100644 --- a/arrow-libs/fx/arrow-fx-coroutines/api/arrow-fx-coroutines.api +++ b/arrow-libs/fx/arrow-fx-coroutines/api/arrow-fx-coroutines.api @@ -5,6 +5,7 @@ public final class arrow/fx/coroutines/AcquireStep { public final class arrow/fx/coroutines/BracketKt { public static final fun bracket (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static final fun bracketCase (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static final fun getThrowableOrNull (Larrow/fx/coroutines/ExitCase;)Ljava/lang/Throwable; public static final fun guarantee (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static final fun guaranteeCase (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static final fun onCancel (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; @@ -30,7 +31,7 @@ public final class arrow/fx/coroutines/CyclicBarrierCancellationException : java public fun ()V } -public abstract class arrow/fx/coroutines/ExitCase { +public abstract interface class arrow/fx/coroutines/ExitCase { public static final field Companion Larrow/fx/coroutines/ExitCase$Companion; } @@ -51,6 +52,8 @@ public final class arrow/fx/coroutines/ExitCase$Companion { public final class arrow/fx/coroutines/ExitCase$Completed : arrow/fx/coroutines/ExitCase { public static final field INSTANCE Larrow/fx/coroutines/ExitCase$Completed; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I public fun toString ()Ljava/lang/String; } @@ -238,27 +241,56 @@ public final class arrow/fx/coroutines/ResourceExtensionsKt { public final class arrow/fx/coroutines/ResourceKt { public static final fun allocated (Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static final fun asFlow (Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/flow/Flow; + public static final fun install (Larrow/fx/coroutines/ResourceScope;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static final fun resource (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function3;)Lkotlin/jvm/functions/Function2; public static final fun resource (Lkotlin/jvm/functions/Function2;)Lkotlin/jvm/functions/Function2; - public static final fun resourceScope (Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static final fun resourceScope (Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static final fun use (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; } public abstract interface class arrow/fx/coroutines/ResourceScope : arrow/AutoCloseScope { public abstract fun bind (Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; - public abstract fun install (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; - public abstract fun onRelease (Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public abstract fun onClose (Lkotlin/jvm/functions/Function1;)V + public abstract fun onRelease (Lkotlin/jvm/functions/Function2;)V public abstract fun release (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public abstract fun releaseCase (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; } public final class arrow/fx/coroutines/ResourceScope$DefaultImpls { + public static fun bind (Larrow/fx/coroutines/ResourceScope;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static fun install (Larrow/fx/coroutines/ResourceScope;Ljava/lang/AutoCloseable;)Ljava/lang/AutoCloseable; - public static fun onRelease (Larrow/fx/coroutines/ResourceScope;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static fun onClose (Larrow/fx/coroutines/ResourceScope;Lkotlin/jvm/functions/Function1;)V public static fun release (Larrow/fx/coroutines/ResourceScope;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static fun releaseCase (Larrow/fx/coroutines/ResourceScope;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; } +public final class arrow/fx/coroutines/ResourceScopeImpl : arrow/fx/coroutines/ResourceScope { + public fun bind (Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static fun bind-impl (Ljava/util/concurrent/atomic/AtomicReference;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static final synthetic fun box-impl (Ljava/util/concurrent/atomic/AtomicReference;)Larrow/fx/coroutines/ResourceScopeImpl; + public static final fun cancelAll-impl (Ljava/util/concurrent/atomic/AtomicReference;Larrow/fx/coroutines/ExitCase;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static fun constructor-impl (Ljava/util/concurrent/atomic/AtomicReference;)Ljava/util/concurrent/atomic/AtomicReference; + public static synthetic fun constructor-impl$default (Ljava/util/concurrent/atomic/AtomicReference;ILkotlin/jvm/internal/DefaultConstructorMarker;)Ljava/util/concurrent/atomic/AtomicReference; + public fun equals (Ljava/lang/Object;)Z + public static fun equals-impl (Ljava/util/concurrent/atomic/AtomicReference;Ljava/lang/Object;)Z + public static final fun equals-impl0 (Ljava/util/concurrent/atomic/AtomicReference;Ljava/util/concurrent/atomic/AtomicReference;)Z + public fun hashCode ()I + public static fun hashCode-impl (Ljava/util/concurrent/atomic/AtomicReference;)I + public fun install (Ljava/lang/AutoCloseable;)Ljava/lang/AutoCloseable; + public static fun install-impl (Ljava/util/concurrent/atomic/AtomicReference;Ljava/lang/AutoCloseable;)Ljava/lang/AutoCloseable; + public fun onClose (Lkotlin/jvm/functions/Function1;)V + public static fun onClose-impl (Ljava/util/concurrent/atomic/AtomicReference;Lkotlin/jvm/functions/Function1;)V + public fun onRelease (Lkotlin/jvm/functions/Function2;)V + public static fun onRelease-impl (Ljava/util/concurrent/atomic/AtomicReference;Lkotlin/jvm/functions/Function2;)V + public fun release (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static fun release-impl (Ljava/util/concurrent/atomic/AtomicReference;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun releaseCase (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static fun releaseCase-impl (Ljava/util/concurrent/atomic/AtomicReference;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun toString ()Ljava/lang/String; + public static fun toString-impl (Ljava/util/concurrent/atomic/AtomicReference;)Ljava/lang/String; + public final synthetic fun unbox-impl ()Ljava/util/concurrent/atomic/AtomicReference; +} + public abstract interface annotation class arrow/fx/coroutines/ScopeDSL : java/lang/annotation/Annotation { } From 04103e87fea6fe8c08bd0732c4d9fb57c586270c Mon Sep 17 00:00:00 2001 From: Youssef Shoaib Date: Sat, 18 May 2024 05:52:20 +0100 Subject: [PATCH 5/5] Fix minor bug with suppressedExceptions not getting preserved --- .../src/commonMain/kotlin/arrow/fx/coroutines/Resource.kt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/arrow-libs/fx/arrow-fx-coroutines/src/commonMain/kotlin/arrow/fx/coroutines/Resource.kt b/arrow-libs/fx/arrow-fx-coroutines/src/commonMain/kotlin/arrow/fx/coroutines/Resource.kt index 0da44288256..6b3587858df 100644 --- a/arrow-libs/fx/arrow-fx-coroutines/src/commonMain/kotlin/arrow/fx/coroutines/Resource.kt +++ b/arrow-libs/fx/arrow-fx-coroutines/src/commonMain/kotlin/arrow/fx/coroutines/Resource.kt @@ -475,9 +475,11 @@ internal value class ResourceScopeImpl( override fun onRelease(release: suspend (ExitCase) -> Unit) = finalizers.update(release::prependTo) - suspend fun cancelAll(exitCase: ExitCase): Unit = withContext(NonCancellable) { - finalizers.value.fold(exitCase.throwableOrNull) { acc, finalizer -> - acc.add(runCatching { finalizer(exitCase) }.exceptionOrNull()) + suspend fun cancelAll(exitCase: ExitCase) { + withContext(NonCancellable) { + finalizers.value.fold(exitCase.throwableOrNull) { acc, finalizer -> + acc.add(runCatching { finalizer(exitCase) }.exceptionOrNull()) + } }?.let { throw it } } }