From c0c17a3d57b333e9275581b6a18add6b59d26eb3 Mon Sep 17 00:00:00 2001 From: Adam Hearn <22334119+hearnadam@users.noreply.github.com> Date: Fri, 16 May 2025 09:49:39 -0700 Subject: [PATCH] Consider all `VirtualMachineError` fatal --- .../test/scala/zio/internal/IsFatalSpec.scala | 47 +++++++++++++++++++ .../src/main/scala/zio/internal/IsFatal.scala | 15 +++--- 2 files changed, 55 insertions(+), 7 deletions(-) create mode 100644 core-tests/shared/src/test/scala/zio/internal/IsFatalSpec.scala diff --git a/core-tests/shared/src/test/scala/zio/internal/IsFatalSpec.scala b/core-tests/shared/src/test/scala/zio/internal/IsFatalSpec.scala new file mode 100644 index 000000000000..f65ef9c3a7cb --- /dev/null +++ b/core-tests/shared/src/test/scala/zio/internal/IsFatalSpec.scala @@ -0,0 +1,47 @@ +package zio.internal + +import zio.test.Assertion._ +import zio.test._ +import zio.ZIOBaseSpec + +object IsFatalSpec extends ZIOBaseSpec { + def spec = + suite("IsFatal")( + suite("empty")( + test("apply(VirtualMachineError)") { + val isFatal = IsFatal.empty + assert(isFatal(new OutOfMemoryError()))(isTrue) && + assert(isFatal(new StackOverflowError()))(isTrue) + }, + test("apply(Non-VirtualMachineError)") { + val isFatal = IsFatal.empty + assert(isFatal(new RuntimeException()))(isFalse) && + assert(isFatal(new IllegalArgumentException()))(isFalse) + }, + test("|") { + val tag = IsFatal(classOf[RuntimeException]) + assert(IsFatal.empty | tag)(equalTo(tag)) && + assert(tag | IsFatal.empty)(equalTo(tag)) + } + ), + suite("Tag")( + test("matches assignable types") { + val isFatal = IsFatal(classOf[RuntimeException]) + assert(isFatal(new RuntimeException()))(isTrue) && + assert(isFatal(new IllegalArgumentException()))(isTrue) && + assert(isFatal(new Exception()))(isFalse) + } + ), + suite("Both")( + test("matches any of the two") { + val first = IsFatal(classOf[RuntimeException]) + val second = IsFatal(classOf[Exception]) + val combined = first | second + assert(combined(new RuntimeException()))(isTrue) && + assert(combined(new IllegalArgumentException()))(isTrue) && + assert(combined(new Exception()))(isTrue) && + assert(combined(new Throwable()))(isFalse) + } + ) + ) +} diff --git a/core/shared/src/main/scala/zio/internal/IsFatal.scala b/core/shared/src/main/scala/zio/internal/IsFatal.scala index 9771467daaa2..587fb100e519 100644 --- a/core/shared/src/main/scala/zio/internal/IsFatal.scala +++ b/core/shared/src/main/scala/zio/internal/IsFatal.scala @@ -20,20 +20,21 @@ sealed trait IsFatal extends (Throwable => Boolean) { self => import IsFatal._ def apply(t: Throwable): Boolean = - if (t.isInstanceOf[StackOverflowError]) true + if (t.isInstanceOf[VirtualMachineError]) true else self match { + case _: Empty.type => false case Both(left, right) => left(t) || right(t) - case Empty => false case Single(tag) => tag.isAssignableFrom(t.getClass) } def |(that: IsFatal): IsFatal = - (self, that) match { - case (self, Empty) => self - case (Empty, that) => that - case (self, that) => Both(self, that) - } + if (self eq Empty) that + else + that match { + case _: Empty.type => self + case _ => Both(self, that) + } } object IsFatal {