From 47b06a609b5fa51bea2864e5dbc25bef0029f68d Mon Sep 17 00:00:00 2001 From: Sam Cooper <54266448+roomscape@users.noreply.github.com> Date: Thu, 17 Nov 2022 14:11:17 +0000 Subject: [PATCH] Change return type of raise to Nothing (#2839) * Change return type of raise to Nothing Implements #2805 * Update public api with ./gradlew apiDump * Suppress warnings for unreachable calls to fail in tests The test is verifying that no code will be executed after a call to raise, so it's actually testing the very behaviour that the compiler is warning us about. Co-authored-by: Alejandro Serrano --- arrow-libs/core/arrow-core/api/arrow-core.api | 26 +++++++++---------- .../arrow/core/continuations/Builders.kt | 10 +++---- .../kotlin/arrow/core/continuations/Effect.kt | 6 ++--- .../kotlin/arrow/core/continuations/Fold.kt | 2 +- .../kotlin/arrow/core/continuations/Raise.kt | 2 +- .../core/continuations/EagerEffectSpec.kt | 11 +++++--- .../arrow/core/continuations/EffectSpec.kt | 13 ++++++---- .../kotlin/examples/example-effect-05.kt | 2 +- .../kotlin/examples/example-effect-07.kt | 2 +- .../kotlin/examples/example-effect-09.kt | 2 +- 10 files changed, 41 insertions(+), 35 deletions(-) diff --git a/arrow-libs/core/arrow-core/api/arrow-core.api b/arrow-libs/core/arrow-core/api/arrow-core.api index 74b2b6921da..222f4ec7e2b 100644 --- a/arrow-libs/core/arrow-core/api/arrow-core.api +++ b/arrow-libs/core/arrow-core/api/arrow-core.api @@ -2598,7 +2598,7 @@ public final class arrow/core/continuations/DefaultRaise : arrow/core/continuati public fun catch (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public fun invoke (Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; public fun invoke (Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; - public fun raise (Ljava/lang/Object;)Ljava/lang/Object; + public fun raise (Ljava/lang/Object;)Ljava/lang/Void; public fun recover (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object; public fun recover (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public fun recover (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; @@ -2619,7 +2619,7 @@ public final class arrow/core/continuations/DefaultStateRaise : arrow/atomic/Ato public fun getValue ()Ljava/lang/Object; public fun invoke (Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; public fun invoke (Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; - public fun raise (Ljava/lang/Object;)Ljava/lang/Object; + public fun raise (Ljava/lang/Object;)Ljava/lang/Void; public fun recover (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object; public fun recover (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public fun recover (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; @@ -2688,7 +2688,7 @@ public final class arrow/core/continuations/IorRaise : arrow/core/continuations/ public fun invoke (Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public fun maybeCombine (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; public fun plus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun raise (Ljava/lang/Object;)Ljava/lang/Object; + public fun raise (Ljava/lang/Object;)Ljava/lang/Void; public fun recover (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object; public fun recover (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public fun recover (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; @@ -2726,9 +2726,9 @@ public final class arrow/core/continuations/NullableRaise : arrow/core/continuat public fun invoke (Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static fun invoke-impl (Larrow/core/continuations/Raise;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; public static fun invoke-impl (Larrow/core/continuations/Raise;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; - public synthetic fun raise (Ljava/lang/Object;)Ljava/lang/Object; - public fun raise (Ljava/lang/Void;)Ljava/lang/Object; - public static fun raise-impl (Larrow/core/continuations/Raise;Ljava/lang/Void;)Ljava/lang/Object; + public synthetic fun raise (Ljava/lang/Object;)Ljava/lang/Void; + public fun raise (Ljava/lang/Void;)Ljava/lang/Void; + public static fun raise-impl (Larrow/core/continuations/Raise;Ljava/lang/Void;)Ljava/lang/Void; public fun recover (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object; public fun recover (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public fun recover (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; @@ -2771,9 +2771,9 @@ public final class arrow/core/continuations/OptionRaise : arrow/core/continuatio public fun invoke (Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static fun invoke-impl (Larrow/core/continuations/Raise;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; public static fun invoke-impl (Larrow/core/continuations/Raise;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; - public fun raise (Larrow/core/None;)Ljava/lang/Object; - public synthetic fun raise (Ljava/lang/Object;)Ljava/lang/Object; - public static fun raise-impl (Larrow/core/continuations/Raise;Larrow/core/None;)Ljava/lang/Object; + public fun raise (Larrow/core/None;)Ljava/lang/Void; + public synthetic fun raise (Ljava/lang/Object;)Ljava/lang/Void; + public static fun raise-impl (Larrow/core/continuations/Raise;Larrow/core/None;)Ljava/lang/Void; public fun recover (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object; public fun recover (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public fun recover (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; @@ -2796,7 +2796,7 @@ public abstract interface class arrow/core/continuations/Raise { public abstract fun catch (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public abstract fun invoke (Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; public abstract fun invoke (Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; - public abstract fun raise (Ljava/lang/Object;)Ljava/lang/Object; + public abstract fun raise (Ljava/lang/Object;)Ljava/lang/Void; public abstract fun recover (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object; public abstract fun recover (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public abstract fun recover (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; @@ -2855,9 +2855,9 @@ public final class arrow/core/continuations/ResultRaise : arrow/core/continuatio public fun invoke (Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static fun invoke-impl (Larrow/core/continuations/Raise;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; public static fun invoke-impl (Larrow/core/continuations/Raise;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; - public synthetic fun raise (Ljava/lang/Object;)Ljava/lang/Object; - public fun raise (Ljava/lang/Throwable;)Ljava/lang/Object; - public static fun raise-impl (Larrow/core/continuations/Raise;Ljava/lang/Throwable;)Ljava/lang/Object; + public synthetic fun raise (Ljava/lang/Object;)Ljava/lang/Void; + public fun raise (Ljava/lang/Throwable;)Ljava/lang/Void; + public static fun raise-impl (Larrow/core/continuations/Raise;Ljava/lang/Throwable;)Ljava/lang/Void; public fun recover (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object; public fun recover (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public fun recover (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; diff --git a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/continuations/Builders.kt b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/continuations/Builders.kt index a242ac30fa0..99d730a44bb 100644 --- a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/continuations/Builders.kt +++ b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/continuations/Builders.kt @@ -46,7 +46,7 @@ public inline fun ior(semigroup: Semigroup, @BuilderInference action: public value class NullableRaise(private val cont: Raise) : Raise { @EffectDSL public fun ensure(value: Boolean): Unit = ensure(value) { null } - override fun raise(r: Nothing?): B = cont.raise(r) + override fun raise(r: Nothing?): Nothing = cont.raise(r) public fun Option.bind(): B = bind { raise(null) } public fun B?.bind(): B { @@ -62,13 +62,13 @@ public value class NullableRaise(private val cont: Raise) : Raise) : Raise { - override fun raise(r: Throwable): B = cont.raise(r) + override fun raise(r: Throwable): Nothing = cont.raise(r) public fun Result.bind(): B = fold(::identity) { raise(it) } } @JvmInline public value class OptionRaise(private val cont: Raise) : Raise { - override fun raise(r: None): B = cont.raise(r) + override fun raise(r: None): Nothing = cont.raise(r) public fun Option.bind(): B = bind { raise(None) } public fun ensure(value: Boolean): Unit = ensure(value) { None } @@ -83,8 +83,8 @@ public class IorRaise @PublishedApi internal constructor( @PublishedApi internal val effect: StateRaise, E>, ) : Raise, Semigroup by semigroup { - - override fun raise(r: E): B = effect.raise(combine(r)) + + override fun raise(r: E): Nothing = effect.raise(combine(r)) public fun Ior.bind(): B = when (this) { diff --git a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/continuations/Effect.kt b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/continuations/Effect.kt index d9de40f4727..3130b5cd28c 100644 --- a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/continuations/Effect.kt +++ b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/continuations/Effect.kt @@ -355,7 +355,7 @@ import kotlin.jvm.JvmMultifileClass * val error = "Error" * val exit = CompletableDeferred() * effect { - * parZip({ awaitExitCase(exit) }, { raise(error) }) { a, b -> a + b } + * parZip({ awaitExitCase(exit) }, { raise(error) }) { a: Int, b: Int -> a + b } * }.fold({ it shouldBe error }, { fail("Int can never be the result") }) * exit.await().shouldBeTypeOf() * } @@ -425,7 +425,7 @@ import kotlin.jvm.JvmMultifileClass * val error = "Error" * val exit = CompletableDeferred() * effect { - * raceN({ awaitExitCase(exit) }) { raise(error) } + * raceN({ awaitExitCase(exit) }) { raise(error) } * .merge() // Flatten Either result from race into Int * }.fold({ msg -> msg shouldBe error }, { fail("Int can never be the result") }) * // It's possible not all parallel task got launched, and in those cases awaitCancellation never ran @@ -497,7 +497,7 @@ import kotlin.jvm.JvmMultifileClass * resourceScope { * effect { * val reader = bufferedReader("build.gradle.kts") - * raise(error) + * raise(error) * reader.lineSequence().count() * }.fold({ it shouldBe error }, { fail("Int can never be the result") }) * } diff --git a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/continuations/Fold.kt b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/continuations/Fold.kt index bbae0759511..40580116d5e 100644 --- a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/continuations/Fold.kt +++ b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/continuations/Fold.kt @@ -72,7 +72,7 @@ internal fun CancellationException.raisedOrRethrow(raise: DefaultRaise): R = /** Serves as both purposes of a scope-reference token, and a default implementation for Raise. */ @PublishedApi internal class DefaultRaise : Raise { - override fun raise(r: Any?): B = throw RaiseCancellationException(r, this) + override fun raise(r: Any?): Nothing = throw RaiseCancellationException(r, this) } /** CancellationException is required to cancel coroutines when raising from within them. */ diff --git a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/continuations/Raise.kt b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/continuations/Raise.kt index d4f1736edfd..e72e8e5df3b 100644 --- a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/continuations/Raise.kt +++ b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/continuations/Raise.kt @@ -61,7 +61,7 @@ public annotation class EffectDSL public interface Raise { /** Raise a _logical failure_ of type [R] */ - public fun raise(r: R): A + public fun raise(r: R): Nothing /** * Invoke an [EagerEffect] inside `this` [Raise] context. diff --git a/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/continuations/EagerEffectSpec.kt b/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/continuations/EagerEffectSpec.kt index 671306bb6ac..8286e614132 100644 --- a/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/continuations/EagerEffectSpec.kt +++ b/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/continuations/EagerEffectSpec.kt @@ -36,7 +36,7 @@ class EagerEffectSpec : StringSpec({ val promise = CompletableDeferred() eagerEffect { try { - raise(s) + raise(s) } finally { require(promise.complete(i)) } @@ -141,31 +141,34 @@ class EagerEffectSpec : StringSpec({ } } + @Suppress("UNREACHABLE_CODE") "catch - error path and recover" { checkAll(Arb.int(), Arb.string()) { int, fallback -> eagerEffect { - raise(int) + raise(int) fail("It should never reach this point") }.recover { fallback } .runCont() shouldBe fallback } } + @Suppress("UNREACHABLE_CODE") "catch - error path and re-raise" { checkAll(Arb.int(), Arb.string()) { int, fallback -> eagerEffect { - raise(int) + raise(int) fail("It should never reach this point") }.recover { raise(fallback) } .runCont() shouldBe fallback } } + @Suppress("UNREACHABLE_CODE") "catch - error path and throw" { checkAll(Arb.int(), Arb.string()) { int, msg -> shouldThrow { eagerEffect { - raise(int) + raise(int) fail("It should never reach this point") }.recover { throw RuntimeException(msg) } .runCont() diff --git a/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/continuations/EffectSpec.kt b/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/continuations/EffectSpec.kt index 569651f962e..eb4b91b8c5c 100644 --- a/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/continuations/EffectSpec.kt +++ b/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/continuations/EffectSpec.kt @@ -47,7 +47,7 @@ class EffectSpec : val promise = CompletableDeferred() effect { try { - raise(s().suspend()) + raise(s().suspend()) } finally { require(promise.complete(i())) } @@ -132,7 +132,7 @@ class EffectSpec : "short-circuit" { checkAll(Arb.string().suspend()) { msg -> effect { - raise(msg()) + raise(msg()) }.runCont() shouldBe msg() } } @@ -299,31 +299,34 @@ class EffectSpec : } } + @Suppress("UNREACHABLE_CODE") "catch - error path and recover" { checkAll(Arb.int().suspend(), Arb.string().suspend()) { int, fallback -> effect { - raise(int()) + raise(int()) fail("It should never reach this point") }.recover { fallback() } .runCont() shouldBe fallback() } } + @Suppress("UNREACHABLE_CODE") "catch - error path and re-raise" { checkAll(Arb.int().suspend(), Arb.string().suspend()) { int, fallback -> effect { - raise(int()) + raise(int()) fail("It should never reach this point") }.recover { raise(fallback()) } .runCont() shouldBe fallback() } } + @Suppress("UNREACHABLE_CODE") "catch - error path and throw" { checkAll(Arb.int().suspend(), Arb.string().suspend()) { int, msg -> shouldThrow { effect { - raise(int()) + raise(int()) fail("It should never reach this point") }.recover { throw RuntimeException(msg()) } .runCont() diff --git a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-effect-05.kt b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-effect-05.kt index c17af634fe8..09cd2ef8212 100644 --- a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-effect-05.kt +++ b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-effect-05.kt @@ -19,7 +19,7 @@ suspend fun awaitExitCase(exit: CompletableDeferred): A = val error = "Error" val exit = CompletableDeferred() effect { - parZip({ awaitExitCase(exit) }, { raise(error) }) { a, b -> a + b } + parZip({ awaitExitCase(exit) }, { raise(error) }) { a: Int, b: Int -> a + b } }.fold({ it shouldBe error }, { fail("Int can never be the result") }) exit.await().shouldBeTypeOf() } diff --git a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-effect-07.kt b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-effect-07.kt index 33f4a45af98..8d9295d3545 100644 --- a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-effect-07.kt +++ b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-effect-07.kt @@ -23,7 +23,7 @@ suspend fun main() { val error = "Error" val exit = CompletableDeferred() effect { - raceN({ awaitExitCase(exit) }) { raise(error) } + raceN({ awaitExitCase(exit) }) { raise(error) } .merge() // Flatten Either result from race into Int }.fold({ msg -> msg shouldBe error }, { fail("Int can never be the result") }) // It's possible not all parallel task got launched, and in those cases awaitCancellation never ran diff --git a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-effect-09.kt b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-effect-09.kt index e3426a5911b..97083577588 100644 --- a/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-effect-09.kt +++ b/arrow-libs/core/arrow-core/src/jvmTest/kotlin/examples/example-effect-09.kt @@ -26,7 +26,7 @@ suspend fun main() { resourceScope { effect { val reader = bufferedReader("build.gradle.kts") - raise(error) + raise(error) reader.lineSequence().count() }.fold({ it shouldBe error }, { fail("Int can never be the result") }) }