From 0491d43b03c88e7daeb11ff54c619d854856c1f9 Mon Sep 17 00:00:00 2001 From: Tim Spence Date: Mon, 23 May 2022 17:56:32 +0100 Subject: [PATCH] Various improvements - ImplicitNotFound error for SemigroupK/MonoidK - Replace given priority via traits with NotGiven --- .../scala-3/cats/derived/DerivedMonoidK.scala | 38 ++++++++++++------- .../cats/derived/DerivedSemigroupK.scala | 24 +++++++----- .../scala-3/cats/derived/MonoidKSuite.scala | 4 +- .../cats/derived/SemigroupKSuite.scala | 1 - 4 files changed, 41 insertions(+), 26 deletions(-) diff --git a/core/src/main/scala-3/cats/derived/DerivedMonoidK.scala b/core/src/main/scala-3/cats/derived/DerivedMonoidK.scala index d1ca05c2..3f9d64be 100644 --- a/core/src/main/scala-3/cats/derived/DerivedMonoidK.scala +++ b/core/src/main/scala-3/cats/derived/DerivedMonoidK.scala @@ -3,10 +3,19 @@ package cats.derived import cats.* import shapeless3.deriving.{Const, K1} +import scala.annotation.implicitNotFound import scala.compiletime.* - +import scala.util.NotGiven + +@implicitNotFound("""Could not derive an instance of MonoidK[F] where F = ${F}. +Make sure that F[_] satisfies one of the following conditions: + * it is a constant type [x] =>> T where T: Monoid + * it is a nested type [x] =>> G[H[x]] where G: MonoidK + * it is a nested type [x] =>> G[H[x]] where G: Applicative and H: MonoidK + * it is a generic case class where all fields have a MonoidK instance +""") type DerivedMonoidK[F[_]] = Derived[MonoidK[F]] -object DerivedMonoidK extends DerivedMonoidKInstances1: +object DerivedMonoidK: type Or[F[_]] = Derived.Or[MonoidK[F]] inline def apply[F[_]]: MonoidK[F] = import DerivedMonoidK.given @@ -20,6 +29,19 @@ object DerivedMonoidK extends DerivedMonoidKInstances1: given [F[_], G[_]](using F: Or[F]): DerivedMonoidK[[x] =>> F[G[x]]] = F.unify.compose[G] + given [F[_], G[_]](using + N: NotGiven[Or[F]], + F0: DerivedApplicative.Or[F], + G0: Or[G] + ): DerivedMonoidK[[x] =>> F[G[x]]] = + new MonoidK[[x] =>> F[G[x]]]: + val F: Applicative[F] = F0.unify + val G: MonoidK[G] = G0.unify + + final override def empty[A]: F[G[A]] = F.pure(G.empty[A]) + + final override def combineK[A](x: F[G[A]], y: F[G[A]]): F[G[A]] = F.map2(x, y)(G.combineK(_, _)) + given [F[_]](using inst: => K1.ProductInstances[Or, F]): DerivedMonoidK[F] = given K1.ProductInstances[MonoidK, F] = inst.unify new Product[MonoidK, F] {} @@ -28,15 +50,3 @@ object DerivedMonoidK extends DerivedMonoidKInstances1: extends MonoidK[F], DerivedSemigroupK.Product[T, F]: final override def empty[A]: F[A] = inst.construct([t[_]] => (emp: T[t]) => emp.empty[A]) - -trait DerivedMonoidKInstances1: - import DerivedMonoidK.Or - - given [F[_], G[_]](using F0: DerivedApplicative.Or[F], G0: Or[G]): DerivedMonoidK[[x] =>> F[G[x]]] = - new MonoidK[[x] =>> F[G[x]]]: - val F: Applicative[F] = F0.unify - val G: MonoidK[G] = G0.unify - - final override def empty[A]: F[G[A]] = F.pure(G.empty[A]) - - final override def combineK[A](x: F[G[A]], y: F[G[A]]): F[G[A]] = F.map2(x, y)(G.combineK(_, _)) diff --git a/core/src/main/scala-3/cats/derived/DerivedSemigroupK.scala b/core/src/main/scala-3/cats/derived/DerivedSemigroupK.scala index 26b6f124..b826cf28 100644 --- a/core/src/main/scala-3/cats/derived/DerivedSemigroupK.scala +++ b/core/src/main/scala-3/cats/derived/DerivedSemigroupK.scala @@ -3,10 +3,19 @@ package cats.derived import cats.{Semigroup, SemigroupK} import shapeless3.deriving.{Const, K1} +import scala.annotation.implicitNotFound import scala.compiletime.* - +import scala.util.NotGiven + +@implicitNotFound("""Could not derive an instance of SemigroupK[F] where F = ${F}. +Make sure that F[_] satisfies one of the following conditions: + * it is a constant type [x] =>> T where T: Semigroup + * it is a nested type [x] =>> G[H[x]] where G: SemigroupK + * it is a nested type [x] =>> G[H[x]] where G: Apply and H: SemigroupK + * it is a generic case class where all fields have a SemigroupK instance +""") type DerivedSemigroupK[F[_]] = Derived[SemigroupK[F]] -object DerivedSemigroupK extends DerivedSemigroupKInstances1: +object DerivedSemigroupK: type Or[F[_]] = Derived.Or[SemigroupK[F]] inline def apply[F[_]]: SemigroupK[F] = import DerivedSemigroupK.given @@ -18,6 +27,10 @@ object DerivedSemigroupK extends DerivedSemigroupKInstances1: given [F[_], G[_]](using F: Or[F]): DerivedSemigroupK[[x] =>> F[G[x]]] = F.unify.compose[G] + given [F[_], G[_]](using N: NotGiven[Or[F]], F: DerivedApply.Or[F], G: Or[G]): DerivedSemigroupK[[x] =>> F[G[x]]] = + new SemigroupK[[x] =>> F[G[x]]]: + final override def combineK[A](x: F[G[A]], y: F[G[A]]): F[G[A]] = F.unify.map2(x, y)(G.unify.combineK(_, _)) + given [F[_]](using inst: => K1.ProductInstances[Or, F]): DerivedSemigroupK[F] = given K1.ProductInstances[SemigroupK, F] = inst.unify new Product[SemigroupK, F] {} @@ -25,10 +38,3 @@ object DerivedSemigroupK extends DerivedSemigroupKInstances1: trait Product[T[x[_]] <: SemigroupK[x], F[_]](using inst: K1.ProductInstances[T, F]) extends SemigroupK[F]: final override def combineK[A](x: F[A], y: F[A]): F[A] = inst.map2[A, A, A](x, y)([t[_]] => (smgrpk: T[t], x: t[A], y: t[A]) => smgrpk.combineK(x, y)) - -trait DerivedSemigroupKInstances1: - import DerivedSemigroupK.Or - - given [F[_], G[_]](using F: DerivedApply.Or[F], G: Or[G]): DerivedSemigroupK[[x] =>> F[G[x]]] = - new SemigroupK[[x] =>> F[G[x]]]: - final override def combineK[A](x: F[G[A]], y: F[G[A]]): F[G[A]] = F.unify.map2(x, y)(G.unify.combineK(_, _)) diff --git a/core/src/test/scala-3/cats/derived/MonoidKSuite.scala b/core/src/test/scala-3/cats/derived/MonoidKSuite.scala index b5fa1b18..f36190c5 100644 --- a/core/src/test/scala-3/cats/derived/MonoidKSuite.scala +++ b/core/src/test/scala-3/cats/derived/MonoidKSuite.scala @@ -32,7 +32,7 @@ class MonoidKSuite extends KittensSuite { } { - import semiInstances.given + import monInstances.given testMonoidK("semi") } } @@ -42,7 +42,7 @@ object MonoidKSuite { type BoxMul[A] = Box[Mul[A]] - object semiInstances { + object monInstances { implicit val complexProduct: MonoidK[ComplexProduct] = semiauto.monoidK implicit val caseClassWOption: MonoidK[CaseClassWOption] = semiauto.monoidK implicit val boxMul: MonoidK[BoxMul] = semiauto.monoidK diff --git a/core/src/test/scala-3/cats/derived/SemigroupKSuite.scala b/core/src/test/scala-3/cats/derived/SemigroupKSuite.scala index 7b79c9b3..b914fa70 100644 --- a/core/src/test/scala-3/cats/derived/SemigroupKSuite.scala +++ b/core/src/test/scala-3/cats/derived/SemigroupKSuite.scala @@ -25,7 +25,6 @@ class SemigroupKSuite extends KittensSuite { locally { import auto.semigroupK.given - summon[SemigroupK[[a] =>> Eval[Option[a]]]] testSemigroupK("auto") }