Skip to content

Commit

Permalink
Change return type of raise to Nothing (#2839)
Browse files Browse the repository at this point in the history
* 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 <[email protected]>
  • Loading branch information
roomscape and serras authored Nov 17, 2022
1 parent 5a03760 commit 47b06a6
Show file tree
Hide file tree
Showing 10 changed files with 41 additions and 35 deletions.
26 changes: 13 additions & 13 deletions arrow-libs/core/arrow-core/api/arrow-core.api
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public inline fun <E, A> ior(semigroup: Semigroup<E>, @BuilderInference action:
public value class NullableRaise(private val cont: Raise<Nothing?>) : Raise<Nothing?> {
@EffectDSL
public fun ensure(value: Boolean): Unit = ensure(value) { null }
override fun <B> raise(r: Nothing?): B = cont.raise(r)
override fun raise(r: Nothing?): Nothing = cont.raise(r)
public fun <B> Option<B>.bind(): B = bind { raise(null) }

public fun <B> B?.bind(): B {
Expand All @@ -62,13 +62,13 @@ public value class NullableRaise(private val cont: Raise<Nothing?>) : Raise<Noth

@JvmInline
public value class ResultRaise(private val cont: Raise<Throwable>) : Raise<Throwable> {
override fun <B> raise(r: Throwable): B = cont.raise(r)
override fun raise(r: Throwable): Nothing = cont.raise(r)
public fun <B> Result<B>.bind(): B = fold(::identity) { raise(it) }
}

@JvmInline
public value class OptionRaise(private val cont: Raise<None>) : Raise<None> {
override fun <B> raise(r: None): B = cont.raise(r)
override fun raise(r: None): Nothing = cont.raise(r)
public fun <B> Option<B>.bind(): B = bind { raise(None) }
public fun ensure(value: Boolean): Unit = ensure(value) { None }

Expand All @@ -83,8 +83,8 @@ public class IorRaise<E> @PublishedApi internal constructor(
@PublishedApi
internal val effect: StateRaise<Option<E>, E>,
) : Raise<E>, Semigroup<E> by semigroup {
override fun <B> raise(r: E): B = effect.raise(combine(r))

override fun raise(r: E): Nothing = effect.raise(combine(r))

public fun <B> Ior<E, B>.bind(): B =
when (this) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,7 @@ import kotlin.jvm.JvmMultifileClass
* val error = "Error"
* val exit = CompletableDeferred<ExitCase>()
* effect<String, Int> {
* parZip({ awaitExitCase<Int>(exit) }, { raise<Int>(error) }) { a, b -> a + b }
* parZip({ awaitExitCase<Int>(exit) }, { raise(error) }) { a: Int, b: Int -> a + b }
* }.fold({ it shouldBe error }, { fail("Int can never be the result") })
* exit.await().shouldBeTypeOf<ExitCase>()
* }
Expand Down Expand Up @@ -425,7 +425,7 @@ import kotlin.jvm.JvmMultifileClass
* val error = "Error"
* val exit = CompletableDeferred<ExitCase>()
* effect<String, Int> {
* raceN({ awaitExitCase<Int>(exit) }) { raise<Int>(error) }
* raceN({ awaitExitCase<Int>(exit) }) { raise(error) }
* .merge() // Flatten Either<Int, Int> 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
Expand Down Expand Up @@ -497,7 +497,7 @@ import kotlin.jvm.JvmMultifileClass
* resourceScope {
* effect<String, Int> {
* val reader = bufferedReader("build.gradle.kts")
* raise<Int>(error)
* raise(error)
* reader.lineSequence().count()
* }.fold({ it shouldBe error }, { fail("Int can never be the result") })
* }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ internal fun <R> 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<Any?> {
override fun <B> 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. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public annotation class EffectDSL
public interface Raise<in R> {

/** Raise a _logical failure_ of type [R] */
public fun <A> raise(r: R): A
public fun raise(r: R): Nothing

/**
* Invoke an [EagerEffect] inside `this` [Raise] context.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class EagerEffectSpec : StringSpec({
val promise = CompletableDeferred<Int>()
eagerEffect {
try {
raise<Int>(s)
raise(s)
} finally {
require(promise.complete(i))
}
Expand Down Expand Up @@ -141,31 +141,34 @@ class EagerEffectSpec : StringSpec({
}
}

@Suppress("UNREACHABLE_CODE")
"catch - error path and recover" {
checkAll(Arb.int(), Arb.string()) { int, fallback ->
eagerEffect<Int, String> {
raise<String>(int)
raise(int)
fail("It should never reach this point")
}.recover<Int, Nothing, String> { fallback }
.runCont() shouldBe fallback
}
}

@Suppress("UNREACHABLE_CODE")
"catch - error path and re-raise" {
checkAll(Arb.int(), Arb.string()) { int, fallback ->
eagerEffect<Int, Unit> {
raise<String>(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<RuntimeException> {
eagerEffect<Int, String> {
raise<String>(int)
raise(int)
fail("It should never reach this point")
}.recover<Int, Nothing, String> { throw RuntimeException(msg) }
.runCont()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ class EffectSpec :
val promise = CompletableDeferred<Int>()
effect {
try {
raise<Int>(s().suspend())
raise(s().suspend())
} finally {
require(promise.complete(i()))
}
Expand Down Expand Up @@ -132,7 +132,7 @@ class EffectSpec :
"short-circuit" {
checkAll(Arb.string().suspend()) { msg ->
effect {
raise<Int>(msg())
raise(msg())
}.runCont() shouldBe msg()
}
}
Expand Down Expand Up @@ -299,31 +299,34 @@ class EffectSpec :
}
}

@Suppress("UNREACHABLE_CODE")
"catch - error path and recover" {
checkAll(Arb.int().suspend(), Arb.string().suspend()) { int, fallback ->
effect<Int, String> {
raise<String>(int())
raise(int())
fail("It should never reach this point")
}.recover<Int, Nothing, String> { fallback() }
.runCont() shouldBe fallback()
}
}

@Suppress("UNREACHABLE_CODE")
"catch - error path and re-raise" {
checkAll(Arb.int().suspend(), Arb.string().suspend()) { int, fallback ->
effect<Int, Unit> {
raise<String>(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<RuntimeException> {
effect<Int, String> {
raise<String>(int())
raise(int())
fail("It should never reach this point")
}.recover<Int, Nothing, String> { throw RuntimeException(msg()) }
.runCont()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ suspend fun <A> awaitExitCase(exit: CompletableDeferred<ExitCase>): A =
val error = "Error"
val exit = CompletableDeferred<ExitCase>()
effect<String, Int> {
parZip({ awaitExitCase<Int>(exit) }, { raise<Int>(error) }) { a, b -> a + b }
parZip({ awaitExitCase<Int>(exit) }, { raise(error) }) { a: Int, b: Int -> a + b }
}.fold({ it shouldBe error }, { fail("Int can never be the result") })
exit.await().shouldBeTypeOf<ExitCase>()
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ suspend fun main() {
val error = "Error"
val exit = CompletableDeferred<ExitCase>()
effect<String, Int> {
raceN({ awaitExitCase<Int>(exit) }) { raise<Int>(error) }
raceN({ awaitExitCase<Int>(exit) }) { raise(error) }
.merge() // Flatten Either<Int, Int> 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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ suspend fun main() {
resourceScope {
effect<String, Int> {
val reader = bufferedReader("build.gradle.kts")
raise<Int>(error)
raise(error)
reader.lineSequence().count()
}.fold({ it shouldBe error }, { fail("Int can never be the result") })
}
Expand Down

0 comments on commit 47b06a6

Please sign in to comment.