@@ -50,6 +50,23 @@ object catz extends CatsEffectPlatform {
50
50
object implicits {
51
51
implicit val rts : Runtime [Clock & CBlocking ] = Runtime .default
52
52
}
53
+
54
+ /**
55
+ * `import zio.interop.catz.generic._` brings in instances of
56
+ * `GenConcurrent` and `GenTemporal`,`MonadCancel` and `MonadError`
57
+ * for arbitrary non-Throwable `E` error type.
58
+ *
59
+ * These instances have somewhat different semantics than the instances
60
+ * in `catz` however - they operate on `Cause[E]` errors. Meaning that
61
+ * cats `ApplicativeError#handleErrorWith` operation can now recover from
62
+ * `ZIO.die` and other non-standard ZIO errors not supported by cats IO.
63
+ *
64
+ * However, in cases where an instance such as `MonadCancel[F, _]` is
65
+ * required by a function, these differences should not normally affect behavior -
66
+ * by ignoring the error type, such a function signals that it does not
67
+ * inspect the errors, but only uses `bracket` portion of `MonadCancel` for finalization.
68
+ */
69
+ object generic extends CatsEffectInstancesCause
53
70
}
54
71
55
72
abstract class CatsEffectPlatform
@@ -82,26 +99,50 @@ abstract class CatsEffectInstances extends CatsZioInstances {
82
99
implicit final def asyncInstance [R <: Clock & CBlocking ]: Async [RIO [R , _]] =
83
100
asyncInstance0.asInstanceOf [Async [RIO [R , _]]]
84
101
85
- implicit final def temporalInstance [R <: Clock , E ]: GenTemporal [ZIO [R , E , _], E ] =
86
- temporalInstance0.asInstanceOf [GenTemporal [ZIO [R , E , _], E ]]
102
+ implicit final def temporalInstance [R <: Clock ]: GenTemporal [ZIO [R , Throwable , _], Throwable ] =
103
+ temporalInstance0.asInstanceOf [GenTemporal [ZIO [R , Throwable , _], Throwable ]]
87
104
88
- implicit final def concurrentInstance [R , E ]: GenConcurrent [ZIO [R , E , _], E ] =
89
- concurrentInstance0.asInstanceOf [GenConcurrent [ZIO [R , E , _], E ]]
105
+ implicit final def concurrentInstance [R ]: GenConcurrent [ZIO [R , Throwable , _], Throwable ] =
106
+ concurrentInstance0.asInstanceOf [GenConcurrent [ZIO [R , Throwable , _], Throwable ]]
90
107
91
108
implicit final def asyncRuntimeInstance [R ](implicit runtime : Runtime [Clock & CBlocking ]): Async [RIO [R , _]] =
92
109
new ZioRuntimeAsync (runtime.environment)
93
110
94
- implicit final def temporalRuntimeInstance [R , E ](implicit runtime : Runtime [Clock ]): GenTemporal [ZIO [R , E , _], E ] =
95
- new ZioRuntimeTemporal (runtime.environment)
111
+ implicit final def temporalRuntimeInstance [R ](implicit
112
+ runtime : Runtime [Clock ]
113
+ ): GenTemporal [ZIO [R , Throwable , _], Throwable ] =
114
+ new ZioRuntimeTemporal [R , Throwable , Throwable ](runtime.environment) with ZioMonadErrorExitThrowable [R ]
96
115
97
116
private [this ] val asyncInstance0 : Async [RIO [Clock & CBlocking , _]] =
98
117
new ZioAsync [Clock & CBlocking ] with ZioBlockingEnvIdentity [Clock & CBlocking , Throwable ]
99
118
100
119
private [this ] val temporalInstance0 : Temporal [RIO [Clock , _]] =
101
- new ZioTemporal [Clock , Throwable ] with ZioClockEnvIdentity [Clock , Throwable ]
120
+ new ZioTemporal [Clock , Throwable , Throwable ]
121
+ with ZioClockEnvIdentity [Clock , Throwable ]
122
+ with ZioMonadErrorExitThrowable [Clock ]
102
123
103
124
private [this ] val concurrentInstance0 : Concurrent [Task ] =
104
- new ZioConcurrent [Any , Throwable ]
125
+ new ZioConcurrent [Any , Throwable , Throwable ] with ZioMonadErrorExitThrowable [Any ]
126
+ }
127
+
128
+ sealed abstract class CatsEffectInstancesCause extends CatsZioInstances {
129
+
130
+ implicit final def temporalInstanceCause [R <: Clock , E ]: GenTemporal [ZIO [R , E , _], Cause [E ]] =
131
+ temporalInstance1.asInstanceOf [GenTemporal [ZIO [R , E , _], Cause [E ]]]
132
+
133
+ implicit final def concurrentInstanceCause [R , E ]: GenConcurrent [ZIO [R , E , _], Cause [E ]] =
134
+ concurrentInstance1.asInstanceOf [GenConcurrent [ZIO [R , E , _], Cause [E ]]]
135
+
136
+ implicit final def temporalRuntimeInstanceCause [R , E ](implicit
137
+ runtime : Runtime [Clock ]
138
+ ): GenTemporal [ZIO [R , E , _], Cause [E ]] =
139
+ new ZioRuntimeTemporal [R , E , Cause [E ]](runtime.environment) with ZioMonadErrorExitCause [R , E ]
140
+
141
+ private [this ] val temporalInstance1 : GenTemporal [ZIO [Clock , Any , _], Cause [Any ]] =
142
+ new ZioTemporal [Clock , Any , Cause [Any ]] with ZioClockEnvIdentity [Clock , Any ] with ZioMonadErrorExitCause [Clock , Any ]
143
+
144
+ private [this ] val concurrentInstance1 : GenConcurrent [ZIO [Any , Any , _], Cause [Any ]] =
145
+ new ZioConcurrent [Any , Any , Cause [Any ]] with ZioMonadErrorExitCause [Any , Any ]
105
146
}
106
147
107
148
abstract class CatsZioInstances extends CatsZioInstances1 {
@@ -181,7 +222,7 @@ sealed abstract class CatsZioInstances2 {
181
222
new ZioArrowChoice
182
223
183
224
private [this ] val monadErrorInstance0 : MonadError [Task , Throwable ] =
184
- new ZioMonadError [Any , Throwable ]
225
+ new ZioMonadError [Any , Throwable , Throwable ] with ZioMonadErrorE [ Any , Throwable ]
185
226
}
186
227
187
228
private class ZioDefer [R , E ] extends Defer [ZIO [R , E , _]] {
@@ -191,27 +232,28 @@ private class ZioDefer[R, E] extends Defer[ZIO[R, E, _]] {
191
232
ZIO .effectSuspendTotal(fa)
192
233
}
193
234
194
- private class ZioConcurrent [R , E ] extends ZioMonadError [R , E ] with GenConcurrent [ZIO [R , E , _], E ] {
235
+ private abstract class ZioConcurrent [R , E , E1 ]
236
+ extends ZioMonadErrorExit [R , E , E1 ]
237
+ with GenConcurrent [ZIO [R , E , _], E1 ] {
195
238
196
- private def toPoll (restore : ZIO .InterruptStatusRestore ) = new Poll [ZIO [R , E , _]] {
197
- override def apply [T ](fa : ZIO [R , E , T ]): ZIO [R , E , T ] = restore(fa)
239
+ private def toFiber [A ](fiber : Fiber [E , A ]): effect.Fiber [F , E1 , A ] = new effect.Fiber [F , E1 , A ] {
240
+ override final val cancel : F [Unit ] = fiber.interrupt.unit
241
+ override final val join : F [Outcome [F , E1 , A ]] = fiber.await.map(exitToOutcome)
198
242
}
199
243
200
- private def toFiber [A ](fiber : Fiber [E , A ]) = new effect.Fiber [F , E , A ] {
201
- override final val cancel : F [Unit ] = fiber.interrupt.unit
202
- override final val join : F [Outcome [F , E , A ]] = fiber.await.map(toOutcome)
203
- }
204
-
205
- private def fiberFailure (error : E ) =
206
- FiberFailure (Cause .fail(error))
244
+ private def toThrowableOrFiberFailure (error : E ): Throwable =
245
+ error match {
246
+ case t : Throwable => t
247
+ case _ => FiberFailure (Cause .fail(error))
248
+ }
207
249
208
250
override def ref [A ](a : A ): F [effect.Ref [F , A ]] =
209
251
ZRef .make(a).map(new ZioRef (_))
210
252
211
253
override def deferred [A ]: F [Deferred [F , A ]] =
212
254
Promise .make[E , A ].map(new ZioDeferred (_))
213
255
214
- override final def start [A ](fa : F [A ]): F [effect.Fiber [F , E , A ]] =
256
+ override final def start [A ](fa : F [A ]): F [effect.Fiber [F , E1 , A ]] =
215
257
fa.interruptible.forkDaemon.map(toFiber)
216
258
217
259
override def never [A ]: F [A ] =
@@ -224,31 +266,34 @@ private class ZioConcurrent[R, E] extends ZioMonadError[R, E] with GenConcurrent
224
266
fa.foldCauseM(cause => if (cause.interrupted) ZIO .halt(cause) else fb, _ => fb)
225
267
226
268
override final def uncancelable [A ](body : Poll [F ] => F [A ]): F [A ] =
227
- ZIO .uninterruptibleMask(body.compose (toPoll))
269
+ ZIO .uninterruptibleMask(restore => body(toPoll(restore) ))
228
270
229
271
override final def canceled : F [Unit ] =
230
272
ZIO .interrupt
231
273
232
274
override final def onCancel [A ](fa : F [A ], fin : F [Unit ]): F [A ] =
233
- fa.onError(cause => fin.orDieWith(fiberFailure ).unless(cause.failed))
275
+ fa.onError(cause => fin.orDieWith(toThrowableOrFiberFailure ).unless(cause.failed))
234
276
235
277
override final def memoize [A ](fa : F [A ]): F [F [A ]] =
236
278
fa.memoize
237
279
238
- override final def racePair [A , B ](fa : F [A ], fb : F [B ]) =
280
+ override final def racePair [A , B ](
281
+ fa : F [A ],
282
+ fb : F [B ]
283
+ ): ZIO [R , Nothing , Either [(Outcome [F , E1 , A ], effect.Fiber [F , E1 , B ]), (effect.Fiber [F , E1 , A ], Outcome [F , E1 , B ])]] =
239
284
(fa.interruptible raceWith fb.interruptible)(
240
- (exit, fiber) => ZIO .succeedNow(Left ((toOutcome (exit), toFiber(fiber)))),
241
- (exit, fiber) => ZIO .succeedNow(Right ((toFiber(fiber), toOutcome (exit))))
285
+ (exit, fiber) => ZIO .succeedNow(Left ((exitToOutcome (exit), toFiber(fiber)))),
286
+ (exit, fiber) => ZIO .succeedNow(Right ((toFiber(fiber), exitToOutcome (exit))))
242
287
)
243
288
244
289
override final def both [A , B ](fa : F [A ], fb : F [B ]): F [(A , B )] =
245
290
fa.interruptible zipPar fb.interruptible
246
291
247
292
override final def guarantee [A ](fa : F [A ], fin : F [Unit ]): F [A ] =
248
- fa.ensuring(fin.orDieWith(fiberFailure ))
293
+ fa.ensuring(fin.orDieWith(toThrowableOrFiberFailure ))
249
294
250
295
override final def bracket [A , B ](acquire : F [A ])(use : A => F [B ])(release : A => F [Unit ]): F [B ] =
251
- acquire.bracket(release.andThen(_.orDieWith(fiberFailure )), use)
296
+ acquire.bracket(release.andThen(_.orDieWith(toThrowableOrFiberFailure )), use)
252
297
253
298
override val unique : F [Unique .Token ] =
254
299
ZIO .effectTotal(new Unique .Token )
@@ -316,9 +361,9 @@ private final class ZioRef[R, E, A](ref: ERef[E, A]) extends effect.Ref[ZIO[R, E
316
361
ref.get
317
362
}
318
363
319
- private abstract class ZioTemporal [R , E ]
320
- extends ZioConcurrent [R , E ]
321
- with GenTemporal [ZIO [R , E , _], E ]
364
+ private abstract class ZioTemporal [R , E , E1 ]
365
+ extends ZioConcurrent [R , E , E1 ]
366
+ with GenTemporal [ZIO [R , E , _], E1 ]
322
367
with ZioClockEnv [R , E ] {
323
368
324
369
override final def sleep (time : FiniteDuration ): F [Unit ] =
@@ -331,7 +376,9 @@ private abstract class ZioTemporal[R, E]
331
376
withClock(currentTime(MILLISECONDS ).map(FiniteDuration (_, MILLISECONDS )))
332
377
}
333
378
334
- private class ZioRuntimeTemporal [R , E ](environment : Clock ) extends ZioTemporal [R , E ] with ZioClockEnv [R , E ] {
379
+ private abstract class ZioRuntimeTemporal [R , E , E1 ](environment : Clock )
380
+ extends ZioTemporal [R , E , E1 ]
381
+ with ZioClockEnv [R , E ] {
335
382
336
383
override protected [this ] def withClock [A ](fa : ZIO [Clock , E , A ]): ZIO [R , E , A ] = fa.provide(environment)
337
384
@@ -364,7 +411,7 @@ private trait ZioBlockingEnvIdentity[R <: Clock & CBlocking, E]
364
411
override protected [this ] def withBlocking [A ](fa : ZIO [CBlocking , E , A ]): ZIO [R , E , A ] = fa
365
412
}
366
413
367
- private class ZioMonadError [R , E ] extends MonadError [ZIO [R , E , _], E ] {
414
+ private abstract class ZioMonadError [R , E , E1 ] extends MonadError [ZIO [R , E , _], E1 ] {
368
415
type F [A ] = ZIO [R , E , A ]
369
416
370
417
override final def pure [A ](a : A ): F [A ] =
@@ -394,6 +441,19 @@ private class ZioMonadError[R, E] extends MonadError[ZIO[R, E, _], E] {
394
441
override final def unit : F [Unit ] =
395
442
ZIO .unit
396
443
444
+ override final def tailRecM [A , B ](a : A )(f : A => F [Either [A , B ]]): F [B ] = {
445
+ def loop (a : A ): F [B ] = f(a).flatMap {
446
+ case Left (a) => loop(a)
447
+ case Right (b) => ZIO .succeedNow(b)
448
+ }
449
+
450
+ ZIO .effectSuspendTotal(loop(a))
451
+ }
452
+
453
+ }
454
+
455
+ private trait ZioMonadErrorE [R , E ] extends ZioMonadError [R , E , E ] {
456
+
397
457
override final def handleErrorWith [A ](fa : F [A ])(f : E => F [A ]): F [A ] =
398
458
fa.catchAll(f)
399
459
@@ -408,15 +468,48 @@ private class ZioMonadError[R, E] extends MonadError[ZIO[R, E, _], E] {
408
468
409
469
override final def adaptError [A ](fa : F [A ])(pf : PartialFunction [E , E ]): F [A ] =
410
470
fa.mapError(pf.orElse { case error => error })
471
+ }
411
472
412
- override final def tailRecM [A , B ](a : A )(f : A => F [Either [A , B ]]): F [B ] = {
413
- def loop (a : A ): F [B ] = f(a).flatMap {
414
- case Left (a) => loop(a)
415
- case Right (b) => ZIO .succeedNow(b)
473
+ private trait ZioMonadErrorCause [R , E ] extends ZioMonadError [R , E , Cause [E ]] {
474
+
475
+ override final def handleErrorWith [A ](fa : F [A ])(f : Cause [E ] => F [A ]): F [A ] =
476
+ // fa.catchAllCause(f)
477
+ fa.catchSomeCause {
478
+ // pretend that we can't catch inner interrupt to satisfy `uncancelable canceled associates right over flatMap attempt`
479
+ // law since we use a poor definition of `canceled=ZIO.interrupt` right now
480
+ // https://github.com/zio/interop-cats/issues/503#issuecomment-1157101175=
481
+ case c if ! c.interrupted => f(c)
416
482
}
417
483
418
- ZIO .effectSuspendTotal(loop(a))
419
- }
484
+ override final def recoverWith [A ](fa : F [A ])(pf : PartialFunction [Cause [E ], F [A ]]): F [A ] =
485
+ // fa.catchSomeCause(pf)
486
+ fa.catchSomeCause(({ case c if ! c.interrupted => c }: PartialFunction [Cause [E ], Cause [E ]]).andThen(pf))
487
+
488
+ override final def raiseError [A ](e : Cause [E ]): F [A ] =
489
+ ZIO .halt(e)
490
+
491
+ override final def attempt [A ](fa : F [A ]): F [Either [Cause [E ], A ]] =
492
+ // fa.sandbox.attempt
493
+ fa.map(Right (_)).catchSomeCause {
494
+ case c if ! c.interrupted => ZIO .succeedNow(Left (c))
495
+ }
496
+
497
+ override final def adaptError [A ](fa : F [A ])(pf : PartialFunction [Cause [E ], Cause [E ]]): F [A ] =
498
+ fa.mapErrorCause(pf.orElse { case error => error })
499
+ }
500
+
501
+ private abstract class ZioMonadErrorExit [R , E , E1 ] extends ZioMonadError [R , E , E1 ] {
502
+ protected def exitToOutcome [A ](exit : Exit [E , A ]): Outcome [F , E1 , A ]
503
+ }
504
+
505
+ private trait ZioMonadErrorExitThrowable [R ]
506
+ extends ZioMonadErrorExit [R , Throwable , Throwable ]
507
+ with ZioMonadErrorE [R , Throwable ] {
508
+ override protected def exitToOutcome [A ](exit : Exit [Throwable , A ]): Outcome [F , Throwable , A ] = toOutcomeThrowable(exit)
509
+ }
510
+
511
+ private trait ZioMonadErrorExitCause [R , E ] extends ZioMonadErrorExit [R , E , Cause [E ]] with ZioMonadErrorCause [R , E ] {
512
+ override protected def exitToOutcome [A ](exit : Exit [E , A ]): Outcome [F , Cause [E ], A ] = toOutcomeCause(exit)
420
513
}
421
514
422
515
private class ZioSemigroupK [R , E ] extends SemigroupK [ZIO [R , E , _]] {
0 commit comments