Repository: 7mind/izumi
Pull request #793 (2019-12-19 23:43:46)

Fix cats conversions type inference & implicit priority


Patch:
diff --git a/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOCatsConversions.scala b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOCatsConversions.scala
index 53f1670f4..6dd844ffc 100644
--- a/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOCatsConversions.scala
+++ b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOCatsConversions.scala
@@ -19,46 +19,44 @@ import scala.util.Either
   * }}}
   */
 trait BIOCatsConversions extends BIOCatsConversions1 {
-  @inline implicit final def BIOAsyncForkToConcurrent[F[+_, +_]](implicit F: BIOAsync[F], Fork: BIOFork[F]): BIOCatsConcurrent[F] = new BIOCatsConcurrent[F](F, Fork)
+  @inline implicit final def BIOToFunctor[F[_, +_], E](implicit F0: BIOFunctor[F]): BIOCatsFunctor[F, E] = new BIOCatsFunctor[F, E] {
+    override val F: BIOFunctor[F] = F0
+  }
 }
-
 trait BIOCatsConversions1 extends BIOCatsConversions2 {
-  @inline implicit final def BIOAsyncToAsync[F[+_, +_]](implicit F: BIOAsync[F]): BIOCatsAsync[F] = new BIOCatsAsync[F](F)
+  /** search for BIOFunctor first to pin F to the closest lexically available effect type */
+  @inline implicit final def BIOToBifunctor[F[+_, +_]](implicit @deprecated("unused","unused") ev: BIOFunctor[F], F0: BIOBifunctor[F]): BIOCatsBifunctor[F] = new BIOCatsBifunctor[F] {
+    override val F: BIOBifunctor[F] = F0
+  }
 }
-
 trait BIOCatsConversions2 extends BIOCatsConversions3 {
-  @inline implicit final def BIOToSync[F[+_, +_]](implicit F: BIO[F]): BIOCatsSync[F] = new BIOCatsSync[F](F)
+  @inline implicit final def BIOToApplicative[F[+_, +_], E](implicit @deprecated("unused","unused") ev: BIOFunctor[F], F0: BIOApplicative[F]): BIOCatsApplicative[F, E] = new BIOCatsApplicative[F, E] {
+    override val F: BIOApplicative[F] = F0
+  }
 }
-
 trait BIOCatsConversions3 extends BIOCatsConversions4 {
-  @inline implicit final def BIOToBracket[F[+_, +_]](implicit F: BIOPanic[F]): BIOCatsBracket[F] = new BIOCatsBracket[F](F)
+  @inline implicit final def BIOToApplicativeError[F[+_, +_], E](implicit @deprecated("unused","unused") ev: BIOFunctor[F], F0: BIOError[F]): BIOCatsApplicativeError[F, E] = new BIOCatsApplicativeError[F, E] {
+    override val F: BIOError[F] = F0
+  }
 }
-
 trait BIOCatsConversions4 extends BIOCatsConversions5 {
-  @inline implicit final def BIOToMonadError[F[+_, +_], E](implicit F: BIOMonadError[F]): BIOCatsMonadError[F, E] = new BIOCatsMonadError[F, E](F)
+  @inline implicit final def BIOToMonad[F[+_, +_], E](implicit @deprecated("unused","unused") ev: BIOFunctor[F], F: BIOMonad[F]): BIOCatsMonad[F, E] = new BIOCatsMonad[F, E](F)
 }
 trait BIOCatsConversions5 extends BIOCatsConversions6 {
-  @inline implicit final def BIOToMonad[F[+_, +_], E](implicit F: BIOMonad[F]): BIOCatsMonad[F, E] = new BIOCatsMonad[F, E](F)
+  @inline implicit final def BIOToMonadError[F[+_, +_], E](implicit @deprecated("unused","unused") ev: BIOFunctor[F], F: BIOMonadError[F]): BIOCatsMonadError[F, E] = new BIOCatsMonadError[F, E](F)
 }
 trait BIOCatsConversions6 extends BIOCatsConversions7 {
-  @inline implicit final def BIOToApplicativeError[F[+_, +_], E](implicit F0: BIOError[F]): BIOCatsApplicativeError[F, E] = new BIOCatsApplicativeError[F, E] {
-    override val F: BIOError[F] = F0
-  }
+  @inline implicit final def BIOToBracket[F[+_, +_]](implicit @deprecated("unused","unused") ev: BIOFunctor[F], F: BIOPanic[F]): BIOCatsBracket[F] = new BIOCatsBracket[F](F)
 }
 trait BIOCatsConversions7 extends BIOCatsConversions8 {
-  @inline implicit final def BIOToApplicative[F[+_, +_], E](implicit F0: BIOApplicative[F]): BIOCatsApplicative[F, E] = new BIOCatsApplicative[F, E] {
-    override val F: BIOApplicative[F] = F0
-  }
+  @inline implicit final def BIOToSync[F[+_, +_]](implicit @deprecated("unused","unused") ev: BIOFunctor[F], F: BIO[F]): BIOCatsSync[F] = new BIOCatsSync[F](F)
 }
 trait BIOCatsConversions8 extends BIOCatsConversions9 {
-  @inline implicit final def BIOToBifunctor[F[+_, +_]](implicit F0: BIOBifunctor[F]): BIOCatsBifunctor[F] = new BIOCatsBifunctor[F] {
-    override val F: BIOBifunctor[F] = F0
-  }
+  @inline implicit final def BIOAsyncToAsync[F[+_, +_]](implicit @deprecated("unused","unused") ev: BIOFunctor[F], F: BIOAsync[F]): BIOCatsAsync[F] = new BIOCatsAsync[F](F)
 }
