From c5a2154c90f639194613a987c340f1060d04854c Mon Sep 17 00:00:00 2001 From: "John A. De Goes" Date: Mon, 1 Nov 2021 15:29:28 -0600 Subject: [PATCH 1/2] Remove captureTrace from user-code by filling trace in runtime system --- core/shared/src/main/scala/zio/Cause.scala | 132 +++++++++++------- core/shared/src/main/scala/zio/IO.scala | 13 -- core/shared/src/main/scala/zio/RIO.scala | 13 -- core/shared/src/main/scala/zio/Runtime.scala | 2 +- core/shared/src/main/scala/zio/Task.scala | 15 -- core/shared/src/main/scala/zio/UIO.scala | 13 -- core/shared/src/main/scala/zio/URIO.scala | 13 -- core/shared/src/main/scala/zio/ZIO.scala | 32 +---- .../scala/zio/internal/FiberContext.scala | 5 +- 9 files changed, 93 insertions(+), 145 deletions(-) diff --git a/core/shared/src/main/scala/zio/Cause.scala b/core/shared/src/main/scala/zio/Cause.scala index 4275fd1b7cee..2b77eb8218b0 100644 --- a/core/shared/src/main/scala/zio/Cause.scala +++ b/core/shared/src/main/scala/zio/Cause.scala @@ -117,6 +117,48 @@ sealed abstract class Cause[+E] extends Product with Serializable { self => } .reverse + /** + * Finds something and extracts some details from it. + */ + final def find[Z](f: PartialFunction[Cause[E], Z]): Option[Z] = { + @tailrec + def loop(cause: Cause[E], stack: List[Cause[E]]): Option[Z] = + f.lift(cause) match { + case Some(z) => Some(z) + case None => + cause match { + case Then(left, right) => loop(left, right :: stack) + case Both(left, right) => loop(left, right :: stack) + case Stackless(cause, _) => loop(cause, stack) + case _ => + stack match { + case hd :: tl => loop(hd, tl) + case Nil => None + } + } + } + loop(self, Nil) + } + + /** + * Folds over the cause to statefully compute a value. + */ + final def foldLeft[Z](z: Z)(f: PartialFunction[(Z, Cause[E]), Z]): Z = { + @tailrec + def loop(z: Z, cause: Cause[E], stack: List[Cause[E]]): Z = + (f.applyOrElse[(Z, Cause[E]), Z](z -> cause, _ => z), cause) match { + case (z, Then(left, right)) => loop(z, left, right :: stack) + case (z, Both(left, right)) => loop(z, left, right :: stack) + case (z, Stackless(cause, _)) => loop(z, cause, stack) + case (z, _) => + stack match { + case hd :: tl => loop(z, hd, tl) + case Nil => z + } + } + loop(z, self, Nil) + } + /** * Determines if the `Cause` contains an interruption. */ @@ -177,6 +219,16 @@ sealed abstract class Cause[+E] extends Product with Serializable { self => case Fail(_, _) => false }.getOrElse(true) + /** + * Determines if the `Cause` is traced. + */ + final def isTraced: Boolean = + find { + case Die(_, trace) if trace != ZTrace.none => () + case Fail(_, trace) if trace != ZTrace.none => () + case Interrupt(_, trace) if trace != ZTrace.none => () + }.isDefined + final def fold[Z]( empty: => Z, failCase: (E, ZTrace) => Z, @@ -281,22 +333,6 @@ sealed abstract class Cause[+E] extends Product with Serializable { self => case Stackless(cause, stackless) => Stackless(cause.map(f), stackless) } - /** - * Returns a `Cause` that has been stripped of all tracing information. - */ - final def untraced: Cause[E] = - self match { - case Stackless(cause, data) => Stackless(cause.untraced, data) - - case Empty => Empty - case c @ Fail(_, _) => c - case c @ Die(_, _) => c - case c @ Interrupt(_, _) => c - - case Then(left, right) => Then(left.untraced, right.untraced) - case Both(left, right) => Both(left.untraced, right.untraced) - } - /** * Returns a `String` with the cause pretty-printed. */ @@ -462,41 +498,37 @@ sealed abstract class Cause[+E] extends Product with Serializable { self => } .reverse - final def find[Z](f: PartialFunction[Cause[E], Z]): Option[Z] = { - @tailrec - def loop(cause: Cause[E], stack: List[Cause[E]]): Option[Z] = - f.lift(cause) match { - case Some(z) => Some(z) - case None => - cause match { - case Then(left, right) => loop(left, right :: stack) - case Both(left, right) => loop(left, right :: stack) - case Stackless(cause, _) => loop(cause, stack) - case _ => - stack match { - case hd :: tl => loop(hd, tl) - case Nil => None - } - } - } - loop(self, Nil) - } + /** + * Replaces traces with the specified trace. + */ + final def traced(trace: ZTrace): Cause[E] = + self match { + case s @ Stackless(_, _) => s - final def foldLeft[Z](z: Z)(f: PartialFunction[(Z, Cause[E]), Z]): Z = { - @tailrec - def loop(z: Z, cause: Cause[E], stack: List[Cause[E]]): Z = - (f.applyOrElse[(Z, Cause[E]), Z](z -> cause, _ => z), cause) match { - case (z, Then(left, right)) => loop(z, left, right :: stack) - case (z, Both(left, right)) => loop(z, left, right :: stack) - case (z, Stackless(cause, _)) => loop(z, cause, stack) - case (z, _) => - stack match { - case hd :: tl => loop(z, hd, tl) - case Nil => z - } - } - loop(z, self, Nil) - } + case Empty => Empty + case Fail(v, _) => Fail(v, trace) + case Die(v, _) => Die(v, trace) + case Interrupt(v, _) => Interrupt(v, trace) + + case Then(left, right) => Then(left.traced(trace), right.traced(trace)) + case Both(left, right) => Both(left.traced(trace), right.traced(trace)) + } + + /** + * Returns a `Cause` that has been stripped of all tracing information. + */ + final def untraced: Cause[E] = + self match { + case Stackless(cause, data) => Stackless(cause.untraced, data) + + case Empty => Empty + case c @ Fail(_, _) => c + case c @ Die(_, _) => c + case c @ Interrupt(_, _) => c + + case Then(left, right) => Then(left.untraced, right.untraced) + case Both(left, right) => Both(left.untraced, right.untraced) + } private def attachTrace(e: Throwable): Throwable = { val trace = Cause.FiberTrace(Cause.stackless(this).prettyPrint) diff --git a/core/shared/src/main/scala/zio/IO.scala b/core/shared/src/main/scala/zio/IO.scala index 5fb69b45e21e..8ae7f8d20911 100644 --- a/core/shared/src/main/scala/zio/IO.scala +++ b/core/shared/src/main/scala/zio/IO.scala @@ -575,12 +575,6 @@ object IO { def failCause[E](cause: => Cause[E])(implicit trace: ZTraceElement): IO[E, Nothing] = ZIO.failCause(cause) - /** - * @see See [[zio.ZIO.failCauseWith]] - */ - def failCauseWith[E](function: (() => ZTrace) => Cause[E])(implicit trace: ZTraceElement): IO[E, Nothing] = - ZIO.failCauseWith(function) - /** * @see [[zio.ZIO.fiberId]] */ @@ -929,13 +923,6 @@ object IO { def halt[E](cause: => Cause[E])(implicit trace: ZTraceElement): IO[E, Nothing] = ZIO.halt(cause) - /** - * @see See [[zio.ZIO.haltWith]] - */ - @deprecated("use failCauseWith", "2.0.0") - def haltWith[E](function: (() => ZTrace) => Cause[E])(implicit trace: ZTraceElement): IO[E, Nothing] = - ZIO.haltWith(function) - /** * @see [[zio.ZIO.ifM]] */ diff --git a/core/shared/src/main/scala/zio/RIO.scala b/core/shared/src/main/scala/zio/RIO.scala index 318c0e8cbca0..96b4d7fea808 100644 --- a/core/shared/src/main/scala/zio/RIO.scala +++ b/core/shared/src/main/scala/zio/RIO.scala @@ -585,12 +585,6 @@ object RIO { def failCause(cause: => Cause[Throwable])(implicit trace: ZTraceElement): Task[Nothing] = ZIO.failCause(cause) - /** - * @see See [[zio.ZIO.failCauseWith]] - */ - def failCauseWith[R](function: (() => ZTrace) => Cause[Throwable])(implicit trace: ZTraceElement): RIO[R, Nothing] = - ZIO.failCauseWith(function) - /** * @see [[zio.ZIO.fiberId]] */ @@ -961,13 +955,6 @@ object RIO { def halt(cause: => Cause[Throwable])(implicit trace: ZTraceElement): Task[Nothing] = ZIO.halt(cause) - /** - * @see See [[zio.ZIO.haltWith]] - */ - @deprecated("use failCauseWith", "2.0.0") - def haltWith[R](function: (() => ZTrace) => Cause[Throwable])(implicit trace: ZTraceElement): RIO[R, Nothing] = - ZIO.haltWith(function) - /** * @see [[zio.ZIO.ifM]] */ diff --git a/core/shared/src/main/scala/zio/Runtime.scala b/core/shared/src/main/scala/zio/Runtime.scala index 1d3cab331aba..18d04bc70407 100644 --- a/core/shared/src/main/scala/zio/Runtime.scala +++ b/core/shared/src/main/scala/zio/Runtime.scala @@ -169,7 +169,7 @@ trait Runtime[+R] { case ZIO.Tags.Fail => val zio = curZio.asInstanceOf[ZIO.Fail[E]] - done = Exit.failCause(zio.fill(() => null)) + done = Exit.failCause(zio.cause()) case ZIO.Tags.Succeed => val zio = curZio.asInstanceOf[ZIO.Succeed[A]] diff --git a/core/shared/src/main/scala/zio/Task.scala b/core/shared/src/main/scala/zio/Task.scala index 45c2b883b3a7..57ef9c7b4ca1 100644 --- a/core/shared/src/main/scala/zio/Task.scala +++ b/core/shared/src/main/scala/zio/Task.scala @@ -565,14 +565,6 @@ object Task extends TaskPlatformSpecific { def failCause(cause: => Cause[Throwable])(implicit trace: ZTraceElement): Task[Nothing] = ZIO.failCause(cause) - /** - * @see See [[zio.ZIO.failCauseWith]] - */ - def failCauseWith[E <: Throwable](function: (() => ZTrace) => Cause[E])(implicit - trace: ZTraceElement - ): Task[Nothing] = - ZIO.failCauseWith(function) - /** * @see [[zio.ZIO.fiberId]] */ @@ -908,13 +900,6 @@ object Task extends TaskPlatformSpecific { def halt(cause: => Cause[Throwable])(implicit trace: ZTraceElement): Task[Nothing] = ZIO.halt(cause) - /** - * @see See [[zio.ZIO.haltWith]] - */ - @deprecated("use failCauseWith", "2.0.0") - def haltWith[E <: Throwable](function: (() => ZTrace) => Cause[E])(implicit trace: ZTraceElement): Task[Nothing] = - ZIO.haltWith(function) - /** * @see [[zio.ZIO.ifM]] */ diff --git a/core/shared/src/main/scala/zio/UIO.scala b/core/shared/src/main/scala/zio/UIO.scala index 6cb49a6617c6..288931efbd56 100644 --- a/core/shared/src/main/scala/zio/UIO.scala +++ b/core/shared/src/main/scala/zio/UIO.scala @@ -484,12 +484,6 @@ object UIO { def failCause(cause: => Cause[Nothing])(implicit trace: ZTraceElement): UIO[Nothing] = ZIO.failCause(cause) - /** - * @see [[zio.ZIO.failCauseWith]] - */ - def failCauseWith(function: (() => ZTrace) => Cause[Nothing])(implicit trace: ZTraceElement): UIO[Nothing] = - ZIO.failCauseWith(function) - /** * @see [[zio.ZIO.fiberId]] */ @@ -790,13 +784,6 @@ object UIO { def halt(cause: => Cause[Nothing])(implicit trace: ZTraceElement): UIO[Nothing] = ZIO.halt(cause) - /** - * @see [[zio.ZIO.haltWith]] - */ - @deprecated("use failCauseWith", "2.0.0") - def haltWith(function: (() => ZTrace) => Cause[Nothing])(implicit trace: ZTraceElement): UIO[Nothing] = - ZIO.haltWith(function) - /** * @see [[zio.ZIO.ifM]] */ diff --git a/core/shared/src/main/scala/zio/URIO.scala b/core/shared/src/main/scala/zio/URIO.scala index 779a5496cbeb..fc90f12e841e 100644 --- a/core/shared/src/main/scala/zio/URIO.scala +++ b/core/shared/src/main/scala/zio/URIO.scala @@ -504,12 +504,6 @@ object URIO { def failCause(cause: => Cause[Nothing])(implicit trace: ZTraceElement): UIO[Nothing] = ZIO.failCause(cause) - /** - * @see [[zio.ZIO.failCauseWith]] - */ - def failCauseWith[R](function: (() => ZTrace) => Cause[Nothing])(implicit trace: ZTraceElement): URIO[R, Nothing] = - ZIO.failCauseWith(function) - /** * @see [[zio.ZIO.fiberId]] */ @@ -861,13 +855,6 @@ object URIO { def halt(cause: => Cause[Nothing])(implicit trace: ZTraceElement): UIO[Nothing] = ZIO.halt(cause) - /** - * @see [[zio.ZIO.haltWith]] - */ - @deprecated("use failCauseWith", "2.0.0") - def haltWith[R](function: (() => ZTrace) => Cause[Nothing])(implicit trace: ZTraceElement): URIO[R, Nothing] = - ZIO.haltWith(function) - /** * @see [[zio.ZIO.ifM]] */ diff --git a/core/shared/src/main/scala/zio/ZIO.scala b/core/shared/src/main/scala/zio/ZIO.scala index dac473b4af75..b1fc96da3090 100644 --- a/core/shared/src/main/scala/zio/ZIO.scala +++ b/core/shared/src/main/scala/zio/ZIO.scala @@ -3423,7 +3423,7 @@ object ZIO extends ZIOCompanionPlatformSpecific { * detected in the code. */ def die(t: => Throwable)(implicit trace: ZTraceElement): UIO[Nothing] = - failCauseWith(trace => Cause.Die(t, trace())) + failCause(Cause.Die(t, ZTrace.none)) /** * Returns an effect that dies with a [[java.lang.RuntimeException]] having the @@ -3655,22 +3655,13 @@ object ZIO extends ZIOCompanionPlatformSpecific { * The moral equivalent of `throw` for pure code. */ def fail[E](error: => E)(implicit trace: ZTraceElement): IO[E, Nothing] = - failCauseWith(trace => Cause.Fail(error, trace())) + failCause(Cause.Fail(error, ZTrace.none)) /** * Returns an effect that models failure with the specified `Cause`. */ def failCause[E](cause: => Cause[E])(implicit trace: ZTraceElement): IO[E, Nothing] = - new ZIO.Fail(_ => cause, trace) - - /** - * Returns an effect that models failure with the specified `Cause`. - * - * This version takes in a lazily-evaluated trace that can be attached to the `Cause` - * via `Cause.Traced`. - */ - def failCauseWith[E](function: (() => ZTrace) => Cause[E])(implicit trace: ZTraceElement): IO[E, Nothing] = - new ZIO.Fail(function, trace) + new ZIO.Fail(() => cause, trace) /** * Returns the `FiberId` of the fiber executing the effect that calls this method. @@ -4333,16 +4324,6 @@ object ZIO extends ZIOCompanionPlatformSpecific { def halt[E](cause: => Cause[E])(implicit trace: ZTraceElement): IO[E, Nothing] = failCause(cause) - /** - * Returns an effect that models failure with the specified `Cause`. - * - * This version takes in a lazily-evaluated trace that can be attached to the `Cause` - * via `Cause.Traced`. - */ - @deprecated("use failCauseWith", "2.0.0") - def haltWith[E](function: (() => ZTrace) => Cause[E])(implicit trace: ZTraceElement): IO[E, Nothing] = - failCauseWith(function) - /** * Runs `onTrue` if the result of `b` is `true` and `onFalse` otherwise. */ @@ -4376,7 +4357,7 @@ object ZIO extends ZIOCompanionPlatformSpecific { * Returns an effect that is interrupted as if by the specified fiber. */ def interruptAs(fiberId: => FiberId)(implicit trace: ZTraceElement): UIO[Nothing] = - failCauseWith(trace => Cause.interrupt(fiberId, trace())) + failCause(Cause.interrupt(fiberId)) /** * Prefix form of `ZIO#interruptible`. @@ -6237,10 +6218,9 @@ object ZIO extends ZIOCompanionPlatformSpecific { override def tag = Tags.CheckInterrupt } - private[zio] final class Fail[E](val fill: (() => ZTrace) => Cause[E], val trace: ZTraceElement) - extends IO[E, Nothing] { self => + private[zio] final class Fail[E](val cause: () => Cause[E], val trace: ZTraceElement) extends IO[E, Nothing] { self => def unsafeLog: () => String = - () => s"Fail at ${trace}" + () => s"Fail ${cause()} at ${trace}" override def tag = Tags.Fail diff --git a/core/shared/src/main/scala/zio/internal/FiberContext.scala b/core/shared/src/main/scala/zio/internal/FiberContext.scala index df346453d1db..adfd41a98844 100644 --- a/core/shared/src/main/scala/zio/internal/FiberContext.scala +++ b/core/shared/src/main/scala/zio/internal/FiberContext.scala @@ -350,7 +350,10 @@ private[zio] final class FiberContext[E, A]( else fastPathFlatMapContinuationTrace :: Nil fastPathFlatMapContinuationTrace = null.asInstanceOf[ZTraceElement] - val tracedCause = zio.fill(() => captureTrace(zio.trace :: fastPathTrace)) + val cause = zio.cause() + val tracedCause = + if (cause.isTraced) cause + else cause.traced(captureTrace(zio.trace :: fastPathTrace)) val discardedFolds = unwindStack() val fullCause = From 8fef3aa87abb55810b324cc2f986b4954004f3bb Mon Sep 17 00:00:00 2001 From: "John A. De Goes" Date: Mon, 1 Nov 2021 15:30:49 -0600 Subject: [PATCH 2/2] clean --- .../scala/zio/internal/FiberContext.scala | 25 ++++++++----------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/core/shared/src/main/scala/zio/internal/FiberContext.scala b/core/shared/src/main/scala/zio/internal/FiberContext.scala index adfd41a98844..ec7fec4be04b 100644 --- a/core/shared/src/main/scala/zio/internal/FiberContext.scala +++ b/core/shared/src/main/scala/zio/internal/FiberContext.scala @@ -243,7 +243,7 @@ private[zio] final class FiberContext[E, A]( // Store the trace of the immediate future flatMap during evaluation // of a 1-hop left bind, to show a stack trace closer to the point of failure - var fastPathFlatMapContinuationTrace: ZTraceElement = null.asInstanceOf[ZTraceElement] + var extraTrace: ZTraceElement = null.asInstanceOf[ZTraceElement] if (runtimeConfig.enableCurrentFiber) Fiber._currentFiber.set(this) if (runtimeConfig.superviseOperations && (runtimeConfig.supervisor ne null)) @@ -292,9 +292,9 @@ private[zio] final class FiberContext[E, A]( case ZIO.Tags.Succeed => val io2 = nested.asInstanceOf[ZIO.Succeed[Any]] - fastPathFlatMapContinuationTrace = zio.trace + extraTrace = zio.trace val value = io2.effect() - fastPathFlatMapContinuationTrace = null.asInstanceOf[ZTraceElement] + extraTrace = null.asInstanceOf[ZTraceElement] curZio = k(value) @@ -302,16 +302,16 @@ private[zio] final class FiberContext[E, A]( val io2 = nested.asInstanceOf[ZIO.SucceedWith[Any]] val effect = io2.effect - fastPathFlatMapContinuationTrace = zio.trace + extraTrace = zio.trace val value = effect(runtimeConfig, fiberId) - fastPathFlatMapContinuationTrace = null.asInstanceOf[ZTraceElement] + extraTrace = null.asInstanceOf[ZTraceElement] curZio = k(value) case ZIO.Tags.Yield => - fastPathFlatMapContinuationTrace = zio.trace + extraTrace = zio.trace evaluateLater(k(())) - fastPathFlatMapContinuationTrace = null.asInstanceOf[ZTraceElement] + extraTrace = null.asInstanceOf[ZTraceElement] curZio = null @@ -344,15 +344,12 @@ private[zio] final class FiberContext[E, A]( case ZIO.Tags.Fail => val zio = curZio.asInstanceOf[ZIO.Fail[Any]] - // Put last trace into a val to avoid `ObjectRef` boxing. - val fastPathTrace = - if (fastPathFlatMapContinuationTrace == null) Nil - else fastPathFlatMapContinuationTrace :: Nil - fastPathFlatMapContinuationTrace = null.asInstanceOf[ZTraceElement] + val fastPathTrace = if (extraTrace == null) Nil else extraTrace :: Nil + extraTrace = null.asInstanceOf[ZTraceElement] val cause = zio.cause() - val tracedCause = - if (cause.isTraced) cause + val tracedCause = + if (cause.isTraced) cause else cause.traced(captureTrace(zio.trace :: fastPathTrace)) val discardedFolds = unwindStack()