diff --git a/core/shared/src/main/scala/cats/effect/IOFiber.scala b/core/shared/src/main/scala/cats/effect/IOFiber.scala index 727193ac1b..42e0648125 100644 --- a/core/shared/src/main/scala/cats/effect/IOFiber.scala +++ b/core/shared/src/main/scala/cats/effect/IOFiber.scala @@ -241,10 +241,11 @@ private final class IOFiber[A]( case 1 => val cur = cur0.asInstanceOf[Error] - if (!NonFatal(cur.t)) - onFatalFailure(cur.t) + val ex = cur.t + if (!NonFatal(ex)) + onFatalFailure(ex) - runLoop(failed(cur.t, 0), nextCancelation, nextAutoCede) + runLoop(failed(ex, 0), nextCancelation, nextAutoCede) case 2 => val cur = cur0.asInstanceOf[Delay[Any]] @@ -437,6 +438,8 @@ private final class IOFiber[A]( case 1 => val error = ioa.asInstanceOf[Error] val t = error.t + if (!NonFatal(t)) + onFatalFailure(t) // We need to augment the exception here because it doesn't get // forwarded to the `failed` path. Tracing.augmentThrowable(runtime.enhancedExceptions, t, tracingEvents) diff --git a/tests/jvm/src/test/scala/cats/effect/IOAppSpec.scala b/tests/jvm/src/test/scala/cats/effect/IOAppSpec.scala index 75688054fd..7838f2cc87 100644 --- a/tests/jvm/src/test/scala/cats/effect/IOAppSpec.scala +++ b/tests/jvm/src/test/scala/cats/effect/IOAppSpec.scala @@ -187,6 +187,20 @@ class IOAppSpec extends Specification { h.stderr() must contain("Boom!") } + "exit on raising a fatal error with attempt" in { + val h = platform(RaiseFatalErrorAttempt, List.empty) + h.awaitStatus() mustEqual 1 + h.stderr() must contain ("Boom!") + h.stdout() must not(contain("sadness")) + } + + "exit on raising a fatal error with handleError" in { + val h = platform(RaiseFatalErrorHandle, List.empty) + h.awaitStatus() mustEqual 1 + h.stderr() must contain ("Boom!") + h.stdout() must not(contain("sadness")) + } + "warn on global runtime collision" in { val h = platform(GlobalRacingInit, List.empty) h.awaitStatus() mustEqual 0 diff --git a/tests/shared/src/main/scala/catseffect/examples.scala b/tests/shared/src/main/scala/catseffect/examples.scala index d1262bec53..b9f5688c3e 100644 --- a/tests/shared/src/main/scala/catseffect/examples.scala +++ b/tests/shared/src/main/scala/catseffect/examples.scala @@ -58,6 +58,24 @@ package examples { } } + object RaiseFatalErrorAttempt extends IOApp { + def run(args: List[String]): IO[ExitCode] = { + IO.raiseError[Unit](new OutOfMemoryError("Boom!")) + .attempt + .flatMap(_ => IO.println("sadness")) + .as(ExitCode.Success) + } + } + + object RaiseFatalErrorHandle extends IOApp { + def run(args: List[String]): IO[ExitCode] = { + IO.raiseError[Unit](new OutOfMemoryError("Boom!")) + .handleError(_ => ()) + .flatMap(_ => IO.println("sadness")) + .as(ExitCode.Success) + } + } + object Canceled extends IOApp { def run(args: List[String]): IO[ExitCode] = IO.canceled.as(ExitCode.Success) diff --git a/tests/shared/src/test/scala/cats/effect/IOSpec.scala b/tests/shared/src/test/scala/cats/effect/IOSpec.scala index 538dbce557..d8152ccc81 100644 --- a/tests/shared/src/test/scala/cats/effect/IOSpec.scala +++ b/tests/shared/src/test/scala/cats/effect/IOSpec.scala @@ -345,20 +345,6 @@ class IOSpec extends BaseSpec with Discipline with IOPlatformSpecification { } yield reported test must completeAs(true) } - - "immediately surface fatal errors" in ticked { implicit ticker => - val error = new VirtualMachineError {} - val io = IO.raiseError[Unit](error).voidError - - val fatalThrown = - try { - unsafeRun[Unit](io) - false - } catch { - case t: Throwable => t eq error - } - IO(fatalThrown) must completeAs(true) - } } "suspension of side effects" should {