+
 trait BIOCatsConversions9 {
-  @inline implicit final def BIOToFunctor[F[_, +_], E](implicit F0: BIOFunctor[F]): BIOCatsFunctor[F, E] = new BIOCatsFunctor[F, E] {
-    override val F: BIOFunctor[F] = F0
-  }
+  @inline implicit final def BIOAsyncForkToConcurrent[F[+_, +_]](implicit @deprecated("unused","unused") ev: BIOFunctor[F], F: BIOAsync[F], Fork: BIOFork[F]): BIOCatsConcurrent[F] = new BIOCatsConcurrent[F](F, Fork)
 }
 
 object BIOCatsConversions {
diff --git a/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/package.scala b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/package.scala
index 030a3111a..6ade55a97 100644
--- a/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/package.scala
+++ b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/package.scala
@@ -5,7 +5,7 @@ import java.util.concurrent.CompletionStage
 import cats.~>
 import izumi.functional.bio.impl.{BIOTemporalZio, BIOZio}
 import izumi.functional.mono.{Clock, Entropy, SyncSafe}
-import zio.{IO, ZIO}
+import zio.ZIO
 
 import scala.concurrent.duration.{Duration, FiniteDuration}
 import scala.concurrent.{ExecutionContext, Future}
@@ -227,7 +227,7 @@ package object bio extends BIOSyntax {
     }
   }
 
-  trait BIOAsync[F[+_, +_]] extends BIO[F] with BIOTemporalInstances {
+  trait BIOAsync[F[+_, +_]] extends BIO[F] {
     final type Canceler = F[Nothing, Unit]
 
     def async[E, A](register: (Either[E, A] => Unit) => Unit): F[E, A]


Test patch:
diff --git a/fundamentals/fundamentals-bio/src/test/scala/izumi/fundamentals/bio/test/CatsConversionTest.scala b/fundamentals/fundamentals-bio/src/test/scala/izumi/fundamentals/bio/test/CatsConversionTest.scala
new file mode 100644
index 000000000..d8b7553d9
--- /dev/null
+++ b/fundamentals/fundamentals-bio/src/test/scala/izumi/fundamentals/bio/test/CatsConversionTest.scala
@@ -0,0 +1,23 @@
+package izumi.fundamentals.bio.test
+
+import cats.effect.concurrent.Ref
+import cats.effect.{Async, Sync}
+import izumi.functional.bio.BIO
+import izumi.functional.bio.catz._
+import org.scalatest.WordSpec
+
+class CatsConversionTest extends WordSpec {
+
+  class X[F[+_, +_]: BIO](val ref: Ref[F[Throwable, ?], Int])
+
+  "pickup conversion to Sync" in {
+    def conv[F[+_, +_]: BIO]: F[Throwable, Int] = {
+      Ref.of(0)
+        .flatMap(_.get)
+    }
+    conv[zio.IO]
+    implicitly[Sync[zio.Task]]
+    implicitly[Async[zio.Task]]
+  }
+
+}