From 076ffce4420726d622fc29ffcf9c52c714451db7 Mon Sep 17 00:00:00 2001 From: Georgi Krastev Date: Mon, 8 Jan 2024 00:19:23 +0200 Subject: [PATCH] Strict semiauto derivation for Scala 3 (#626) * Strict semiauto derivation for Scala 3 * Strict derivation for Hash * Strict derivation for Empty * Strict derivation for Semigroup * Strict derivation for Monoid * Strict derivation for Order * Strict derivation for CommutativeSemigroup * Strict derivation for CommutativeMonoid * Deprecate nameless givens * Strict derivation for Show * Strict derivation for PartialOrder * Strict derivation for ShowPretty * Strict derivation for EmptyK * Strict derivation for SemigroupK * Strict derivation for MonoidK * Strict derivation for Pure * Strict derivation for Invariant * Reduce number of deprecated methods * Strict derivation for Functor * Strict derivation for Contravariant * Strict derivation for Foldable * Strict validation for Apply * Strict derivation for Applicative * Strict derivation for Reducible * Strict derivation for Traverse * Strict derivation for NonEmptyTraverse * Restrict strict derivation to product and coproduct --- .../main/scala-3/cats/derived/Derived.scala | 5 +- .../cats/derived/DerivedApplicative.scala | 20 +++++-- .../scala-3/cats/derived/DerivedApply.scala | 16 ++++-- .../derived/DerivedCommutativeMonoid.scala | 12 +++- .../derived/DerivedCommutativeSemigroup.scala | 12 +++- .../cats/derived/DerivedContravariant.scala | 21 +++++-- .../scala-3/cats/derived/DerivedEmpty.scala | 17 ++++-- .../scala-3/cats/derived/DerivedEmptyK.scala | 49 ++++++++++------- .../main/scala-3/cats/derived/DerivedEq.scala | 13 ++++- .../cats/derived/DerivedFoldable.scala | 26 ++++++--- .../scala-3/cats/derived/DerivedFunctor.scala | 26 ++++++--- .../scala-3/cats/derived/DerivedHash.scala | 13 ++++- .../cats/derived/DerivedInvariant.scala | 19 +++++-- .../scala-3/cats/derived/DerivedMonoid.scala | 12 +++- .../scala-3/cats/derived/DerivedMonoidK.scala | 42 +++++++++----- .../derived/DerivedNonEmptyTraverse.scala | 44 ++++++++++----- .../scala-3/cats/derived/DerivedOrder.scala | 13 ++++- .../cats/derived/DerivedPartialOrder.scala | 13 ++++- .../scala-3/cats/derived/DerivedPure.scala | 25 ++++++--- .../cats/derived/DerivedReducible.scala | 31 ++++++++--- .../cats/derived/DerivedSemigroup.scala | 14 ++++- .../cats/derived/DerivedSemigroupK.scala | 34 ++++++++---- .../scala-3/cats/derived/DerivedShow.scala | 21 +++++-- .../cats/derived/DerivedShowPretty.scala | 30 +++++++--- .../cats/derived/DerivedTraverse.scala | 26 ++++++--- .../main/scala-3/cats/derived/package.scala | 55 ++++++++++++++++++- core/src/test/scala-3/cats/derived/ADTs.scala | 1 + .../cats/derived/ApplicativeSuite.scala | 26 ++++++--- .../scala-3/cats/derived/ApplySuite.scala | 18 +++++- .../cats/derived/CommutativeMonoidSuite.scala | 22 +++++--- .../derived/CommutativeSemigroupSuite.scala | 22 +++++--- .../cats/derived/ContravariantSuite.scala | 32 ++++++++--- .../scala-3/cats/derived/EmptyKSuite.scala | 23 ++++++-- .../scala-3/cats/derived/EmptySuite.scala | 35 +++++++++--- .../test/scala-3/cats/derived/EqSuite.scala | 16 ++++++ .../scala-3/cats/derived/FoldableSuite.scala | 26 +++++++++ .../scala-3/cats/derived/FunctorSuite.scala | 28 +++++++++- .../test/scala-3/cats/derived/HashSuite.scala | 16 ++++++ .../scala-3/cats/derived/InvariantSuite.scala | 33 ++++++++++- .../scala-3/cats/derived/KittensSuite.scala | 8 ++- .../scala-3/cats/derived/MonoidKSuite.scala | 29 +++++++--- .../scala-3/cats/derived/MonoidSuite.scala | 23 +++++--- .../cats/derived/NonEmptyTraverseSuite.scala | 26 ++++++++- .../scala-3/cats/derived/OrderSuite.scala | 15 +++++ .../cats/derived/PartialOrderSuite.scala | 22 +++++++- .../test/scala-3/cats/derived/PureSuite.scala | 26 ++++++++- .../scala-3/cats/derived/ReducibleSuite.scala | 27 ++++++++- .../cats/derived/SemigroupKSuite.scala | 29 +++++++--- .../scala-3/cats/derived/SemigroupSuite.scala | 23 +++++--- .../cats/derived/ShowPrettySuite.scala | 21 +++++++ .../test/scala-3/cats/derived/ShowSuite.scala | 22 ++++++++ .../scala-3/cats/derived/TraverseSuite.scala | 25 +++++++++ 52 files changed, 952 insertions(+), 251 deletions(-) diff --git a/core/src/main/scala-3/cats/derived/Derived.scala b/core/src/main/scala-3/cats/derived/Derived.scala index cae1f600..9efcaf22 100644 --- a/core/src/main/scala-3/cats/derived/Derived.scala +++ b/core/src/main/scala-3/cats/derived/Derived.scala @@ -30,11 +30,10 @@ object Derived: extension [I[f[_[_, _]], t[_, _]] <: K2.Instances[f, t], F[_[_, _]], T[_, _]](inst: I[Or2[F], T]) @targetName("unifyK2") def unify: I[F, T] = inst - abstract private[derived] class Lazy[A](f: () => A) extends Serializable: + private[derived] class Lazy[A](f: () => A) extends Serializable: final protected lazy val delegate: A = f() sealed abstract class OrInstances: - inline given [A]: Derived.Or[A] = summonFrom { + inline given [A]: Derived.Or[A] = summonFrom: case instance: A => Derived.Or(instance) case derived: Derived[A] => Derived.Or(derived.instance) - } diff --git a/core/src/main/scala-3/cats/derived/DerivedApplicative.scala b/core/src/main/scala-3/cats/derived/DerivedApplicative.scala index 249e24ba..c3ecd982 100644 --- a/core/src/main/scala-3/cats/derived/DerivedApplicative.scala +++ b/core/src/main/scala-3/cats/derived/DerivedApplicative.scala @@ -20,22 +20,32 @@ object DerivedApplicative: import DerivedApplicative.given summonInline[DerivedApplicative[F]].instance + @nowarn("msg=unused import") + inline def strict[F[_]]: Applicative[F] = + import Strict.given + summonInline[DerivedApplicative[F]].instance + given [T](using T: Monoid[T]): DerivedApplicative[Const[T]] = new Applicative[Const[T]]: def pure[A](x: A): T = T.empty def ap[A, B](ff: T)(fa: T): T = T.combine(ff, fa) given nested[F[_], G[_]](using F: => Or[F], G: => Or[G]): DerivedApplicative[[x] =>> F[G[x]]] = - new Derived.Lazy(() => F.unify.compose(G.unify)) with Applicative[[x] =>> F[G[x]]]: + new Derived.Lazy(() => F.unify.compose(using G.unify)) with Applicative[[x] =>> F[G[x]]]: export delegate.* given [F[_]](using inst: => K1.ProductInstances[Or, F]): DerivedApplicative[F] = - given K1.ProductInstances[Applicative, F] = inst.unify - new Product[Applicative, F] with DerivedApply.Product[Applicative, F] {} + Strict.product(using inst.unify) @deprecated("Kept for binary compatibility", "3.2.0") - private[derived] def given_DerivedApplicative_F[F[_]: Or, G[_]: Or]: DerivedApplicative[[x] =>> F[G[x]]] = summon + protected given [F[_]: Or, G[_]: Or]: DerivedApplicative[[x] =>> F[G[x]]] = nested trait Product[T[f[_]] <: Applicative[f], F[_]](using inst: K1.ProductInstances[T, F]) extends Applicative[F], DerivedApply.Product[T, F]: - final override def pure[A](x: A): F[A] = inst.construct([f[_]] => (F: T[f]) => F.pure[A](x)) + + final override def pure[A](x: A): F[A] = + inst.construct([f[_]] => (F: T[f]) => F.pure[A](x)) + + object Strict: + given product[F[_]](using K1.ProductInstances[Applicative, F]): DerivedApplicative[F] = + new Product[Applicative, F] with DerivedApply.Product[Applicative, F] {} diff --git a/core/src/main/scala-3/cats/derived/DerivedApply.scala b/core/src/main/scala-3/cats/derived/DerivedApply.scala index ced56aed..af64da81 100644 --- a/core/src/main/scala-3/cats/derived/DerivedApply.scala +++ b/core/src/main/scala-3/cats/derived/DerivedApply.scala @@ -20,23 +20,31 @@ object DerivedApply: import DerivedApply.given summonInline[DerivedApply[F]].instance + @nowarn("msg=unused import") + inline def strict[F[_]]: Apply[F] = + import Strict.given + summonInline[DerivedApply[F]].instance + given [T](using T: Semigroup[T]): DerivedApply[Const[T]] = new Apply[Const[T]]: def ap[A, B](ff: T)(fa: T): T = T.combine(ff, fa) def map[A, B](fa: T)(f: A => B): T = fa given nested[F[_], G[_]](using F: => Or[F], G: => Or[G]): DerivedApply[[x] =>> F[G[x]]] = - new Derived.Lazy(() => F.unify.compose(G.unify)) with Apply[[x] =>> F[G[x]]]: + new Derived.Lazy(() => F.unify.compose(using G.unify)) with Apply[[x] =>> F[G[x]]]: export delegate.* given [F[_]](using inst: => K1.ProductInstances[Or, F]): DerivedApply[F] = - given K1.ProductInstances[Apply, F] = inst.unify - new Product[Apply, F] {} + Strict.product(using inst.unify) @deprecated("Kept for binary compatibility", "3.2.0") - private[derived] def given_DerivedApply_F[F[_]: Or, G[_]: Or]: DerivedApply[[x] =>> F[G[x]]] = summon + protected given [F[_]: Or, G[_]: Or]: DerivedApply[[x] =>> F[G[x]]] = nested trait Product[T[f[_]] <: Apply[f], F[_]](using inst: K1.ProductInstances[T, F]) extends Apply[F]: private lazy val F = new DerivedFunctor.Generic[T, F] {} final override def map[A, B](fa: F[A])(f: A => B): F[B] = F.map(fa)(f) final override def ap[A, B](ff: F[A => B])(fa: F[A]): F[B] = inst.map2(ff, fa)([f[_]] => (F: T[f], ff: f[A => B], fa: f[A]) => F.ap(ff)(fa)) + + object Strict: + given product[F[_]](using K1.ProductInstances[Apply, F]): DerivedApply[F] = + new Product[Apply, F] {} diff --git a/core/src/main/scala-3/cats/derived/DerivedCommutativeMonoid.scala b/core/src/main/scala-3/cats/derived/DerivedCommutativeMonoid.scala index 16be9dd9..3a994c36 100644 --- a/core/src/main/scala-3/cats/derived/DerivedCommutativeMonoid.scala +++ b/core/src/main/scala-3/cats/derived/DerivedCommutativeMonoid.scala @@ -17,10 +17,18 @@ object DerivedCommutativeMonoid: import DerivedCommutativeMonoid.given summonInline[DerivedCommutativeMonoid[A]].instance + @nowarn("msg=unused import") + inline def strict[A]: CommutativeMonoid[A] = + import Strict.given + summonInline[DerivedCommutativeMonoid[A]].instance + given [A](using inst: => K0.ProductInstances[Or, A]): DerivedCommutativeMonoid[A] = - given K0.ProductInstances[CommutativeMonoid, A] = inst.unify - new Product[CommutativeMonoid, A] {} + Strict.product(using inst.unify) trait Product[F[x] <: CommutativeMonoid[x], A](using @unused inst: K0.ProductInstances[F, A]) extends DerivedMonoid.Product[F, A], CommutativeMonoid[A] + + object Strict: + given product[A](using K0.ProductInstances[CommutativeMonoid, A]): DerivedCommutativeMonoid[A] = + new Product[CommutativeMonoid, A] {} diff --git a/core/src/main/scala-3/cats/derived/DerivedCommutativeSemigroup.scala b/core/src/main/scala-3/cats/derived/DerivedCommutativeSemigroup.scala index 6cf659d0..c5c557a1 100644 --- a/core/src/main/scala-3/cats/derived/DerivedCommutativeSemigroup.scala +++ b/core/src/main/scala-3/cats/derived/DerivedCommutativeSemigroup.scala @@ -17,10 +17,18 @@ object DerivedCommutativeSemigroup: import DerivedCommutativeSemigroup.given summonInline[DerivedCommutativeSemigroup[A]].instance + @nowarn("msg=unused import") + inline def strict[A]: CommutativeSemigroup[A] = + import Strict.given + summonInline[DerivedCommutativeSemigroup[A]].instance + given [A](using inst: => K0.ProductInstances[Or, A]): DerivedCommutativeSemigroup[A] = - given K0.ProductInstances[CommutativeSemigroup, A] = inst.unify - new Product[CommutativeSemigroup, A] {} + Strict.product(using inst.unify) trait Product[F[x] <: CommutativeSemigroup[x], A](using @unused inst: K0.ProductInstances[F, A]) extends DerivedSemigroup.Product[F, A], CommutativeSemigroup[A] + + object Strict: + given product[A](using K0.ProductInstances[CommutativeSemigroup, A]): DerivedCommutativeSemigroup[A] = + new Product[CommutativeSemigroup, A] {} diff --git a/core/src/main/scala-3/cats/derived/DerivedContravariant.scala b/core/src/main/scala-3/cats/derived/DerivedContravariant.scala index 64848d71..f902c802 100644 --- a/core/src/main/scala-3/cats/derived/DerivedContravariant.scala +++ b/core/src/main/scala-3/cats/derived/DerivedContravariant.scala @@ -21,21 +21,32 @@ object DerivedContravariant: import DerivedContravariant.given summonInline[DerivedContravariant[F]].instance + @nowarn("msg=unused import") + inline def strict[F[_]]: Contravariant[F] = + import Strict.given + summonInline[DerivedContravariant[F]].instance + given [T]: DerivedContravariant[Const[T]] = new Contravariant[Const[T]]: def contramap[A, B](fa: T)(f: B => A): T = fa given nested[F[_], G[_]](using F: DerivedFunctor.Or[F], G: => Or[G]): DerivedContravariant[[x] =>> F[G[x]]] = - new Derived.Lazy(() => F.unify.composeContravariant(G.unify)) with Contravariant[[x] =>> F[G[x]]]: + new Derived.Lazy(() => F.unify.composeContravariant(using G.unify)) with Contravariant[[x] =>> F[G[x]]]: export delegate.* given [F[_]](using inst: => K1.Instances[Or, F]): DerivedContravariant[F] = - given K1.Instances[Contravariant, F] = inst.unify - new Generic[Contravariant, F] {} + generic(using inst.unify) @deprecated("Kept for binary compatibility", "3.2.0") - private[derived] def given_DerivedContravariant_F[F[_]: DerivedFunctor.Or, G[_]: Or] - : DerivedContravariant[[x] =>> F[G[x]]] = summon + protected given [F[_]: DerivedFunctor.Or, G[_]: Or]: DerivedContravariant[[x] =>> F[G[x]]] = nested + + private def generic[F[_]](using K1.Instances[Contravariant, F]): DerivedContravariant[F] = + new Generic[Contravariant, F] {} trait Generic[T[f[_]] <: Contravariant[f], F[_]](using inst: K1.Instances[T, F]) extends Contravariant[F]: final override def contramap[A, B](fa: F[A])(f: B => A): F[B] = inst.map(fa)([f[_]] => (T: T[f], fa: f[A]) => T.contramap(fa)(f)) + + object Strict: + given product[F[_]](using K1.ProductInstances[Contravariant, F]): DerivedContravariant[F] = generic + given coproduct[F[_]](using inst: => K1.CoproductInstances[Or, F]): DerivedContravariant[F] = + generic(using inst.unify) diff --git a/core/src/main/scala-3/cats/derived/DerivedEmpty.scala b/core/src/main/scala-3/cats/derived/DerivedEmpty.scala index 02d17acb..0df77a60 100644 --- a/core/src/main/scala-3/cats/derived/DerivedEmpty.scala +++ b/core/src/main/scala-3/cats/derived/DerivedEmpty.scala @@ -19,8 +19,17 @@ object DerivedEmpty: import DerivedEmpty.given summonInline[DerivedEmpty[A]].instance - given product[A](using inst: K0.ProductInstances[Or, A]): DerivedEmpty[A] = - Empty(inst.unify.construct([a] => (_: Empty[a]).empty)) + @nowarn("msg=unused import") + inline def strict[A]: Empty[A] = + import Strict.given + summonInline[DerivedEmpty[A]].instance + + given product[A](using inst: K0.ProductInstances[Or, A]): DerivedEmpty[A] = Strict.product(using inst.unify) + inline given coproduct[A](using gen: K0.CoproductGeneric[A]): DerivedEmpty[A] = Strict.coproduct + + object Strict: + given product[A](using inst: K0.ProductInstances[Empty, A]): DerivedEmpty[A] = + Empty(inst.construct([a] => (A: Empty[a]) => A.empty)) - inline given coproduct[A](using gen: K0.CoproductGeneric[A]): DerivedEmpty[A] = - Empty(gen.withOnly[Or, A]([a <: A] => (_: Or[a]).unify.empty)) + inline given coproduct[A](using gen: K0.CoproductGeneric[A]): DerivedEmpty[A] = + Empty(gen.withOnly[Or, A]([a <: A] => (A: Or[a]) => A.unify.empty)) diff --git a/core/src/main/scala-3/cats/derived/DerivedEmptyK.scala b/core/src/main/scala-3/cats/derived/DerivedEmptyK.scala index b9ebf749..250f4962 100644 --- a/core/src/main/scala-3/cats/derived/DerivedEmptyK.scala +++ b/core/src/main/scala-3/cats/derived/DerivedEmptyK.scala @@ -23,32 +23,43 @@ object DerivedEmptyK: import DerivedEmptyK.given summonInline[DerivedEmptyK[F]].instance + @nowarn("msg=unused import") + inline def strict[F[_]]: EmptyK[F] = + import Strict.given + summonInline[DerivedEmptyK[F]].instance + given [T](using T: Empty[T]): DerivedEmptyK[Const[T]] = new EmptyK[Const[T]]: def empty[A]: T = T.empty - given nested[F[_], G[_]](using F: => Or[F]): DerivedEmptyK[[x] =>> F[G[x]]] = new EmptyK[[x] =>> F[G[x]]]: - lazy val f = F.unify - def empty[A]: F[G[A]] = f.empty + given nested[F[_], G[_]](using F: => Or[F]): DerivedEmptyK[[x] =>> F[G[x]]] = + new EmptyK[[x] =>> F[G[x]]]: + lazy val f = F.unify + def empty[A]: F[G[A]] = f.empty - given nested[F[_], G[_]](using NotGiven[Or[F]])(using - F: DerivedPure.Or[F], - G: => Or[G] - ): DerivedEmptyK[[x] =>> F[G[x]]] = new EmptyK[[x] =>> F[G[x]]]: - val f = F.unify - lazy val g = G.unify - def empty[A]: F[G[A]] = f.pure(g.empty) + given nested[F[_], G[_]](using + NotGiven[Or[F]] + )(using F: DerivedPure.Or[F], G: => Or[G]): DerivedEmptyK[[x] =>> F[G[x]]] = + new EmptyK[[x] =>> F[G[x]]]: + val f = F.unify + lazy val g = G.unify + def empty[A]: F[G[A]] = f.pure(g.empty) - given product[F[_]](using inst: K1.ProductInstances[Or, F]): DerivedEmptyK[F] = new EmptyK[F]: - val f = inst.unify - def empty[A]: F[A] = f.construct([f[_]] => (F: EmptyK[f]) => F.empty[A]) - - inline given coproduct[F[_]](using gen: K1.CoproductGeneric[F]): DerivedEmptyK[F] = - gen.withOnly[Or, EmptyK[F]]([f[x] <: F[x]] => (F: Or[f]) => F.unify.asInstanceOf[EmptyK[F]]) + given product[F[_]](using inst: K1.ProductInstances[Or, F]): DerivedEmptyK[F] = Strict.product(using inst.unify) + inline given coproduct[F[_]](using K1.CoproductGeneric[F]): DerivedEmptyK[F] = Strict.coproduct @deprecated("Kept for binary compatibility", "3.2.0") - private[derived] def given_DerivedEmptyK_F[F[_]: Or, G[_]]: DerivedEmptyK[[x] =>> F[G[x]]] = summon + protected given [F[_], G[_]](using F: Or[F]): DerivedEmptyK[[x] =>> F[G[x]]] = + nested(using F) @deprecated("Kept for binary compatibility", "3.2.0") - private[derived] def given_DerivedEmptyK_F[F[_]: DerivedPure.Or, G[_]: Or]( + protected given [F[_], G[_]](using ev: NotGiven[Or[F]] - ): DerivedEmptyK[[x] =>> F[G[x]]] = nested(using ev) + )(using DerivedPure.Or[F], Or[G]): DerivedEmptyK[[x] =>> F[G[x]]] = + nested(using ev) + + object Strict: + given product[F[_]](using inst: K1.ProductInstances[EmptyK, F]): DerivedEmptyK[F] = new EmptyK[F]: + def empty[A]: F[A] = inst.construct([f[_]] => (F: EmptyK[f]) => F.empty[A]) + + inline given coproduct[F[_]](using gen: K1.CoproductGeneric[F]): DerivedEmptyK[F] = + gen.withOnly[Or, EmptyK[F]]([f[x] <: F[x]] => (F: Or[f]) => F.unify.asInstanceOf[EmptyK[F]]) diff --git a/core/src/main/scala-3/cats/derived/DerivedEq.scala b/core/src/main/scala-3/cats/derived/DerivedEq.scala index 49f2d326..a24757ff 100644 --- a/core/src/main/scala-3/cats/derived/DerivedEq.scala +++ b/core/src/main/scala-3/cats/derived/DerivedEq.scala @@ -19,12 +19,16 @@ object DerivedEq: import DerivedEq.given summonInline[DerivedEq[A]].instance + @nowarn("msg=unused import") + inline def strict[A]: Eq[A] = + import Strict.given + summonInline[DerivedEq[A]].instance + given singleton[A <: Singleton: ValueOf]: DerivedEq[A] = Eq.allEqual given product[A](using inst: => K0.ProductInstances[Or, A]): DerivedEq[A] = - given K0.ProductInstances[Eq, A] = inst.unify - new Product[Eq, A] {} + Strict.product(using inst.unify) given coproduct[A](using inst: => K0.CoproductInstances[Or, A]): DerivedEq[A] = given K0.CoproductInstances[Eq, A] = inst.unify @@ -37,3 +41,8 @@ object DerivedEq: trait Coproduct[F[x] <: Eq[x], A](using inst: K0.CoproductInstances[F, A]) extends Eq[A]: final override def eqv(x: A, y: A): Boolean = inst.fold2(x, y)(false): [t] => (eqt: F[t], x: t, y: t) => eqt.eqv(x, y) + + object Strict: + export DerivedEq.coproduct + given product[A](using K0.ProductInstances[Eq, A]): DerivedEq[A] = + new Product[Eq, A] {} diff --git a/core/src/main/scala-3/cats/derived/DerivedFoldable.scala b/core/src/main/scala-3/cats/derived/DerivedFoldable.scala index ec7da966..cfc59e66 100644 --- a/core/src/main/scala-3/cats/derived/DerivedFoldable.scala +++ b/core/src/main/scala-3/cats/derived/DerivedFoldable.scala @@ -21,24 +21,24 @@ object DerivedFoldable: import DerivedFoldable.given summonInline[DerivedFoldable[F]].instance + @nowarn("msg=unused import") + inline def strict[F[_]]: Foldable[F] = + import Strict.given + summonInline[DerivedFoldable[F]].instance + given [T]: DerivedFoldable[Const[T]] = new Foldable[Const[T]]: def foldLeft[A, B](fa: T, b: B)(f: (B, A) => B): B = b def foldRight[A, B](fa: T, lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = lb given nested[F[_], G[_]](using F: => Or[F], G: => Or[G]): DerivedFoldable[[x] =>> F[G[x]]] = - new Derived.Lazy(() => F.unify.compose(G.unify)) with Foldable[[x] =>> F[G[x]]]: + new Derived.Lazy(() => F.unify.compose(using G.unify)) with Foldable[[x] =>> F[G[x]]]: export delegate.* - given [F[_]](using inst: K1.ProductInstances[Or, F]): DerivedFoldable[F] = - given K1.ProductInstances[Foldable, F] = inst.unify - new Product[Foldable, F] {} - - given [F[_]](using inst: => K1.CoproductInstances[Or, F]): DerivedFoldable[F] = - given K1.CoproductInstances[Foldable, F] = inst.unify - new Coproduct[Foldable, F] {} + given [F[_]](using inst: K1.ProductInstances[Or, F]): DerivedFoldable[F] = Strict.product(using inst.unify) + given [F[_]](using => K1.CoproductInstances[Or, F]): DerivedFoldable[F] = Strict.coproduct @deprecated("Kept for binary compatibility", "3.2.0") - private[derived] def given_DerivedFoldable_F[F[_]: Or, G[_]: Or]: DerivedFoldable[[x] =>> F[G[x]]] = summon + protected given [F[_]: Or, G[_]: Or]: DerivedFoldable[[x] =>> F[G[x]]] = nested trait Product[T[f[_]] <: Foldable[f], F[_]](using inst: K1.ProductInstances[T, F]) extends Foldable[F]: final override def foldLeft[A, B](fa: F[A], b: B)(f: (B, A) => B): B = @@ -54,3 +54,11 @@ object DerivedFoldable: final override def foldRight[A, B](fa: F[A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = inst.fold(fa)([f[_]] => (F: T[f], fa: f[A]) => Eval.defer(F.foldRight(fa, lb)(f))) + + object Strict: + given product[F[_]](using K1.ProductInstances[Foldable, F]): DerivedFoldable[F] = + new Product[Foldable, F] {} + + given coproduct[F[_]](using inst: => K1.CoproductInstances[Or, F]): DerivedFoldable[F] = + given K1.CoproductInstances[Foldable, F] = inst.unify + new Coproduct[Foldable, F] {} diff --git a/core/src/main/scala-3/cats/derived/DerivedFunctor.scala b/core/src/main/scala-3/cats/derived/DerivedFunctor.scala index 58430b85..4d7e1e62 100644 --- a/core/src/main/scala-3/cats/derived/DerivedFunctor.scala +++ b/core/src/main/scala-3/cats/derived/DerivedFunctor.scala @@ -22,33 +22,45 @@ object DerivedFunctor: import DerivedFunctor.given summonInline[DerivedFunctor[F]].instance + @nowarn("msg=unused import") + inline def strict[F[_]]: Functor[F] = + import Strict.given + summonInline[DerivedFunctor[F]].instance + given [T]: DerivedFunctor[Const[T]] = new Functor[Const[T]]: def map[A, B](fa: T)(f: A => B): T = fa given nested[F[_], G[_]](using F: => Or[F], G: => Or[G]): DerivedFunctor[[x] =>> F[G[x]]] = - new Derived.Lazy(() => F.unify.compose(G.unify)) with Functor[[x] =>> F[G[x]]]: + new Derived.Lazy(() => F.unify.compose(using G.unify)) with Functor[[x] =>> F[G[x]]]: export delegate.* given nested[F[_], G[_]](using F: DerivedContravariant.Or[F], G: DerivedContravariant.Or[G] ): DerivedFunctor[[x] =>> F[G[x]]] = - F.unify.compose(G.unify) + F.unify.compose(using G.unify) given [F[_]](using inst: => K1.Instances[Or, F]): DerivedFunctor[F] = - given K1.Instances[Functor, F] = inst.unify - new Generic[Functor, F] {} + generic(using inst.unify) @deprecated("Kept for binary compatibility", "3.2.0") - private[derived] def given_DerivedFunctor_F[F[_], G[_]](using F: Or[F], G: Or[G]): DerivedFunctor[[x] =>> F[G[x]]] = + protected given [F[_], G[_]](using F: Or[F], G: Or[G]): DerivedFunctor[[x] =>> F[G[x]]] = nested(using F, G) @deprecated("Kept for binary compatibility", "3.2.0") - private[derived] def given_DerivedFunctor_F[F[_], G[_]](using + protected given [F[_], G[_]](using F: DerivedContravariant.Or[F], G: DerivedContravariant.Or[G] - ): DerivedFunctor[[x] =>> F[G[x]]] = nested(using F, G) + ): DerivedFunctor[[x] =>> F[G[x]]] = + nested(using F, G) + + private def generic[F[_]](using K1.Instances[Functor, F]): DerivedFunctor[F] = + new Generic[Functor, F] {} trait Generic[T[f[_]] <: Functor[f], F[_]](using inst: K1.Instances[T, F]) extends Functor[F]: final override def map[A, B](fa: F[A])(f: A => B): F[B] = inst.map(fa)([f[_]] => (F: T[f], fa: f[A]) => F.map(fa)(f)) + + object Strict: + given product[F[_]](using K1.ProductInstances[Functor, F]): DerivedFunctor[F] = generic + given coproduct[F[_]](using inst: => K1.CoproductInstances[Or, F]): DerivedFunctor[F] = generic(using inst.unify) diff --git a/core/src/main/scala-3/cats/derived/DerivedHash.scala b/core/src/main/scala-3/cats/derived/DerivedHash.scala index 8a4b11ed..87f4d542 100644 --- a/core/src/main/scala-3/cats/derived/DerivedHash.scala +++ b/core/src/main/scala-3/cats/derived/DerivedHash.scala @@ -20,6 +20,11 @@ object DerivedHash: import DerivedHash.given summonInline[DerivedHash[A]].instance + @nowarn("msg=unused import") + inline def strict[A]: Hash[A] = + import Strict.given + summonInline[DerivedHash[A]].instance + // These instances support singleton types unlike the instances in Cats' kernel. given boolean[A <: Boolean]: DerivedHash[A] = Hash.fromUniversalHashCode given byte[A <: Byte]: DerivedHash[A] = Hash.fromUniversalHashCode @@ -33,8 +38,7 @@ object DerivedHash: given symbol[A <: Symbol]: DerivedHash[A] = Hash.fromUniversalHashCode given product[A <: scala.Product](using inst: => K0.ProductInstances[Or, A]): DerivedHash[A] = - given K0.ProductInstances[Hash, A] = inst.unify - new Product[Hash, A] {} + Strict.product(using inst.unify) given coproduct[A](using inst: => K0.CoproductInstances[Or, A]): DerivedHash[A] = given K0.CoproductInstances[Hash, A] = inst.unify @@ -59,3 +63,8 @@ object DerivedHash: final override def hash(x: A): Int = inst.fold[Int](x)([t] => (h: F[t], x: t) => h.hash(x)) + + object Strict: + export DerivedHash.coproduct + given product[A <: scala.Product](using K0.ProductInstances[Hash, A]): DerivedHash[A] = + new Product[Hash, A] {} diff --git a/core/src/main/scala-3/cats/derived/DerivedInvariant.scala b/core/src/main/scala-3/cats/derived/DerivedInvariant.scala index 21126878..9d496251 100644 --- a/core/src/main/scala-3/cats/derived/DerivedInvariant.scala +++ b/core/src/main/scala-3/cats/derived/DerivedInvariant.scala @@ -21,20 +21,31 @@ object DerivedInvariant: import DerivedInvariant.given summonInline[DerivedInvariant[F]].instance + @nowarn("msg=unused import") + inline def strict[F[_]]: Invariant[F] = + import Strict.given + summonInline[DerivedInvariant[F]].instance + given [T]: DerivedInvariant[Const[T]] = new Invariant[Const[T]]: def imap[A, B](fa: T)(f: A => B)(g: B => A): T = fa given nested[F[_], G[_]](using F: => Or[F], G: => Or[G]): DerivedInvariant[[x] =>> F[G[x]]] = - new Derived.Lazy(() => F.unify.compose(G.unify)) with Invariant[[x] =>> F[G[x]]]: + new Derived.Lazy(() => F.unify.compose(using G.unify)) with Invariant[[x] =>> F[G[x]]]: export delegate.* given [F[_]](using inst: => K1.Instances[Or, F]): DerivedInvariant[F] = - given K1.Instances[Invariant, F] = inst.unify - new Generic[Invariant, F] {} + generic(using inst.unify) @deprecated("Kept for binary compatibility", "3.2.0") - private[derived] def given_DerivedInvariant_F[F[_]: Or, G[_]: Or]: DerivedInvariant[[x] =>> F[G[x]]] = summon + protected given [F[_]: Or, G[_]: Or]: DerivedInvariant[[x] =>> F[G[x]]] = nested + + private def generic[F[_]](using K1.Instances[Invariant, F]): DerivedInvariant[F] = + new Generic[Invariant, F] {} trait Generic[T[f[_]] <: Invariant[f], F[_]](using inst: K1.Instances[T, F]) extends Invariant[F]: final override def imap[A, B](fa: F[A])(f: A => B)(g: B => A): F[B] = inst.map(fa)([f[_]] => (F: T[f], fa: f[A]) => F.imap(fa)(f)(g)) + + object Strict: + given product[F[_]](using K1.ProductInstances[Invariant, F]): DerivedInvariant[F] = generic + given coproduct[F[_]](using inst: => K1.CoproductInstances[Or, F]): DerivedInvariant[F] = generic(using inst.unify) diff --git a/core/src/main/scala-3/cats/derived/DerivedMonoid.scala b/core/src/main/scala-3/cats/derived/DerivedMonoid.scala index 48daf661..d16ecc0c 100644 --- a/core/src/main/scala-3/cats/derived/DerivedMonoid.scala +++ b/core/src/main/scala-3/cats/derived/DerivedMonoid.scala @@ -17,12 +17,20 @@ object DerivedMonoid: import DerivedMonoid.given summonInline[DerivedMonoid[A]].instance + @nowarn("msg=unused import") + inline def strict[A]: Monoid[A] = + import Strict.given + summonInline[DerivedMonoid[A]].instance + given [A](using inst: => K0.ProductInstances[Or, A]): DerivedMonoid[A] = - given K0.ProductInstances[Monoid, A] = inst.unify - new Product[Monoid, A] {} + Strict.product(using inst.unify) trait Product[F[x] <: Monoid[x], A](using inst: K0.ProductInstances[F, A]) extends DerivedSemigroup.Product[F, A], Monoid[A]: final override lazy val empty: A = inst.construct([A] => (F: F[A]) => F.empty) + + object Strict: + given product[A](using K0.ProductInstances[Monoid, A]): DerivedMonoid[A] = + new Product[Monoid, A] {} diff --git a/core/src/main/scala-3/cats/derived/DerivedMonoidK.scala b/core/src/main/scala-3/cats/derived/DerivedMonoidK.scala index 389378a9..4c68cf85 100644 --- a/core/src/main/scala-3/cats/derived/DerivedMonoidK.scala +++ b/core/src/main/scala-3/cats/derived/DerivedMonoidK.scala @@ -1,6 +1,6 @@ package cats.derived -import cats.* +import cats.{Monoid, MonoidK} import shapeless3.deriving.{Const, K1} import scala.annotation.* @@ -22,6 +22,11 @@ object DerivedMonoidK: import DerivedMonoidK.given summonInline[DerivedMonoidK[F]].instance + @nowarn("msg=unused import") + inline def strict[F[_]]: MonoidK[F] = + import Strict.given + summonInline[DerivedMonoidK[F]].instance + given [T](using T: Monoid[T]): DerivedMonoidK[Const[T]] = new MonoidK[Const[T]]: def empty[A]: T = T.empty def combineK[A](x: T, y: T): T = T.combine(x, y) @@ -30,28 +35,35 @@ object DerivedMonoidK: new Derived.Lazy(() => F.unify.compose[G]) with MonoidK[[x] =>> F[G[x]]]: export delegate.* - given nested[F[_], G[_]](using NotGiven[Or[F]])(using - F: DerivedApplicative.Or[F], - G: => Or[G] - ): DerivedMonoidK[[x] =>> F[G[x]]] = new MonoidK[[x] =>> F[G[x]]]: - val f: Applicative[F] = F.unify - lazy val g: MonoidK[G] = G.unify - def empty[A]: F[G[A]] = f.pure(g.empty[A]) - def combineK[A](x: F[G[A]], y: F[G[A]]): F[G[A]] = f.map2(x, y)(g.combineK) + given nested[F[_], G[_]](using + NotGiven[Or[F]] + )(using F: DerivedApplicative.Or[F], G: => Or[G]): DerivedMonoidK[[x] =>> F[G[x]]] = + new MonoidK[[x] =>> F[G[x]]]: + val f = F.unify + lazy val g = G.unify + def empty[A]: F[G[A]] = f.pure(g.empty[A]) + 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] {} + Strict.product(using inst.unify) @deprecated("Kept for binary compatibility", "3.2.0") - private[derived] def given_DerivedMonoidK_F[F[_]: Or, G[_]]: DerivedMonoidK[[x] =>> F[G[x]]] = summon + protected given [F[_], G[_]](using F: Or[F]): DerivedMonoidK[[x] =>> F[G[x]]] = + nested(using F) @deprecated("Kept for binary compatibility", "3.2.0") - private[derived] def given_DerivedMonoidK_F[F[_]: DerivedApplicative.Or, G[_]: Or]( + protected given [F[_], G[_]](using ev: NotGiven[Or[F]] - ): DerivedMonoidK[[x] =>> F[G[x]]] = nested(using ev) + )(using F: DerivedApplicative.Or[F], G: Or[G]): DerivedMonoidK[[x] =>> F[G[x]]] = + nested(using ev) trait Product[T[f[_]] <: MonoidK[f], F[_]](using inst: K1.ProductInstances[T, F]) extends MonoidK[F], DerivedSemigroupK.Product[T, F]: - final override def empty[A]: F[A] = inst.construct([f[_]] => (F: T[f]) => F.empty[A]) + + final override def empty[A]: F[A] = + inst.construct([f[_]] => (F: T[f]) => F.empty[A]) + + object Strict: + given product[F[_]](using K1.ProductInstances[MonoidK, F]): DerivedMonoidK[F] = + new Product[MonoidK, F] {} diff --git a/core/src/main/scala-3/cats/derived/DerivedNonEmptyTraverse.scala b/core/src/main/scala-3/cats/derived/DerivedNonEmptyTraverse.scala index 56fad294..9d262552 100644 --- a/core/src/main/scala-3/cats/derived/DerivedNonEmptyTraverse.scala +++ b/core/src/main/scala-3/cats/derived/DerivedNonEmptyTraverse.scala @@ -21,32 +21,29 @@ object DerivedNonEmptyTraverse: import DerivedNonEmptyTraverse.given summonInline[DerivedNonEmptyTraverse[F]].instance + @nowarn("msg=unused import") + inline def strict[F[_]]: NonEmptyTraverse[F] = + import DerivedTraverse.Strict.given + import DerivedNonEmptyTraverse.Strict.given + summonInline[DerivedNonEmptyTraverse[F]].instance + given nested[F[_], G[_]](using F: => Or[F], G: => Or[G]): DerivedNonEmptyTraverse[[x] =>> F[G[x]]] = - new Derived.Lazy(() => F.unify.compose(G.unify)) with NonEmptyTraverse[[x] =>> F[G[x]]]: + new Derived.Lazy(() => F.unify.compose(using G.unify)) with NonEmptyTraverse[[x] =>> F[G[x]]]: export delegate.* def product[F[_]](ev: NonEmptyTraverse[?])(using inst: K1.ProductInstances[DerivedTraverse.Or, F] ): DerivedNonEmptyTraverse[F] = - given K1.ProductInstances[Traverse, F] = inst.unify - new Product[Traverse, F](ev) - with DerivedReducible.Product[Traverse, F](ev) - with DerivedTraverse.Product[Traverse, F] - with DerivedFunctor.Generic[Traverse, F] {} + Strict.product(ev)(using inst.unify) - inline given [F[_]](using gen: K1.ProductGeneric[F]): DerivedNonEmptyTraverse[F] = + inline given product[F[_]](using gen: K1.ProductGeneric[F]): DerivedNonEmptyTraverse[F] = product(K1.summonFirst[Or, gen.MirroredElemTypes].unify) - given [F[_]](using inst: => K1.CoproductInstances[Or, F]): DerivedNonEmptyTraverse[F] = - given K1.CoproductInstances[NonEmptyTraverse, F] = inst.unify - new Coproduct[NonEmptyTraverse, F] - with DerivedReducible.Coproduct[NonEmptyTraverse, F] - with DerivedTraverse.Coproduct[NonEmptyTraverse, F] - with DerivedFunctor.Generic[NonEmptyTraverse, F] {} + given [F[_]](using => K1.CoproductInstances[Or, F]): DerivedNonEmptyTraverse[F] = + Strict.coproduct @deprecated("Kept for binary compatibility", "3.2.0") - private[derived] def given_DerivedNonEmptyTraverse_F[F[_]: Or, G[_]: Or]: DerivedNonEmptyTraverse[[x] =>> F[G[x]]] = - summon + protected given [F[_]: Or, G[_]: Or]: DerivedNonEmptyTraverse[[x] =>> F[G[x]]] = nested trait Product[T[x[_]] <: Traverse[x], F[_]](@unused ev: NonEmptyTraverse[?])(using @unused inst: K1.ProductInstances[T, F] @@ -79,3 +76,20 @@ object DerivedNonEmptyTraverse: case (Left(ff), Right(a)) => Left(F.map(ff)(_(a))) case (Right(f), Left(fa)) => Left(F.map(fa)(f)) case (Right(f), Right(a)) => Right(f(a)) + + object Strict: + def product[F[_]](ev: NonEmptyTraverse[?])(using K1.ProductInstances[Traverse, F]): DerivedNonEmptyTraverse[F] = + new Product[Traverse, F](ev) + with DerivedReducible.Product[Traverse, F](ev) + with DerivedTraverse.Product[Traverse, F] + with DerivedFunctor.Generic[Traverse, F] {} + + inline given product[F[_]](using gen: K1.ProductGeneric[F]): DerivedNonEmptyTraverse[F] = + product(K1.summonFirst[NonEmptyTraverse, gen.MirroredElemTypes]) + + given coproduct[F[_]](using inst: => K1.CoproductInstances[Or, F]): DerivedNonEmptyTraverse[F] = + given K1.CoproductInstances[NonEmptyTraverse, F] = inst.unify + new Coproduct[NonEmptyTraverse, F] + with DerivedReducible.Coproduct[NonEmptyTraverse, F] + with DerivedTraverse.Coproduct[NonEmptyTraverse, F] + with DerivedFunctor.Generic[NonEmptyTraverse, F] {} diff --git a/core/src/main/scala-3/cats/derived/DerivedOrder.scala b/core/src/main/scala-3/cats/derived/DerivedOrder.scala index a3997dab..3eb6a575 100644 --- a/core/src/main/scala-3/cats/derived/DerivedOrder.scala +++ b/core/src/main/scala-3/cats/derived/DerivedOrder.scala @@ -19,12 +19,16 @@ object DerivedOrder: import DerivedOrder.given summonInline[DerivedOrder[A]].instance + @nowarn("msg=unused import") + inline def strict[A]: Order[A] = + import Strict.given + summonInline[DerivedOrder[A]].instance + given singleton[A <: Singleton: ValueOf]: DerivedOrder[A] = Order.allEqual given product[A](using inst: => K0.ProductInstances[Or, A]): DerivedOrder[A] = - given K0.ProductInstances[Order, A] = inst.unify - new Product[Order, A] {} + Strict.product(using inst.unify) given coproduct[A](using inst: => K0.CoproductInstances[Or, A]): DerivedOrder[A] = given K0.CoproductInstances[Order, A] = inst.unify @@ -42,3 +46,8 @@ object DerivedOrder: def compare(x: A, y: A): Int = inst.fold2(x, y)((x: Int, y: Int) => x - y): [t] => (ord: T[t], t0: t, t1: t) => ord.compare(t0, t1) + + object Strict: + export DerivedOrder.coproduct + given product[A](using K0.ProductInstances[Order, A]): DerivedOrder[A] = + new Product[Order, A] {} diff --git a/core/src/main/scala-3/cats/derived/DerivedPartialOrder.scala b/core/src/main/scala-3/cats/derived/DerivedPartialOrder.scala index a4d655ec..da0dfe9e 100644 --- a/core/src/main/scala-3/cats/derived/DerivedPartialOrder.scala +++ b/core/src/main/scala-3/cats/derived/DerivedPartialOrder.scala @@ -19,12 +19,16 @@ object DerivedPartialOrder: import DerivedPartialOrder.given summonInline[DerivedPartialOrder[A]].instance + @nowarn("msg=unused import") + inline def strict[A]: PartialOrder[A] = + import Strict.given + summonInline[DerivedPartialOrder[A]].instance + given singleton[A <: Singleton: ValueOf]: DerivedPartialOrder[A] = Order.allEqual given product[A](using inst: => K0.ProductInstances[Or, A]): DerivedPartialOrder[A] = - given K0.ProductInstances[PartialOrder, A] = inst.unify - new Product[PartialOrder, A] {} + Strict.product(using inst.unify) given coproduct[A](using inst: => K0.CoproductInstances[Or, A]): DerivedPartialOrder[A] = given K0.CoproductInstances[PartialOrder, A] = inst.unify @@ -42,3 +46,8 @@ object DerivedPartialOrder: def partialCompare(x: A, y: A): Double = inst.fold2(x, y)(Double.NaN: Double): [t] => (ord: T[t], t0: t, t1: t) => ord.partialCompare(t0, t1) + + object Strict: + export DerivedPartialOrder.coproduct + given product[A](using K0.ProductInstances[PartialOrder, A]): DerivedPartialOrder[A] = + new Product[PartialOrder, A] {} diff --git a/core/src/main/scala-3/cats/derived/DerivedPure.scala b/core/src/main/scala-3/cats/derived/DerivedPure.scala index cb519f75..38e9e574 100644 --- a/core/src/main/scala-3/cats/derived/DerivedPure.scala +++ b/core/src/main/scala-3/cats/derived/DerivedPure.scala @@ -20,20 +20,29 @@ object DerivedPure: import DerivedPure.given summonInline[DerivedPure[F]].instance + @nowarn("msg=unused import") + inline def strict[F[_]]: Pure[F] = + import Strict.given + summonInline[DerivedPure[F]].instance + given [T](using T: Empty[T]): DerivedPure[Const[T]] = new Pure[Const[T]]: def pure[A](a: A): T = T.empty given [T <: Singleton: ValueOf]: DerivedPure[Const[T]] = new Pure[Const[T]]: def pure[A](a: A): T = valueOf[T] - given nested[F[_], G[_]](using F: => Or[F], G: => Or[G]): DerivedPure[[x] =>> F[G[x]]] = new Pure[[x] =>> F[G[x]]]: - lazy val f = F.unify - lazy val g = G.unify - def pure[A](a: A): F[G[A]] = f.pure(g.pure(a)) + given nested[F[_], G[_]](using F: => Or[F], G: => Or[G]): DerivedPure[[x] =>> F[G[x]]] = + new Pure[[x] =>> F[G[x]]]: + lazy val f = F.unify + lazy val g = G.unify + def pure[A](a: A): F[G[A]] = f.pure(g.pure(a)) - given [F[_]](using inst: K1.ProductInstances[Or, F]): DerivedPure[F] = new Pure[F]: - val f = inst.unify - def pure[A](a: A): F[A] = f.construct([f[_]] => (F: Pure[f]) => F.pure(a)) + given [F[_]](using inst: K1.ProductInstances[Or, F]): DerivedPure[F] = + Strict.product(using inst.unify) @deprecated("Kept for binary compatibility", "3.2.0") - private[derived] def given_DerivedPure_F[F[_]: Or, G[_]: Or]: DerivedPure[[x] =>> F[G[x]]] = summon + protected given [F[_]: Or, G[_]: Or]: DerivedPure[[x] =>> F[G[x]]] = nested + + object Strict: + given product[F[_]](using inst: K1.ProductInstances[Pure, F]): DerivedPure[F] = new Pure[F]: + def pure[A](a: A): F[A] = inst.construct([f[_]] => (F: Pure[f]) => F.pure(a)) diff --git a/core/src/main/scala-3/cats/derived/DerivedReducible.scala b/core/src/main/scala-3/cats/derived/DerivedReducible.scala index 0d55107f..57dddd0d 100644 --- a/core/src/main/scala-3/cats/derived/DerivedReducible.scala +++ b/core/src/main/scala-3/cats/derived/DerivedReducible.scala @@ -21,23 +21,27 @@ object DerivedReducible: import DerivedReducible.given summonInline[DerivedReducible[F]].instance + @nowarn("msg=unused import") + inline def strict[F[_]]: Reducible[F] = + import DerivedFoldable.Strict.given + import DerivedReducible.Strict.given + summonInline[DerivedReducible[F]].instance + given nested[F[_], G[_]](using F: => Or[F], G: => Or[G]): DerivedReducible[[x] =>> F[G[x]]] = - new Derived.Lazy(() => F.unify.compose(G.unify)) with Reducible[[x] =>> F[G[x]]]: + new Derived.Lazy(() => F.unify.compose(using G.unify)) with Reducible[[x] =>> F[G[x]]]: export delegate.* def product[F[_]](ev: Reducible[?])(using inst: K1.ProductInstances[DerivedFoldable.Or, F]): DerivedReducible[F] = - given K1.ProductInstances[Foldable, F] = inst.unify - new Product[Foldable, F](ev) {} + Strict.product(ev)(using inst.unify) - inline given [F[_]](using gen: K1.ProductGeneric[F]): DerivedReducible[F] = + inline given product[F[_]](using gen: K1.ProductGeneric[F]): DerivedReducible[F] = product(K1.summonFirst[Or, gen.MirroredElemTypes].unify) - given [F[_]](using inst: => K1.CoproductInstances[Or, F]): DerivedReducible[F] = - given K1.CoproductInstances[Reducible, F] = inst.unify - new Coproduct[Reducible, F] {} + given [F[_]](using => K1.CoproductInstances[Or, F]): DerivedReducible[F] = + Strict.coproduct @deprecated("Kept for binary compatibility", "3.2.0") - private[derived] def given_DerivedReducible_F[F[_]: Or, G[_]: Or]: DerivedReducible[[x] =>> F[G[x]]] = summon + protected given [F[_]: Or, G[_]: Or]: DerivedReducible[[x] =>> F[G[x]]] = nested trait Product[T[f[_]] <: Foldable[f], F[_]](@unused ev: Reducible[?])(using inst: K1.ProductInstances[T, F]) extends DerivedFoldable.Product[T, F], @@ -75,3 +79,14 @@ object DerivedReducible: final override def reduceRightTo[A, B](fa: F[A])(f: A => B)(g: (A, Eval[B]) => Eval[B]): Eval[B] = inst.fold(fa)([f[_]] => (F: T[f], fa: f[A]) => Eval.defer(F.reduceRightTo(fa)(f)(g))) + + object Strict: + def product[F[_]](ev: Reducible[?])(using K1.ProductInstances[Foldable, F]): DerivedReducible[F] = + new Product[Foldable, F](ev) {} + + inline given product[F[_]](using gen: K1.ProductGeneric[F]): DerivedReducible[F] = + product(K1.summonFirst[Reducible, gen.MirroredElemTypes]) + + given coproduct[F[_]](using inst: => K1.CoproductInstances[Or, F]): DerivedReducible[F] = + given K1.CoproductInstances[Reducible, F] = inst.unify + new Coproduct[Reducible, F] {} diff --git a/core/src/main/scala-3/cats/derived/DerivedSemigroup.scala b/core/src/main/scala-3/cats/derived/DerivedSemigroup.scala index 1ec45e87..df047582 100644 --- a/core/src/main/scala-3/cats/derived/DerivedSemigroup.scala +++ b/core/src/main/scala-3/cats/derived/DerivedSemigroup.scala @@ -17,10 +17,18 @@ object DerivedSemigroup: import DerivedSemigroup.given summonInline[DerivedSemigroup[A]].instance + @nowarn("msg=unused import") + inline def strict[A]: Semigroup[A] = + import Strict.given + summonInline[DerivedSemigroup[A]].instance + given [A](using inst: => K0.ProductInstances[Or, A]): DerivedSemigroup[A] = - given K0.ProductInstances[Semigroup, A] = inst.unify - new Product[Semigroup, A] {} + Strict.product(using inst.unify) trait Product[F[x] <: Semigroup[x], A](using inst: K0.ProductInstances[F, A]) extends Semigroup[A]: final override def combine(x: A, y: A): A = - inst.map2(x, y)([A] => (F: F[A], x: A, y: A) => F.combine(x, y)) + inst.map2(x, y)([a] => (F: F[a], x: a, y: a) => F.combine(x, y)) + + object Strict: + given product[A](using K0.ProductInstances[Semigroup, A]): DerivedSemigroup[A] = + new Product[Semigroup, A] {} diff --git a/core/src/main/scala-3/cats/derived/DerivedSemigroupK.scala b/core/src/main/scala-3/cats/derived/DerivedSemigroupK.scala index 6abbb6e9..158ca454 100644 --- a/core/src/main/scala-3/cats/derived/DerivedSemigroupK.scala +++ b/core/src/main/scala-3/cats/derived/DerivedSemigroupK.scala @@ -22,6 +22,11 @@ object DerivedSemigroupK: import DerivedSemigroupK.given summonInline[DerivedSemigroupK[F]].instance + @nowarn("msg=unused import") + inline def strict[F[_]]: SemigroupK[F] = + import Strict.given + summonInline[DerivedSemigroupK[F]].instance + given [T](using T: Semigroup[T]): DerivedSemigroupK[Const[T]] = new SemigroupK[Const[T]]: def combineK[A](x: T, y: T): T = T.combine(x, y) @@ -29,26 +34,31 @@ object DerivedSemigroupK: new Derived.Lazy(() => F.unify.compose[G]) with SemigroupK[[x] =>> F[G[x]]]: export delegate.* - given nested[F[_], G[_]](using NotGiven[Or[F]])(using - F: DerivedApply.Or[F], - G: => Or[G] - ): DerivedSemigroupK[[x] =>> F[G[x]]] = new SemigroupK[[x] =>> F[G[x]]]: - val f = F.unify - lazy val g = G.unify - def combineK[A](x: F[G[A]], y: F[G[A]]): F[G[A]] = f.map2(x, y)(g.combineK) + given nested[F[_], G[_]](using + NotGiven[Or[F]] + )(using F: DerivedApply.Or[F], G: => Or[G]): DerivedSemigroupK[[x] =>> F[G[x]]] = + new SemigroupK[[x] =>> F[G[x]]]: + val f = F.unify + lazy val g = G.unify + 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]): DerivedSemigroupK[F] = - given K1.ProductInstances[SemigroupK, F] = inst.unify - new Product[SemigroupK, F] {} + Strict.product(using inst.unify) @deprecated("Kept for binary compatibility", "3.2.0") - private[derived] def given_DerivedSemigroupK_F[F[_]: Or, G[_]]: DerivedSemigroupK[[x] =>> F[G[x]]] = summon + protected given [F[_], G[_]](using F: Or[F]): DerivedSemigroupK[[x] =>> F[G[x]]] = + nested(using F) @deprecated("Kept for binary compatibility", "3.2.0") - private[derived] def given_DerivedSemigroupK_F[F[_]: DerivedApply.Or, G[_]: Or]( + protected given [F[_], G[_]](using ev: NotGiven[Or[F]] - ): DerivedSemigroupK[[x] =>> F[G[x]]] = nested(using ev) + )(using F: DerivedApply.Or[F], G: Or[G]): DerivedSemigroupK[[x] =>> F[G[x]]] = + nested(using ev) trait Product[T[f[_]] <: SemigroupK[f], 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(x, y)([f[_]] => (F: T[f], x: f[A], y: f[A]) => F.combineK(x, y)) + + object Strict: + given product[F[_]](using K1.ProductInstances[SemigroupK, F]): DerivedSemigroupK[F] = + new Product[SemigroupK, F] {} diff --git a/core/src/main/scala-3/cats/derived/DerivedShow.scala b/core/src/main/scala-3/cats/derived/DerivedShow.scala index e030a6c6..7386a776 100644 --- a/core/src/main/scala-3/cats/derived/DerivedShow.scala +++ b/core/src/main/scala-3/cats/derived/DerivedShow.scala @@ -19,6 +19,11 @@ object DerivedShow: import DerivedShow.given summonInline[DerivedShow[A]].instance + @nowarn("msg=unused import") + inline def strict[A]: Show[A] = + import Strict.given + summonInline[DerivedShow[A]].instance + // These instances support singleton types unlike the instances in Cats' core. given boolean[A <: Boolean]: DerivedShow[A] = Show.fromToString given byte[A <: Byte]: DerivedShow[A] = Show.fromToString @@ -32,12 +37,10 @@ object DerivedShow: given symbol[A <: Symbol]: DerivedShow[A] = Show.fromToString given [A](using inst: K0.ProductInstances[Or, A], labelling: Labelling[A]): DerivedShow[A] = - given K0.ProductInstances[Show, A] = inst.unify - new Product[Show, A] {} + Strict.product(using labelling, inst.unify) - given [A](using inst: => K0.CoproductInstances[Or, A]): DerivedShow[A] = - given K0.CoproductInstances[Show, A] = inst.unify - new Coproduct[Show, A] {} + given [A](using => K0.CoproductInstances[Or, A]): DerivedShow[A] = + Strict.coproduct trait Product[F[x] <: Show[x], A](using inst: K0.ProductInstances[F, A], labelling: Labelling[A]) extends Show[A]: def show(a: A): String = @@ -64,3 +67,11 @@ object DerivedShow: trait Coproduct[F[x] <: Show[x], A](using inst: K0.CoproductInstances[F, A]) extends Show[A]: def show(a: A): String = inst.fold(a)([t] => (st: F[t], t: t) => st.show(t)) + + object Strict: + given product[A: Labelling](using => K0.ProductInstances[Show, A]): DerivedShow[A] = + new Product[Show, A] {} + + given coproduct[A](using inst: => K0.CoproductInstances[Or, A]): DerivedShow[A] = + given K0.CoproductInstances[Show, A] = inst.unify + new Coproduct[Show, A] {} diff --git a/core/src/main/scala-3/cats/derived/DerivedShowPretty.scala b/core/src/main/scala-3/cats/derived/DerivedShowPretty.scala index 421bcbde..16e9e72f 100644 --- a/core/src/main/scala-3/cats/derived/DerivedShowPretty.scala +++ b/core/src/main/scala-3/cats/derived/DerivedShowPretty.scala @@ -25,7 +25,7 @@ object DerivedShowPretty: inline given [A]: Or[A] = summonFrom: case instance: Show[A] => fromShow(instance) case derived: DerivedShowPretty[A] => fromShow(derived.instance) - private def fromShow[A](instance: Show[A]): Or[A] = instance match + private[derived] def fromShow[A](instance: Show[A]): Or[A] = instance match case pretty: ShowPretty[A] => pretty.showLines case _ => instance.show(_).split(System.lineSeparator).toList @@ -34,6 +34,11 @@ object DerivedShowPretty: import DerivedShowPretty.given summonInline[DerivedShowPretty[A]].instance + @nowarn("msg=unused import") + inline def strict[A]: ShowPretty[A] = + import Strict.given + summonInline[DerivedShowPretty[A]].instance + private def fromToString[A]: ShowPretty[A] = _.toString :: Nil @@ -49,11 +54,14 @@ object DerivedShowPretty: given string[A <: String]: DerivedShowPretty[A] = fromToString given symbol[A <: Symbol]: DerivedShowPretty[A] = fromToString - given [A](using inst: K0.ProductInstances[Or, A], labelling: Labelling[A]): DerivedShowPretty[A] = - new Product[A] {} + given product[A: Labelling](using => K0.ProductInstances[Or, A]): DerivedShowPretty[A] = new Product[A] {} + given coproduct[A](using => K0.CoproductInstances[Or, A]): DerivedShowPretty[A] = new Coproduct[A] {} - given [A](using inst: => K0.CoproductInstances[Or, A]): DerivedShowPretty[A] = - new Coproduct[A] {} + @deprecated("Kept for binary compatibility", "3.2.0") + protected given [A](using K0.ProductInstances[Or, A], Labelling[A]): DerivedShowPretty[A] = product + + @deprecated("Kept for binary compatibility", "3.2.0") + protected given [A](using => K0.CoproductInstances[Or, A]): DerivedShowPretty[A] = coproduct trait Product[A](using inst: K0.ProductInstances[Or, A], labelling: Labelling[A]) extends ShowPretty[A]: def showLines(a: A): List[String] = @@ -63,12 +71,12 @@ object DerivedShowPretty: if n <= 0 then List(s"$prefix()") else var lines = List(")") - inst.project(a)(n - 1)([t] => (show: Or[t], x: t) => show.apply(x)) match + inst.project(a)(n - 1)([a] => (show: Or[a], x: a) => show(x)) match case Nil => lines ::= s" ${labels(n - 1)} = \"\"," case h :: t => lines :::= s" ${labels(n - 1)} = $h" :: t.map(s => " " + s) var i = n - 2 while i >= 0 do - inst.project(a)(i)([t] => (show: Or[t], x: t) => show.apply(x)) match + inst.project(a)(i)([a] => (show: Or[a], x: a) => show(x)) match case Nil => lines ::= s" ${labels(i)} = \"\"," case v :: Nil => lines ::= s" ${labels(i)} = $v," case h :: t => lines = s" ${labels(i)} = $h" :: t.init.map(s => " " + s) ::: s" ${t.last}," :: lines @@ -77,4 +85,10 @@ object DerivedShowPretty: trait Coproduct[A](using inst: K0.CoproductInstances[Or, A]) extends ShowPretty[A]: def showLines(a: A): List[String] = - inst.fold(a)([t] => (st: Or[t], t: t) => st.apply(t)) + inst.fold(a)([a] => (show: Or[a], x: a) => show(x)) + + object Strict: + export DerivedShowPretty.coproduct + given product[A: Labelling](using inst: => K0.ProductInstances[Show, A]): DerivedShowPretty[A] = + given K0.ProductInstances[Or, A] = inst.mapK([a] => (show: Show[a]) => Or.fromShow(show)) + DerivedShowPretty.product diff --git a/core/src/main/scala-3/cats/derived/DerivedTraverse.scala b/core/src/main/scala-3/cats/derived/DerivedTraverse.scala index c54861e1..f3e615bd 100644 --- a/core/src/main/scala-3/cats/derived/DerivedTraverse.scala +++ b/core/src/main/scala-3/cats/derived/DerivedTraverse.scala @@ -21,6 +21,11 @@ object DerivedTraverse: import DerivedTraverse.given summonInline[DerivedTraverse[F]].instance + @nowarn("msg=unused import") + inline def strict[F[_]]: Traverse[F] = + import Strict.given + summonInline[DerivedTraverse[F]].instance + given [T]: DerivedTraverse[Const[T]] = new Traverse[Const[T]]: override def map[A, B](fa: T)(f: A => B): T = fa override def foldLeft[A, B](fa: T, b: B)(f: (B, A) => B): B = b @@ -28,19 +33,14 @@ object DerivedTraverse: override def traverse[G[_], A, B](fa: T)(f: A => G[B])(using G: Applicative[G]): G[T] = G.pure(fa) given nested[F[_], G[_]](using F: => Or[F], G: => Or[G]): DerivedTraverse[[x] =>> F[G[x]]] = - new Derived.Lazy(() => F.unify.compose(G.unify)) with Traverse[[x] =>> F[G[x]]]: + new Derived.Lazy(() => F.unify.compose(using G.unify)) with Traverse[[x] =>> F[G[x]]]: export delegate.* - given [F[_]](using inst: K1.ProductInstances[Or, F]): DerivedTraverse[F] = - given K1.ProductInstances[Traverse, F] = inst.unify - new Product[Traverse, F] with DerivedFunctor.Generic[Traverse, F] {} - - given [F[_]](using inst: => K1.CoproductInstances[Or, F]): DerivedTraverse[F] = - given K1.CoproductInstances[Traverse, F] = inst.unify - new Coproduct[Traverse, F] with DerivedFunctor.Generic[Traverse, F] {} + given [F[_]](using inst: K1.ProductInstances[Or, F]): DerivedTraverse[F] = Strict.product(using inst.unify) + given [F[_]](using => K1.CoproductInstances[Or, F]): DerivedTraverse[F] = Strict.coproduct @deprecated("Kept for binary compatibility", "3.2.0") - private[derived] def given_DerivedTraverse_F[F[_]: Or, G[_]: Or]: DerivedTraverse[[x] =>> F[G[x]]] = summon + protected given [F[_]: Or, G[_]: Or]: DerivedTraverse[[x] =>> F[G[x]]] = nested trait Product[T[f[_]] <: Traverse[f], F[_]](using inst: K1.ProductInstances[T, F]) extends Traverse[F], @@ -60,3 +60,11 @@ object DerivedTraverse: final override def traverse[G[_]: Applicative, A, B](fa: F[A])(f: A => G[B]): G[F[B]] = inst.fold(fa)([f[_]] => (F: T[f], fa: f[A]) => F.traverse(fa)(f).asInstanceOf[G[F[B]]]) + + object Strict: + given product[F[_]](using K1.ProductInstances[Traverse, F]): DerivedTraverse[F] = + new Product[Traverse, F] with DerivedFunctor.Generic[Traverse, F] {} + + given coproduct[F[_]](using inst: => K1.CoproductInstances[Or, F]): DerivedTraverse[F] = + given K1.CoproductInstances[Traverse, F] = inst.unify + new Coproduct[Traverse, F] with DerivedFunctor.Generic[Traverse, F] {} diff --git a/core/src/main/scala-3/cats/derived/package.scala b/core/src/main/scala-3/cats/derived/package.scala index deebb012..6a18b63f 100644 --- a/core/src/main/scala-3/cats/derived/package.scala +++ b/core/src/main/scala-3/cats/derived/package.scala @@ -2,7 +2,7 @@ package cats.derived import alleycats.* import cats.* -import cats.kernel.{CommutativeSemigroup, CommutativeMonoid} +import cats.kernel.{CommutativeMonoid, CommutativeSemigroup} import scala.util.NotGiven @@ -57,6 +57,59 @@ object semiauto: inline def partialOrder[A]: PartialOrder[A] = DerivedPartialOrder[A] inline def showPretty[A]: ShowPretty[A] = DerivedShowPretty[A] +object strict: + extension (x: Eq.type) inline def derived[A]: Eq[A] = DerivedEq.strict[A] + extension (x: Hash.type) inline def derived[A]: Hash[A] = DerivedHash.strict[A] + extension (x: PartialOrder.type) inline def derived[A]: PartialOrder[A] = DerivedPartialOrder.strict[A] + extension (x: Order.type) inline def derived[A]: Order[A] = DerivedOrder.strict[A] + extension (x: Show.type) inline def derived[A]: Show[A] = DerivedShow.strict[A] + extension (x: ShowPretty.type) inline def derived[A]: ShowPretty[A] = DerivedShowPretty.strict[A] + extension (x: Empty.type) inline def derived[A]: Empty[A] = DerivedEmpty.strict[A] + extension (x: Semigroup.type) inline def derived[A]: Semigroup[A] = DerivedSemigroup.strict[A] + extension (x: Monoid.type) inline def derived[A]: Monoid[A] = DerivedMonoid.strict[A] + extension (x: CommutativeSemigroup.type) + inline def derived[A]: CommutativeSemigroup[A] = DerivedCommutativeSemigroup.strict[A] + extension (x: CommutativeMonoid.type) inline def derived[A]: CommutativeMonoid[A] = DerivedCommutativeMonoid.strict[A] + extension (x: EmptyK.type) inline def derived[F[_]]: EmptyK[F] = DerivedEmptyK.strict[F] + extension (x: SemigroupK.type) inline def derived[F[_]]: SemigroupK[F] = DerivedSemigroupK.strict[F] + extension (x: MonoidK.type) inline def derived[F[_]]: MonoidK[F] = DerivedMonoidK.strict[F] + extension (x: Pure.type) inline def derived[F[_]]: Pure[F] = DerivedPure.strict[F] + extension (x: Invariant.type) inline def derived[F[_]]: Invariant[F] = DerivedInvariant.strict[F] + extension (x: Functor.type) inline def derived[F[_]]: Functor[F] = DerivedFunctor.strict[F] + extension (x: Contravariant.type) inline def derived[F[_]]: Contravariant[F] = DerivedContravariant.strict[F] + extension (x: Apply.type) inline def derived[F[_]]: Apply[F] = DerivedApply.strict[F] + extension (x: Applicative.type) inline def derived[F[_]]: Applicative[F] = DerivedApplicative.strict[F] + extension (x: Foldable.type) inline def derived[F[_]]: Foldable[F] = DerivedFoldable.strict[F] + extension (x: Reducible.type) inline def derived[F[_]]: Reducible[F] = DerivedReducible.strict[F] + extension (x: Traverse.type) inline def derived[F[_]]: Traverse[F] = DerivedTraverse.strict[F] + extension (x: NonEmptyTraverse.type) inline def derived[F[_]]: NonEmptyTraverse[F] = DerivedNonEmptyTraverse.strict[F] + + object semiauto: + inline def eq[A]: Eq[A] = DerivedEq.strict[A] + inline def hash[A]: Hash[A] = DerivedHash.strict[A] + inline def partialOrder[A]: PartialOrder[A] = DerivedPartialOrder.strict[A] + inline def order[A]: Order[A] = DerivedOrder.strict[A] + inline def show[A]: Show[A] = DerivedShow.strict[A] + inline def showPretty[A]: ShowPretty[A] = DerivedShowPretty.strict[A] + inline def empty[A]: Empty[A] = DerivedEmpty.strict[A] + inline def semigroup[A]: Semigroup[A] = DerivedSemigroup.strict[A] + inline def monoid[A]: Monoid[A] = DerivedMonoid.strict[A] + inline def commutativeSemigroup[A]: CommutativeSemigroup[A] = DerivedCommutativeSemigroup.strict[A] + inline def commutativeMonoid[A]: CommutativeMonoid[A] = DerivedCommutativeMonoid.strict[A] + inline def emptyK[F[_]]: EmptyK[F] = DerivedEmptyK.strict[F] + inline def semigroupK[F[_]]: SemigroupK[F] = DerivedSemigroupK.strict[F] + inline def monoidK[F[_]]: MonoidK[F] = DerivedMonoidK.strict[F] + inline def pure[F[_]]: Pure[F] = DerivedPure.strict[F] + inline def invariant[F[_]]: Invariant[F] = DerivedInvariant.strict[F] + inline def functor[F[_]]: Functor[F] = DerivedFunctor.strict[F] + inline def contravariant[F[_]]: Contravariant[F] = DerivedContravariant.strict[F] + inline def apply[F[_]]: Apply[F] = DerivedApply.strict[F] + inline def applicative[F[_]]: Applicative[F] = DerivedApplicative.strict[F] + inline def foldable[F[_]]: Foldable[F] = DerivedFoldable.strict[F] + inline def reducible[F[_]]: Reducible[F] = DerivedReducible.strict[F] + inline def traverse[F[_]]: Traverse[F] = DerivedTraverse.strict[F] + inline def nonEmptyTraverse[F[_]]: NonEmptyTraverse[F] = DerivedNonEmptyTraverse.strict[F] + object auto: object eq: inline given [A](using NotGiven[Eq[A]]): Eq[A] = DerivedEq[A] diff --git a/core/src/test/scala-3/cats/derived/ADTs.scala b/core/src/test/scala-3/cats/derived/ADTs.scala index 53f3c1ed..d157e65f 100644 --- a/core/src/test/scala-3/cats/derived/ADTs.scala +++ b/core/src/test/scala-3/cats/derived/ADTs.scala @@ -226,6 +226,7 @@ object ADTs: final case class Second(value: String) final case class Middle(first: First, second: Option[Second]) final case class Top(middle: Middle) + final case class TopK[A](middle: Middle, k: CaseClassWOption[A]) final case class Address(street: String, city: String, state: String) final case class ContactInfo(phoneNumber: String, address: Address) diff --git a/core/src/test/scala-3/cats/derived/ApplicativeSuite.scala b/core/src/test/scala-3/cats/derived/ApplicativeSuite.scala index a326bd86..50ed417e 100644 --- a/core/src/test/scala-3/cats/derived/ApplicativeSuite.scala +++ b/core/src/test/scala-3/cats/derived/ApplicativeSuite.scala @@ -16,10 +16,12 @@ package cats.derived -import cats.Applicative +import cats.{Applicative, Monoid} import cats.laws.discipline.* import cats.laws.discipline.SemigroupalTests.Isomorphisms import org.scalacheck.Arbitrary +import shapeless3.deriving.Const + import scala.compiletime.* class ApplicativeSuite extends KittensSuite: @@ -40,24 +42,26 @@ class ApplicativeSuite extends KittensSuite: checkAll(s"$instance[ListBox]", tests[ListBox].applicative[Int, String, Long]) checkAll(s"$instance is Serializable", SerializableTests.serializable(summonInline[Applicative[Interleaved]])) - locally { + locally: import auto.applicative.given validate("auto.applicative") - } - locally { + locally: import semiInstances.given validate("semiauto.applicative") - } - locally { + locally: + import strictInstances.given + validate("strict.semiauto.applicative") + testNoInstance("strict.semiauto.applicative", "TopK") + + locally: import derivedInstances.* val instance = "derived.applicative" checkAll(s"$instance[CaseClassWOption]", tests[CaseClassWOption].applicative[Int, String, Long]) checkAll(s"$instance[AndInt]", tests[AndInt].applicative[Int, String, Long]) checkAll(s"$instance[Interleaved]", tests[Interleaved].applicative[Int, String, Long]) checkAll(s"$instance is Serializable", SerializableTests.serializable(Applicative[Interleaved])) - } end ApplicativeSuite @@ -76,6 +80,14 @@ object ApplicativeSuite: given Applicative[Interleaved] = semiauto.applicative given Applicative[ListBox] = semiauto.applicative + object strictInstances: + given [T: Monoid]: Applicative[Const[T]] = semiauto.applicative + given [F[_]: Applicative, G[_]: Applicative]: Applicative[[x] =>> F[G[x]]] = Applicative[F].compose[G] + given Applicative[Box] = strict.semiauto.applicative + given Applicative[CaseClassWOption] = strict.semiauto.applicative + given Applicative[AndInt] = strict.semiauto.applicative + given Applicative[Interleaved] = strict.semiauto.applicative + object derivedInstances: case class CaseClassWOption[A](x: ADTs.CaseClassWOption[A]) derives Applicative case class Interleaved[A](x: ADTs.Interleaved[A]) derives Applicative diff --git a/core/src/test/scala-3/cats/derived/ApplySuite.scala b/core/src/test/scala-3/cats/derived/ApplySuite.scala index 2c958856..114857dc 100644 --- a/core/src/test/scala-3/cats/derived/ApplySuite.scala +++ b/core/src/test/scala-3/cats/derived/ApplySuite.scala @@ -16,9 +16,11 @@ package cats.derived -import cats.Apply +import cats.{Apply, Semigroup} import cats.laws.discipline.* import cats.laws.discipline.SemigroupalTests.Isomorphisms +import shapeless3.deriving.Const + import scala.compiletime.* class ApplySuite extends KittensSuite: @@ -48,6 +50,11 @@ class ApplySuite extends KittensSuite: import semiInstances.given validate("semiauto.apply") + locally: + import semiInstances.given + validate("strict.semiauto.apply") + testNoInstance("strict.semiauto.apply", "TopK") + locally: import derivedInstances.* val instance = "derived.apply" @@ -74,6 +81,15 @@ object ApplySuite: given Apply[ListBox] = semiauto.apply given Apply[Search] = semiauto.apply + object strictInstances: + given [T: Semigroup]: Apply[Const[T]] = semiauto.apply + given [F[_]: Apply, G[_]: Apply]: Apply[[x] =>> F[G[x]]] = Apply[F].compose[G] + given Apply[Box] = strict.semiauto.apply + given Apply[CaseClassWOption] = strict.semiauto.apply + given Apply[AndInt] = strict.semiauto.apply + given Apply[Interleaved] = strict.semiauto.apply + given Apply[Search] = strict.semiauto.apply + object derivedInstances: case class CaseClassWOption[A](x: ADTs.CaseClassWOption[A]) derives Apply case class Interleaved[A](x: ADTs.Interleaved[A]) derives Apply diff --git a/core/src/test/scala-3/cats/derived/CommutativeMonoidSuite.scala b/core/src/test/scala-3/cats/derived/CommutativeMonoidSuite.scala index 3f1b2338..d670c173 100644 --- a/core/src/test/scala-3/cats/derived/CommutativeMonoidSuite.scala +++ b/core/src/test/scala-3/cats/derived/CommutativeMonoidSuite.scala @@ -35,29 +35,30 @@ class CommutativeMonoidSuite extends KittensSuite: s"$instance is Serializable", SerializableTests.serializable(summonInline[CommutativeMonoid[CommutativeFoo]]) ) - test(s"$instance respects existing instances") { + test(s"$instance respects existing instances"): val box = summonInline[CommutativeMonoid[BoxMul]] assert(box.empty == Box(Mul(1))) assert(box.combine(Box(Mul(5)), Box(Mul(5))) == Box(Mul(25))) - } - locally { + locally: import auto.commutativeMonoid.given validate("auto.commutativeMonoid") - } - locally { + locally: import semiInstances.given validate("semiauto.commutativeMonoid") - } - locally { + locally: + import strictInstances.given + validate("strict.semiauto.commutativeMonoid") + testNoInstance("strict.semiauto.commutativeMonoid", "Top") + + locally: import derivedInstances.* val instance = "derived.commutativeMonoid" checkAll(s"$instance[CommutativeFoo]", tests[CommutativeFoo].commutativeMonoid) checkAll(s"$instance[BoxMul]", tests[BoxMul].commutativeMonoid) checkAll(s"$instance is Serializable", SerializableTests.serializable(CommutativeMonoid[CommutativeFoo])) - } end CommutativeMonoidSuite @@ -71,6 +72,11 @@ object CommutativeMonoidSuite: given CommutativeMonoid[Recursive] = semiauto.commutativeMonoid given CommutativeMonoid[Box[Mul]] = semiauto.commutativeMonoid + object strictInstances: + given CommutativeMonoid[CommutativeFoo] = strict.semiauto.commutativeMonoid + given CommutativeMonoid[Recursive] = strict.semiauto.commutativeMonoid + given CommutativeMonoid[Box[Mul]] = strict.semiauto.commutativeMonoid + object derivedInstances: case class CommutativeFoo(x: ADTs.CommutativeFoo) derives CommutativeMonoid case class BoxMul(x: CommutativeMonoidSuite.BoxMul) derives CommutativeMonoid diff --git a/core/src/test/scala-3/cats/derived/CommutativeSemigroupSuite.scala b/core/src/test/scala-3/cats/derived/CommutativeSemigroupSuite.scala index e4b4d86c..d3c8719e 100644 --- a/core/src/test/scala-3/cats/derived/CommutativeSemigroupSuite.scala +++ b/core/src/test/scala-3/cats/derived/CommutativeSemigroupSuite.scala @@ -35,28 +35,29 @@ class CommutativeSemigroupSuite extends KittensSuite: s"$instance is Serializable", SerializableTests.serializable(summonInline[CommutativeSemigroup[CommutativeFoo]]) ) - test(s"$instance respects existing instances") { + test(s"$instance respects existing instances"): val box = summonInline[CommutativeSemigroup[BoxMul]] assert(box.combine(Box(Mul(5)), Box(Mul(5))).content.value == 25) - } - locally { + locally: import auto.commutativeSemigroup.given validate("auto.commutativeSemigroup") - } - locally { + locally: import semiInstances.given validate("semiauto.commutativeSemigroup") - } - locally { + locally: + import strictInstances.given + validate("strict.semiauto.commutativeSemigroup") + testNoInstance("strict.semiauto.commutativeSemigroup", "Top") + + locally: import derivedInstances.* val instance = "derived.commutativeSemigroup" checkAll(s"$instance[CommutativeFoo]", tests[CommutativeFoo].commutativeSemigroup) checkAll(s"$instance[BoxMul]", tests[BoxMul].commutativeSemigroup) checkAll(s"$instance is Serializable", SerializableTests.serializable(CommutativeSemigroup[CommutativeFoo])) - } end CommutativeSemigroupSuite @@ -70,6 +71,11 @@ object CommutativeSemigroupSuite: given CommutativeSemigroup[Recursive] = semiauto.commutativeSemigroup given CommutativeSemigroup[BoxMul] = semiauto.commutativeSemigroup + object strictInstances: + given CommutativeSemigroup[CommutativeFoo] = strict.semiauto.commutativeSemigroup + given CommutativeSemigroup[Recursive] = strict.semiauto.commutativeSemigroup + given CommutativeSemigroup[BoxMul] = strict.semiauto.commutativeSemigroup + object derivedInstances: case class CommutativeFoo(x: ADTs.CommutativeFoo) derives CommutativeSemigroup case class BoxMul(x: CommutativeSemigroupSuite.BoxMul) derives CommutativeSemigroup diff --git a/core/src/test/scala-3/cats/derived/ContravariantSuite.scala b/core/src/test/scala-3/cats/derived/ContravariantSuite.scala index c9c8f700..534fc32a 100644 --- a/core/src/test/scala-3/cats/derived/ContravariantSuite.scala +++ b/core/src/test/scala-3/cats/derived/ContravariantSuite.scala @@ -16,10 +16,12 @@ package cats.derived -import cats.Contravariant +import cats.{Contravariant, Functor} import cats.laws.discipline.* import cats.laws.discipline.arbitrary.* import cats.laws.discipline.eq.* +import shapeless3.deriving.Const + import scala.compiletime.* class ContravariantSuite extends KittensSuite: @@ -41,23 +43,25 @@ class ContravariantSuite extends KittensSuite: checkAll(s"$instance[EnumK1Contra]", tests[EnumK1Contra].contravariant[MiniInt, String, Boolean]) checkAll(s"$instance is Serializable", SerializableTests.serializable(summonInline[Contravariant[TreePred]])) - locally { + locally: import auto.contravariant.given validate("auto.contravariant") - } - locally { + locally: import semiInstances.given validate("semiauto.contravariant") - } - locally { + locally: + import strictInstances.given + validate("strict.semiauto.contravariant") + testNoInstance("strict.semiauto.contravariant", "TopK") + + locally: import derivedInstances.* val instance = "derived.contravariant" checkAll(s"$instance[EnumK1Contra]", tests[EnumK1Contra].contravariant[MiniInt, String, Boolean]) checkAll(s"$instance[Single]", tests[Single].contravariant[MiniInt, String, Boolean]) checkAll(s"$instance is Serializable", SerializableTests.serializable(Contravariant[EnumK1Contra])) - } end ContravariantSuite @@ -83,6 +87,20 @@ object ContravariantSuite: given Contravariant[ListSnocF] = semiauto.contravariant given Contravariant[EnumK1Contra] = semiauto.contravariant + object strictInstances: + given [T]: Contravariant[Const[T]] = semiauto.contravariant + given [F[_]: Functor, R]: Contravariant[[x] =>> F[x => R]] = Functor[F].composeContravariant[[x] =>> x => R] + given Functor[Snoc] = strict.semiauto.functor + given Contravariant[OptPred] = strict.semiauto.contravariant + given Contravariant[TreePred] = strict.semiauto.contravariant + given Contravariant[ListPred] = strict.semiauto.contravariant + given Contravariant[GenericAdtPred] = strict.semiauto.contravariant + // TODO: https://github.com/typelevel/kittens/issues/473 + // given Contravariant[InterleavedPred] = strict.semiauto.contravariant + given Contravariant[AndCharPred] = strict.semiauto.contravariant + given Contravariant[ListSnocF] = strict.semiauto.contravariant + given Contravariant[EnumK1Contra] = strict.semiauto.contravariant + object derivedInstances: case class EnumK1Contra[-A](x: ADTs.EnumK1Contra[A]) derives Contravariant case class Single[-A](value: A => Unit) derives Contravariant diff --git a/core/src/test/scala-3/cats/derived/EmptyKSuite.scala b/core/src/test/scala-3/cats/derived/EmptyKSuite.scala index f01fc1eb..a0589e2f 100644 --- a/core/src/test/scala-3/cats/derived/EmptyKSuite.scala +++ b/core/src/test/scala-3/cats/derived/EmptyKSuite.scala @@ -42,24 +42,26 @@ class EmptyKSuite extends KittensSuite: test(s"$instance respects existing instances")(assert(emptyK[BoxColor] == Box(Color(255, 255, 255)))) checkAll(s"$instance is Serializable", SerializableTests.serializable(summonInline[EmptyK[LOption]])) - locally { + locally: import auto.emptyK.given validate("auto.emptyK") - } - locally { + locally: import semiInstances.given validate("semiauto.emptyK") - } - locally { + locally: + import strictInstances.given + validate("strict.semiauto.emptyK") + testNoInstance("strict.semiauto.emptyK", "TopK") + + locally: import derivedInstances.* val instance = "derived.emptyK" test(s"$instance[CaseClassWOption]")(assert(emptyK[CaseClassWOption].x.value.isEmpty)) test(s"$instance[IList]")(assert(emptyK[IList].x == INil())) test(s"$instance[Snoc]")(assert(emptyK[Snoc].x == SNil())) checkAll(s"$instance is Serializable", SerializableTests.serializable(EmptyK[Snoc])) - } end EmptyKSuite @@ -80,6 +82,15 @@ object EmptyKSuite: given EmptyK[Snoc] = semiauto.emptyK given EmptyK[BoxColor] = semiauto.emptyK + object strictInstances: + given EmptyK[LOption] = semiauto.emptyK + given EmptyK[PList] = strict.semiauto.emptyK + given EmptyK[CaseClassWOption] = strict.semiauto.emptyK + given EmptyK[NelOption] = semiauto.emptyK + given EmptyK[IList] = strict.semiauto.emptyK + given EmptyK[Snoc] = strict.semiauto.emptyK + given EmptyK[BoxColor] = strict.semiauto.emptyK + object derivedInstances: case class CaseClassWOption[A](x: ADTs.CaseClassWOption[A]) derives EmptyK case class IList[A](x: ADTs.IList[A]) derives EmptyK diff --git a/core/src/test/scala-3/cats/derived/EmptySuite.scala b/core/src/test/scala-3/cats/derived/EmptySuite.scala index 861847d1..d70bedf1 100644 --- a/core/src/test/scala-3/cats/derived/EmptySuite.scala +++ b/core/src/test/scala-3/cats/derived/EmptySuite.scala @@ -38,23 +38,30 @@ class EmptySuite extends KittensSuite: test(s"$instance respects existing instances")(assert(empty[Box[Mask]] == Box(Mask(0xffffffff)))) checkAll(s"$instance is Serializable", SerializableTests.serializable(summonInline[Empty[Foo]])) - locally { + locally: import auto.empty.given validate("auto.empty") testNoInstance("Empty", "IList[Int]") testNoInstance("Empty", "Snoc[Int]") testNoInstance("Empty", "Rgb") - } - locally { + locally: import semiInstances.given validate("semiauto.empty") - testNoInstance("Empty", "IList[Int]") - testNoInstance("Empty", "Snoc[Int]") - testNoInstance("Empty", "Rgb") - } + testNoInstance("semiauto.empty", "IList[Int]") + testNoInstance("semiauto.empty", "Snoc[Int]") + testNoInstance("semiauto.empty", "Rgb") - locally { + locally: + import strictInstances.given + validate("strict.semiauto.empty") + testNoInstance("strict.semiauto.empty", "Rgb") + testNoInstance("strict.semiauto.empty", "Top") + test("No strict.semiauto.empty for IList[Int] or Snoc[Int]"): + assertNoInstance(compileErrors("given Empty[IList[Int]] = strict.semiauto.empty")) + assertNoInstance(compileErrors("given Empty[Snoc[Int]] = strict.semiauto.empty")) + + locally: import derivedInstances.* val instance = "derived.empty" test(s"$instance[Foo]")(assert(empty[Foo].x == ADTs.Foo(0, None))) @@ -65,7 +72,6 @@ class EmptySuite extends KittensSuite: test(s"$instance[Snoc[Dummy]]")(assert(empty[Snoc[Int]].x == SNil())) test(s"$instance respects existing instances")(assert(empty[BoxMask].x == Box(Mask(0xffffffff)))) checkAll(s"$instance is Serializable", SerializableTests.serializable(Empty[Foo])) - } end EmptySuite @@ -85,6 +91,17 @@ object EmptySuite: given Empty[Box[Mask]] = semiauto.empty given Empty[Chain] = semiauto.empty + object strictInstances: + given Empty[Foo] = strict.semiauto.empty + given Empty[Inner] = strict.semiauto.empty + given Empty[Outer] = strict.semiauto.empty + given Empty[Interleaved[String]] = strict.semiauto.empty + given Empty[Recursive] = strict.semiauto.empty + given Empty[IList[Dummy]] = strict.semiauto.empty + given Empty[Snoc[Dummy]] = strict.semiauto.empty + given Empty[Box[Mask]] = strict.semiauto.empty + given Empty[Chain] = strict.semiauto.empty + object derivedInstances: case class Foo(x: ADTs.Foo) derives Empty case class Outer(x: ADTs.Outer) derives Empty diff --git a/core/src/test/scala-3/cats/derived/EqSuite.scala b/core/src/test/scala-3/cats/derived/EqSuite.scala index 87eb0108..4033b0c4 100644 --- a/core/src/test/scala-3/cats/derived/EqSuite.scala +++ b/core/src/test/scala-3/cats/derived/EqSuite.scala @@ -46,6 +46,11 @@ class EqSuite extends KittensSuite.WithoutEq: import semiInstances.given validate("semiauto.eq") + locally: + import strictInstances.given + validate("strict.semiauto.eq") + testNoInstance("strict.semiauto.eq", "Top") + locally: import derivedInstances.* val instance = "derived.eq" @@ -74,6 +79,17 @@ object EqSuite: given Eq[Recursive] = semiauto.eq given Eq[Singletons[Int]] = semiauto.eq + object strictInstances: + given [A <: Singleton: ValueOf]: Eq[A] = Eq.allEqual + given Eq[Foo] = strict.semiauto.eq + given Eq[IList[Int]] = strict.semiauto.eq + given Eq[Inner] = strict.semiauto.eq + given Eq[Outer] = strict.semiauto.eq + given Eq[Interleaved[Int]] = strict.semiauto.eq + given Eq[Tree[Int]] = strict.semiauto.eq + given Eq[Recursive] = strict.semiauto.eq + given Eq[Singletons[Int]] = strict.semiauto.eq + object derivedInstances: case class Foo(x: ADTs.Foo) derives Eq case class IList[A](x: ADTs.IList[A]) derives Eq diff --git a/core/src/test/scala-3/cats/derived/FoldableSuite.scala b/core/src/test/scala-3/cats/derived/FoldableSuite.scala index 303ae89b..2b33081e 100644 --- a/core/src/test/scala-3/cats/derived/FoldableSuite.scala +++ b/core/src/test/scala-3/cats/derived/FoldableSuite.scala @@ -19,6 +19,8 @@ package cats.derived import cats.{Eval, Foldable} import cats.laws.discipline.* import cats.syntax.all.given +import shapeless3.deriving.Const + import scala.compiletime.* class FoldableSuite extends KittensSuite: @@ -53,6 +55,11 @@ class FoldableSuite extends KittensSuite: import semiInstances.given validate("semiauto.foldable") + locally: + import strictInstances.given + validate("strict.semiauto.foldable") + testNoInstance("strict.semiauto.foldable", "TopK") + locally: import derivedInstances.* val instance = "derived.foldable" @@ -94,6 +101,25 @@ object FoldableSuite: given Foldable[Singletons] = semiauto.foldable given Foldable[Search] = semiauto.foldable + object strictInstances: + given [T]: Foldable[Const[T]] = semiauto.foldable + given [F[_]: Foldable, G[_]: Foldable]: Foldable[[x] =>> F[G[x]]] = Foldable[F].compose[G] + given Foldable[Snoc] = strict.semiauto.foldable + given Foldable[IList] = strict.semiauto.foldable + given Foldable[Tree] = strict.semiauto.foldable + given Foldable[GenericAdt] = strict.semiauto.foldable + given Foldable[OptList] = strict.semiauto.foldable + given Foldable[ListSnoc] = strict.semiauto.foldable + given Foldable[AndChar] = strict.semiauto.foldable + given Foldable[Interleaved] = strict.semiauto.foldable + given Foldable[BoxNel] = strict.semiauto.foldable + given Foldable[EnumK1] = strict.semiauto.foldable + given Foldable[Many] = strict.semiauto.foldable + given Foldable[AtMostOne] = strict.semiauto.foldable + given Foldable[AtLeastOne] = strict.semiauto.foldable + given Foldable[Singletons] = strict.semiauto.foldable + given Foldable[Search] = strict.semiauto.foldable + object derivedInstances: case class IList[A](x: ADTs.IList[A]) derives Foldable case class Tree[A](x: ADTs.Tree[A]) derives Foldable diff --git a/core/src/test/scala-3/cats/derived/FunctorSuite.scala b/core/src/test/scala-3/cats/derived/FunctorSuite.scala index 650a1326..2babf470 100644 --- a/core/src/test/scala-3/cats/derived/FunctorSuite.scala +++ b/core/src/test/scala-3/cats/derived/FunctorSuite.scala @@ -16,9 +16,11 @@ package cats.derived -import cats.Functor +import cats.{Contravariant, Functor} import cats.laws.discipline.* import cats.laws.discipline.eq.* +import shapeless3.deriving.Const + import scala.compiletime.* class FunctorSuite extends KittensSuite: @@ -56,6 +58,11 @@ class FunctorSuite extends KittensSuite: import semiInstances.given validate("semiauto.functor") + locally: + import strictInstances.given + validate("strict.semiauto.functor") + testNoInstance("strict.semiauto.functor", "TopK") + locally: import derivedInstances.* val instance = "derived.functor" @@ -98,6 +105,25 @@ object FunctorSuite: given Functor[Singletons] = semiauto.functor given Functor[Search] = semiauto.functor + object strictInstances: + given [T]: Functor[Const[T]] = semiauto.functor + given [F[_]: Functor, G[_]: Functor]: Functor[[x] =>> F[G[x]]] = Functor[F].compose[G] + given [F[_]: Contravariant, G[_]: Contravariant]: Functor[[x] =>> F[G[x]]] = Contravariant[F].compose[G] + given Functor[Snoc] = strict.semiauto.functor + given Functor[IList] = strict.semiauto.functor + given Functor[Tree] = strict.semiauto.functor + given Functor[GenericAdt] = strict.semiauto.functor + given Functor[OptList] = strict.semiauto.functor + given Functor[ListSnoc] = strict.semiauto.functor + given Functor[AndChar] = strict.semiauto.functor + given Functor[Interleaved] = strict.semiauto.functor + given Functor[EnumK1] = strict.semiauto.functor + given Functor[Many] = strict.semiauto.functor + given Functor[AtMostOne] = strict.semiauto.functor + given Functor[AtLeastOne] = strict.semiauto.functor + given Functor[Singletons] = strict.semiauto.functor + given Functor[Search] = strict.semiauto.functor + object derivedInstances: case class IList[A](x: ADTs.IList[A]) derives Functor case class Tree[A](x: ADTs.Tree[A]) derives Functor diff --git a/core/src/test/scala-3/cats/derived/HashSuite.scala b/core/src/test/scala-3/cats/derived/HashSuite.scala index e54a1c17..9507bfa0 100644 --- a/core/src/test/scala-3/cats/derived/HashSuite.scala +++ b/core/src/test/scala-3/cats/derived/HashSuite.scala @@ -30,6 +30,11 @@ class HashSuite extends KittensSuite: import semiInstances.given validate("semiauto.hash") + locally: + import strictInstances.given + validate("strict.semiauto.hash") + testNoInstance("strict.semiauto.hash", "Top") + locally: import derivedInstances.* val instance = "derived.hash" @@ -58,6 +63,17 @@ object HashSuite: given Hash[EnumK0] = semiauto.hash given Hash[Singletons[Int]] = semiauto.hash + object strictInstances: + given [A <: Singleton: ValueOf]: Hash[A] = Hash.fromUniversalHashCode + given Hash[IList[Int]] = strict.semiauto.hash + given Hash[Inner] = strict.semiauto.hash + given Hash[Outer] = strict.semiauto.hash + given Hash[Interleaved[Int]] = strict.semiauto.hash + given Hash[Tree[Int]] = strict.semiauto.hash + given Hash[Recursive] = strict.semiauto.hash + given Hash[EnumK0] = strict.semiauto.hash + given Hash[Singletons[Int]] = strict.semiauto.hash + object derivedInstances: case class IList[A](x: ADTs.IList[A]) derives Hash case class Inner(x: ADTs.Inner) derives Hash diff --git a/core/src/test/scala-3/cats/derived/InvariantSuite.scala b/core/src/test/scala-3/cats/derived/InvariantSuite.scala index 56da5cae..50dcb32b 100644 --- a/core/src/test/scala-3/cats/derived/InvariantSuite.scala +++ b/core/src/test/scala-3/cats/derived/InvariantSuite.scala @@ -20,18 +20,20 @@ import cats.Invariant import cats.laws.discipline.* import cats.laws.discipline.arbitrary.* import cats.laws.discipline.eq.* +import shapeless3.deriving.Const + import scala.compiletime.* class InvariantSuite extends KittensSuite: - import InvariantSuite.* import ADTs.* + import InvariantSuite.* inline def tests[F[_]]: InvariantTests[F] = InvariantTests[F](summonInline) inline def validate(instance: String): Unit = checkAll(s"$instance[TreeF]", tests[TreeF].invariant[MiniInt, String, Boolean]) - checkAll(s"$instance[GenAdtF]", tests[GenericAdtF].invariant[MiniInt, String, Boolean]) + checkAll(s"$instance[GenericAdtF]", tests[GenericAdtF].invariant[MiniInt, String, Boolean]) // TODO: https://github.com/typelevel/kittens/issues/473 // checkAll(s"$instance[InterleavedF]", tests[InterleavedF].invariant[MiniInt, String, Boolean]) checkAll(s"$instance[AndCharF]", tests[AndCharF].invariant[MiniInt, String, Boolean]) @@ -54,6 +56,11 @@ class InvariantSuite extends KittensSuite: import semiInstances.given validate("semiauto.invariant") + locally: + import strictInstances.given + validate("strict.semiauto.invariant") + testNoInstance("strict.semiauto.invariant", "TopK") + locally: import derivedInstances.* val instance = "derived.invariant" @@ -96,6 +103,28 @@ object InvariantSuite: given Invariant[Singletons] = semiauto.invariant given Invariant[Search] = semiauto.invariant + object strictInstances: + given [T]: Invariant[Const[T]] = semiauto.invariant + given [F[_]: Invariant, G[_]: Invariant]: Invariant[[x] =>> F[G[x]]] = Invariant[F].compose[G] + given [F[_]: Invariant, R]: Invariant[[x] =>> F[x => R]] = Invariant[F].compose[[x] =>> x => R] + given Invariant[Snoc] = strict.semiauto.invariant + given Invariant[GenericAdtF] = strict.semiauto.invariant + given Invariant[ListFToInt] = strict.semiauto.invariant + // TODO: https://github.com/typelevel/kittens/issues/473 + // given Invariant[InterleavedF] = strict.semiauto.invariant + given Invariant[AndCharF] = strict.semiauto.invariant + given Invariant[TreeF] = strict.semiauto.invariant + given Invariant[Pred] = strict.semiauto.invariant + given Invariant[ListSnoc] = strict.semiauto.invariant + given Invariant[Bivariant] = strict.semiauto.invariant + given Invariant[IList] = strict.semiauto.invariant + given Invariant[EnumK1Inv] = strict.semiauto.invariant + given Invariant[Many] = strict.semiauto.invariant + given Invariant[AtMostOne] = strict.semiauto.invariant + given Invariant[AtLeastOne] = strict.semiauto.invariant + given Invariant[Singletons] = strict.semiauto.invariant + given Invariant[Search] = strict.semiauto.invariant + object derivedInstances: case class Bivariant[A](x: ADTs.Bivariant[A]) derives Invariant case class IList[A](x: ADTs.IList[A]) derives Invariant diff --git a/core/src/test/scala-3/cats/derived/KittensSuite.scala b/core/src/test/scala-3/cats/derived/KittensSuite.scala index 47bf5511..8d3128f1 100644 --- a/core/src/test/scala-3/cats/derived/KittensSuite.scala +++ b/core/src/test/scala-3/cats/derived/KittensSuite.scala @@ -61,7 +61,9 @@ object KittensSuite: given [A <: Product](using mirror: Mirror.ProductOf[A], via: Cogen[mirror.MirroredElemTypes]): Cogen[A] = via.contramap(Tuple.fromProductTyped) - inline def testNoInstance(inline tc: String, target: String): Unit = - val errors = compileErrors(tc + "[" + target + "]") + def assertNoInstance(errors: String): Unit = val message = "No given instance of type" - test(s"No $tc for $target")(assert(errors.contains(message), s"$errors did not contain $message")) + assert(errors.contains(message), s"$errors did not contain $message") + + inline def testNoInstance(inline tc: String, target: String): Unit = + test(s"No $tc for $target")(assertNoInstance(compileErrors(tc + "[" + target + "]"))) diff --git a/core/src/test/scala-3/cats/derived/MonoidKSuite.scala b/core/src/test/scala-3/cats/derived/MonoidKSuite.scala index d85b884b..29c304a9 100644 --- a/core/src/test/scala-3/cats/derived/MonoidKSuite.scala +++ b/core/src/test/scala-3/cats/derived/MonoidKSuite.scala @@ -1,7 +1,9 @@ package cats.derived -import cats.MonoidK +import cats.{Applicative, Eval, Monoid, MonoidK} import cats.laws.discipline.{MonoidKTests, SerializableTests} +import shapeless3.deriving.Const + import scala.compiletime.* class MonoidKSuite extends KittensSuite: @@ -16,30 +18,31 @@ class MonoidKSuite extends KittensSuite: checkAll(s"$instance[CaseClassWOption]", tests[CaseClassWOption].monoidK[Char]) checkAll(s"$instance[BoxMul]", tests[BoxMul].monoidK[Char]) checkAll(s"$instance is Serializable", SerializableTests.serializable(summonInline[MonoidK[ComplexProduct]])) - test(s"$instance respects existing instances") { + test(s"$instance respects existing instances"): val M = summonInline[MonoidK[BoxMul]] assert(M.empty[Char] == Box(Mul[Char](1))) assert(M.combineK(Box(Mul[Char](5)), Box(Mul[Char](5))) == Box(Mul[Char](25))) - } - locally { + locally: import auto.monoidK.given validate("auto.monoidK") - } - locally { + locally: import semiInstances.given validate("semiauto.monoidK") - } - locally { + locally: + import strictInstances.given + validate("strict.semiauto.monoidK") + testNoInstance("strict.semiauto.monoidK", "TopK") + + locally: import derivedInstances.* val instance = "derived.monoidK" checkAll(s"$instance[ComplexProduct]", tests[ComplexProduct].monoidK[Char]) checkAll(s"$instance[CaseClassWOption]", tests[CaseClassWOption].monoidK[Char]) checkAll(s"$instance[Simple]", tests[Simple].monoidK[Char]) checkAll(s"$instance is Serializable", SerializableTests.serializable(MonoidK[ComplexProduct])) - } end MonoidKSuite @@ -53,6 +56,14 @@ object MonoidKSuite: given MonoidK[CaseClassWOption] = semiauto.monoidK given MonoidK[BoxMul] = semiauto.monoidK + object strictInstances: + given [T: Monoid]: MonoidK[Const[T]] = semiauto.monoidK + given [F[_]: MonoidK, G[_]]: MonoidK[[x] =>> F[G[x]]] = MonoidK[F].compose[G] + given [F[_]: Applicative, G[_]: MonoidK]: MonoidK[[x] =>> F[G[x]]] = semiauto.monoidK + given MonoidK[ComplexProduct] = strict.semiauto.monoidK + given MonoidK[CaseClassWOption] = strict.semiauto.monoidK + given MonoidK[BoxMul] = strict.semiauto.monoidK + object derivedInstances: case class ComplexProduct[A](x: ADTs.ComplexProduct[A]) derives MonoidK case class CaseClassWOption[A](x: ADTs.CaseClassWOption[A]) derives MonoidK diff --git a/core/src/test/scala-3/cats/derived/MonoidSuite.scala b/core/src/test/scala-3/cats/derived/MonoidSuite.scala index 3651cb82..27834101 100644 --- a/core/src/test/scala-3/cats/derived/MonoidSuite.scala +++ b/core/src/test/scala-3/cats/derived/MonoidSuite.scala @@ -33,30 +33,31 @@ class MonoidSuite extends KittensSuite: checkAll(s"$instance[Box[Mul]]", tests[Box[Mul]].monoid) checkAll(s"$instance[Recursive]", tests[Recursive].monoid) checkAll(s"$instance is Serializable", SerializableTests.serializable(summonInline[Monoid[Foo]])) - test(s"$instance respects existing instances") { + test(s"$instance respects existing instances"): val box = summonInline[Monoid[Box[Mul]]] assert(box.empty == Box(Mul(1))) assert(box.combine(Box(Mul(5)), Box(Mul(5))) == Box(Mul(25))) - } - locally { + locally: import auto.monoid.given validate("auto.monoid") - } - locally { + locally: import semiInstances.given validate("semiauto.monoid") - } - locally { + locally: + import strictInstances.given + validate("strict.semiauto.monoid") + testNoInstance("strict.semiauto.monoid", "Top") + + locally: import derivedInstances.* val instance = "derived.monoid" checkAll(s"$instance[Foo]", tests[Foo].monoid) checkAll(s"$instance[Interleaved[Int]]", tests[Interleaved[Int]].monoid) checkAll(s"$instance[BoxMul]", tests[BoxMul].monoid) checkAll(s"$instance is Serializable", SerializableTests.serializable(Monoid[Foo])) - } end MonoidSuite @@ -69,6 +70,12 @@ object MonoidSuite: given Monoid[Interleaved[Int]] = semiauto.monoid given Monoid[Box[Mul]] = semiauto.monoid + object strictInstances: + given Monoid[Foo] = strict.semiauto.monoid + given Monoid[Recursive] = strict.semiauto.monoid + given Monoid[Interleaved[Int]] = strict.semiauto.monoid + given Monoid[Box[Mul]] = strict.semiauto.monoid + object derivedInstances: case class Foo(x: ADTs.Foo) derives Monoid case class Interleaved[A](x: ADTs.Interleaved[A]) derives Monoid diff --git a/core/src/test/scala-3/cats/derived/NonEmptyTraverseSuite.scala b/core/src/test/scala-3/cats/derived/NonEmptyTraverseSuite.scala index dafa0c06..4f810459 100644 --- a/core/src/test/scala-3/cats/derived/NonEmptyTraverseSuite.scala +++ b/core/src/test/scala-3/cats/derived/NonEmptyTraverseSuite.scala @@ -16,9 +16,11 @@ package cats.derived -import cats.{Eq, NonEmptyTraverse} +import cats.{Eq, NonEmptyTraverse, Traverse} import cats.data.{NonEmptyList, OneAnd} import cats.laws.discipline.* +import shapeless3.deriving.Const + import scala.compiletime.* class NonEmptyTraverseSuite extends KittensSuite: @@ -82,6 +84,11 @@ class NonEmptyTraverseSuite extends KittensSuite: import semiInstances.given validate("semiauto.nonEmptyTraverse") + locally: + import strictInstances.given + validate("strict.semiauto.nonEmptyTraverse") + testNoInstance("strict.semiauto.nonEmptyTraverse", "TopK") + locally: import derivedInstances.* val instance = "derived.nonEmptyTraverse" @@ -132,6 +139,23 @@ object NonEmptyTraverseSuite: given NonEmptyTraverse[Singletons] = semiauto.nonEmptyTraverse given NonEmptyTraverse[Search] = semiauto.nonEmptyTraverse + object strictInstances: + given [T]: Traverse[Const[T]] = semiauto.traverse + given [F[_]: Traverse, G[_]: Traverse]: Traverse[[x] =>> F[G[x]]] = Traverse[F].compose[G] + given Traverse[IList] = strict.semiauto.traverse + given Traverse[Snoc] = strict.semiauto.traverse + given NonEmptyTraverse[ICons] = strict.semiauto.nonEmptyTraverse + given NonEmptyTraverse[SCons] = strict.semiauto.nonEmptyTraverse + given NonEmptyTraverse[Tree] = strict.semiauto.nonEmptyTraverse + given NonEmptyTraverse[NelSCons] = strict.semiauto.nonEmptyTraverse + given NonEmptyTraverse[NelAndOne] = strict.semiauto.nonEmptyTraverse + given NonEmptyTraverse[VecAndNel] = strict.semiauto.nonEmptyTraverse + given NonEmptyTraverse[Interleaved] = strict.semiauto.nonEmptyTraverse + given NonEmptyTraverse[EnumK1] = strict.semiauto.nonEmptyTraverse + given NonEmptyTraverse[AtLeastOne] = strict.semiauto.nonEmptyTraverse + given NonEmptyTraverse[Singletons] = strict.semiauto.nonEmptyTraverse + given NonEmptyTraverse[Search] = strict.semiauto.nonEmptyTraverse + object derivedInstances: case class ICons[A](x: ADTs.ICons[A]) derives NonEmptyTraverse case class Tree[A](x: ADTs.Tree[A]) derives NonEmptyTraverse diff --git a/core/src/test/scala-3/cats/derived/OrderSuite.scala b/core/src/test/scala-3/cats/derived/OrderSuite.scala index 0a26607c..04cbbb5f 100644 --- a/core/src/test/scala-3/cats/derived/OrderSuite.scala +++ b/core/src/test/scala-3/cats/derived/OrderSuite.scala @@ -45,6 +45,11 @@ class OrderSuite extends KittensSuite: import semiInstances.given validate("semiauto.order") + locally: + import strictInstances.given + validate("strict.semiauto.order") + testNoInstance("strict.semiauto.order", "Top") + locally: import derivedInstances.* val instance = "derived.order" @@ -71,6 +76,16 @@ object OrderSuite: given Order[EnumK0] = semiauto.order given Order[Singletons[Int]] = semiauto.order + object strictInstances: + given [A <: Singleton: ValueOf]: Order[A] = Order.allEqual + given Order[Inner] = strict.semiauto.order + given Order[Outer] = strict.semiauto.order + given Order[Interleaved[Int]] = strict.semiauto.order + given Order[Recursive] = strict.semiauto.order + given Order[GenericAdt[Int]] = strict.semiauto.order + given Order[EnumK0] = strict.semiauto.order + given Order[Singletons[Int]] = strict.semiauto.order + object derivedInstances: case class Inner(x: ADTs.Inner) derives Order case class Outer(x: ADTs.Outer) derives Order diff --git a/core/src/test/scala-3/cats/derived/PartialOrderSuite.scala b/core/src/test/scala-3/cats/derived/PartialOrderSuite.scala index 5e79575c..1917dc44 100644 --- a/core/src/test/scala-3/cats/derived/PartialOrderSuite.scala +++ b/core/src/test/scala-3/cats/derived/PartialOrderSuite.scala @@ -16,8 +16,9 @@ package cats.derived -import cats.PartialOrder +import cats.{Order, PartialOrder} import cats.kernel.laws.discipline.* + import scala.compiletime.* class PartialOrderSuite extends KittensSuite: @@ -54,6 +55,11 @@ class PartialOrderSuite extends KittensSuite: import semiInstances.given validate("semiauto.partialOrder") + locally: + import strictInstances.given + validate("strict.semiauto.partialOrder") + testNoInstance("strict.semiauto.partialOrder", "Top") + locally: import derivedInstances.* val instance = "derived.partialOrder" @@ -66,7 +72,7 @@ class PartialOrderSuite extends KittensSuite: checkAll(s"$instance[BoxKV]", tests[BoxKV].partialOrder) checkAll(s"$instance[EnumK0]", tests[EnumK0].partialOrder) checkAll(s"$instance[Singletons[Int]]", tests[Singletons[Int]].partialOrder) - checkAll(s"$instance is Serialiable", SerializableTests.serializable(PartialOrder[Tree[Int]])) + checkAll(s"$instance is Serializable", SerializableTests.serializable(PartialOrder[Tree[Int]])) end PartialOrderSuite @@ -84,6 +90,18 @@ object PartialOrderSuite: given PartialOrder[EnumK0] = semiauto.partialOrder given PartialOrder[Singletons[Int]] = semiauto.partialOrder + object strictInstances: + given [A <: Singleton: ValueOf]: PartialOrder[A] = Order.allEqual + given PartialOrder[IList[Int]] = strict.semiauto.partialOrder + given PartialOrder[Inner] = strict.semiauto.partialOrder + given PartialOrder[Outer] = strict.semiauto.partialOrder + given PartialOrder[Interleaved[Int]] = strict.semiauto.partialOrder + given PartialOrder[Tree[Int]] = strict.semiauto.partialOrder + given PartialOrder[Recursive] = strict.semiauto.partialOrder + given PartialOrder[Box[KeyValue]] = strict.semiauto.partialOrder + given PartialOrder[EnumK0] = strict.semiauto.partialOrder + given PartialOrder[Singletons[Int]] = strict.semiauto.partialOrder + object derivedInstances: case class IList[A](x: ADTs.IList[A]) derives PartialOrder case class Interleaved[A](x: ADTs.Interleaved[A]) derives PartialOrder diff --git a/core/src/test/scala-3/cats/derived/PureSuite.scala b/core/src/test/scala-3/cats/derived/PureSuite.scala index 19800820..655b2ad9 100644 --- a/core/src/test/scala-3/cats/derived/PureSuite.scala +++ b/core/src/test/scala-3/cats/derived/PureSuite.scala @@ -16,9 +16,11 @@ package cats.derived -import alleycats.Pure +import alleycats.{Empty, Pure} import cats.data.NonEmptyList import cats.laws.discipline.SerializableTests +import shapeless3.deriving.Const + import scala.compiletime.* class PureSuite extends KittensSuite: @@ -48,8 +50,15 @@ class PureSuite extends KittensSuite: locally: import semiInstances.given validate("semiauto.pure") - testNoInstance("Pure", "IList") - testNoInstance("Pure", "Snoc") + testNoInstance("semiauto.pure", "IList") + testNoInstance("semiauto.pure", "Snoc") + + locally: + import strictInstances.given + validate("strict.semiauto.pure") + testNoInstance("strict.semiauto.pure", "IList") + testNoInstance("strict.semiauto.pure", "Snoc") + testNoInstance("strict.semiauto.pure", "TopK") locally: import derivedInstances.* @@ -77,6 +86,17 @@ object PureSuite: given Pure[Singletons] = semiauto.pure given Pure[BoxColor] = semiauto.pure + object strictInstances: + given [T: Empty]: Pure[Const[T]] = semiauto.pure + given [T <: Singleton: ValueOf]: Pure[Const[T]] = semiauto.pure + given Pure[LOption] = semiauto.pure + given Pure[PList] = strict.semiauto.pure + given Pure[CaseClassWOption] = strict.semiauto.pure + given Pure[NelOption] = semiauto.pure + given Pure[Interleaved] = strict.semiauto.pure + given Pure[Singletons] = strict.semiauto.pure + given Pure[BoxColor] = strict.semiauto.pure + object derivedInstances: case class CaseClassWOption[A](x: ADTs.CaseClassWOption[A]) derives Pure case class Interleaved[A](x: ADTs.Interleaved[A]) derives Pure diff --git a/core/src/test/scala-3/cats/derived/ReducibleSuite.scala b/core/src/test/scala-3/cats/derived/ReducibleSuite.scala index 196778f4..aef62c7f 100644 --- a/core/src/test/scala-3/cats/derived/ReducibleSuite.scala +++ b/core/src/test/scala-3/cats/derived/ReducibleSuite.scala @@ -16,10 +16,12 @@ package cats.derived -import cats.{Eval, Reducible} +import cats.{Eval, Foldable, Reducible} import cats.data.{NonEmptyList, OneAnd} import cats.laws.discipline.* import cats.syntax.all.given +import shapeless3.deriving.Const + import scala.compiletime.* class ReducibleSuite extends KittensSuite: @@ -51,6 +53,11 @@ class ReducibleSuite extends KittensSuite: import semiInstances.given validate("semiauto.reducible") + locally: + import strictInstances.given + validate("strict.semiauto.reducible") + testNoInstance("strict.semiauto.reducible", "TopK") + locally: import derivedInstances.* val instance = "derived.reducible" @@ -85,6 +92,24 @@ object ReducibleSuite: given Reducible[Singletons] = semiauto.reducible given Reducible[Search] = semiauto.reducible + object strictInstances: + given [T]: Foldable[Const[T]] = semiauto.foldable + given [F[_]: Foldable, G[_]: Foldable]: Foldable[[x] =>> F[G[x]]] = Foldable[F].compose[G] + given Foldable[IList] = strict.semiauto.foldable + given Foldable[Snoc] = strict.semiauto.foldable + given Reducible[ICons] = strict.semiauto.reducible + given Reducible[SCons] = strict.semiauto.reducible + given Reducible[Tree] = strict.semiauto.reducible + given Reducible[NelSCons] = strict.semiauto.reducible + given Reducible[NelAndOne] = strict.semiauto.reducible + given Reducible[VecAndNel] = strict.semiauto.reducible + given Reducible[Interleaved] = strict.semiauto.reducible + given Reducible[BoxZipper] = strict.semiauto.reducible + given Reducible[EnumK1] = strict.semiauto.reducible + given Reducible[AtLeastOne] = strict.semiauto.reducible + given Reducible[Singletons] = strict.semiauto.reducible + given Reducible[Search] = strict.semiauto.reducible + object derivedInstances: case class ICons[A](x: ADTs.ICons[A]) derives Reducible case class Tree[A](x: ADTs.Tree[A]) derives Reducible diff --git a/core/src/test/scala-3/cats/derived/SemigroupKSuite.scala b/core/src/test/scala-3/cats/derived/SemigroupKSuite.scala index edf3c13a..7cb41d5a 100644 --- a/core/src/test/scala-3/cats/derived/SemigroupKSuite.scala +++ b/core/src/test/scala-3/cats/derived/SemigroupKSuite.scala @@ -1,7 +1,9 @@ package cats.derived -import cats.SemigroupK +import cats.{Apply, Eval, Semigroup, SemigroupK} import cats.laws.discipline.{SemigroupKTests, SerializableTests} +import shapeless3.deriving.Const + import scala.compiletime.* class SemigroupKSuite extends KittensSuite: @@ -16,28 +18,29 @@ class SemigroupKSuite extends KittensSuite: checkAll(s"$instance[CaseClassWOption]", tests[CaseClassWOption].semigroupK[Char]) checkAll(s"$instance[BoxMul]", tests[BoxMul].semigroupK[Char]) checkAll(s"$instance is Serializable", SerializableTests.serializable(summonInline[SemigroupK[ComplexProduct]])) - test(s"$instance respects existing instances") { + test(s"$instance respects existing instances"): assert(summonInline[SemigroupK[BoxMul]].combineK(Box(Mul[Char](5)), Box(Mul[Char](5))) == Box(Mul[Char](25))) - } - locally { + locally: import auto.semigroupK.given validate("auto.semigroupK") - } - locally { + locally: + import strictInstances.given + validate("strict.semiauto.semigroupK") + testNoInstance("strict.semiauto.semigroupK", "TopK") + + locally: import semiInstances.given validate("semiauto.semigroupK") - } - locally { + locally: import derivedInstances.* val instance = "derived.semigroupK" checkAll(s"$instance[ComplexProduct]", tests[ComplexProduct].semigroupK[Char]) checkAll(s"$instance[CaseClassWOption]", tests[CaseClassWOption].semigroupK[Char]) checkAll(s"$instance[Simple]", tests[Simple].semigroupK[Char]) checkAll(s"$instance is Serializable", SerializableTests.serializable(SemigroupK[ComplexProduct])) - } end SemigroupKSuite @@ -51,6 +54,14 @@ object SemigroupKSuite: given SemigroupK[CaseClassWOption] = semiauto.semigroupK given SemigroupK[BoxMul] = semiauto.semigroupK + object strictInstances: + given [T: Semigroup]: SemigroupK[Const[T]] = semiauto.semigroupK + given [F[_]: SemigroupK, G[_]]: SemigroupK[[x] =>> F[G[x]]] = SemigroupK[F].compose[G] + given [F[_]: Apply, G[_]: SemigroupK]: SemigroupK[[x] =>> F[G[x]]] = semiauto.semigroupK + given SemigroupK[ComplexProduct] = strict.semiauto.semigroupK + given SemigroupK[CaseClassWOption] = strict.semiauto.semigroupK + given SemigroupK[BoxMul] = strict.semiauto.semigroupK + object derivedInstances: case class ComplexProduct[A](x: ADTs.ComplexProduct[A]) derives SemigroupK case class CaseClassWOption[A](x: ADTs.CaseClassWOption[A]) derives SemigroupK diff --git a/core/src/test/scala-3/cats/derived/SemigroupSuite.scala b/core/src/test/scala-3/cats/derived/SemigroupSuite.scala index c11b75b1..11646b04 100644 --- a/core/src/test/scala-3/cats/derived/SemigroupSuite.scala +++ b/core/src/test/scala-3/cats/derived/SemigroupSuite.scala @@ -35,29 +35,30 @@ class SemigroupSuite extends KittensSuite: checkAll(s"$instances[Box[Mul]]", tests[Box[Mul]].semigroup) checkAll(s"$instances[Recursive]", tests[Recursive].semigroup) checkAll(s"$instances is Serializable", SerializableTests.serializable(summonInline[Semigroup[Foo]])) - test(s"$instances respects existing instances") { + test(s"$instances respects existing instances"): val box = summonInline[Semigroup[Box[Mul]]] assert(box.combine(Box(Mul(5)), Box(Mul(5))).content.value == 25) - } - locally { + locally: import auto.semigroup.given validate("auto.semigroup") - } - locally { + locally: import semiInstances.given validate("semiauto.semigroup") - } - locally { + locally: + import strictInstances.given + validate("strict.semiauto.semigroup") + testNoInstance("strict.semiauto.semigroup", "Top") + + locally: import derivedInstances.* val instances = "derived.semigroup" checkAll(s"$instances[Foo]", tests[Foo].semigroup) checkAll(s"$instances[Interleaved[Int]]", tests[Interleaved[Int]].semigroup) checkAll(s"$instances[BoxMul]", tests[BoxMul].semigroup) checkAll(s"$instances is Serializable", SerializableTests.serializable(Semigroup[Foo])) - } end SemigroupSuite @@ -70,6 +71,12 @@ object SemigroupSuite: given Semigroup[Interleaved[Int]] = semiauto.semigroup given Semigroup[Box[Mul]] = semiauto.semigroup + object strictInstances: + given Semigroup[Foo] = strict.semiauto.semigroup + given Semigroup[Recursive] = strict.semiauto.semigroup + given Semigroup[Interleaved[Int]] = strict.semiauto.semigroup + given Semigroup[Box[Mul]] = strict.semiauto.semigroup + object derivedInstances: case class Foo(x: ADTs.Foo) derives Semigroup case class Interleaved[A](x: ADTs.Interleaved[A]) derives Semigroup diff --git a/core/src/test/scala-3/cats/derived/ShowPrettySuite.scala b/core/src/test/scala-3/cats/derived/ShowPrettySuite.scala index ced9f73c..5cb8c90b 100644 --- a/core/src/test/scala-3/cats/derived/ShowPrettySuite.scala +++ b/core/src/test/scala-3/cats/derived/ShowPrettySuite.scala @@ -162,6 +162,11 @@ class ShowPrettySuite extends KittensSuite: import semiInstances.given validate("semiauto.showPretty") + locally: + import strictInstances.given + validate("strict.semiauto.showPretty") + testNoInstance("strict.semiauto.showPretty", "Top") + end ShowPrettySuite object ShowPrettySuite: @@ -187,6 +192,22 @@ object ShowPrettySuite: given ShowPretty[Singletons[Int]] = semiauto.showPretty given ShowPretty[Box[Bogus]] = semiauto.showPretty + object strictInstances: + given [A <: Singleton: ValueOf]: Show[A] = Show.fromToString + given ShowPretty[Foo] = strict.semiauto.showPretty + given ShowPretty[Inner] = strict.semiauto.showPretty + given ShowPretty[Outer] = strict.semiauto.showPretty + given ShowPretty[IntTree] = strict.semiauto.showPretty + given ShowPretty[GenericAdt[Int]] = strict.semiauto.showPretty + given ShowPretty[ContactInfo] = strict.semiauto.showPretty + given ShowPretty[People] = strict.semiauto.showPretty + given ShowPretty[ListFieldChild] = strict.semiauto.showPretty + given ShowPretty[ListField] = strict.semiauto.showPretty + given ShowPretty[Interleaved[Int]] = strict.semiauto.showPretty + given ShowPretty[Tree[Int]] = strict.semiauto.showPretty + given ShowPretty[Singletons[Int]] = strict.semiauto.showPretty + given ShowPretty[Box[Bogus]] = strict.semiauto.showPretty + object derivedInstances: case class Foo(x: ADTs.Foo) derives ShowPretty case class Outer(x: ADTs.Outer) derives ShowPretty diff --git a/core/src/test/scala-3/cats/derived/ShowSuite.scala b/core/src/test/scala-3/cats/derived/ShowSuite.scala index 9472b070..b72dedaf 100644 --- a/core/src/test/scala-3/cats/derived/ShowSuite.scala +++ b/core/src/test/scala-3/cats/derived/ShowSuite.scala @@ -83,6 +83,11 @@ class ShowSuite extends KittensSuite: import semiInstances.given validate("semiauto.show") + locally: + import strictInstances.given + validate("strict.semiauto.show") + testNoInstance("strict.semiauto.show", "Top") + end ShowSuite object ShowSuite: @@ -109,6 +114,23 @@ object ShowSuite: given Show[Box[Bogus]] = semiauto.show given Show[EnumK0] = semiauto.show + object strictInstances: + given [A <: Singleton: ValueOf]: Show[A] = Show.fromToString + given Show[Foo] = strict.semiauto.show + given Show[Inner] = strict.semiauto.show + given Show[Outer] = strict.semiauto.show + given Show[IntTree] = strict.semiauto.show + given Show[GenericAdt[Int]] = strict.semiauto.show + given Show[ContactInfo] = strict.semiauto.show + given Show[People] = strict.semiauto.show + given Show[ListFieldChild] = strict.semiauto.show + given Show[ListField] = strict.semiauto.show + given Show[Interleaved[Int]] = strict.semiauto.show + given Show[Tree[Int]] = strict.semiauto.show + given Show[Singletons[Int]] = strict.semiauto.show + given Show[Box[Bogus]] = strict.semiauto.show + given Show[EnumK0] = strict.semiauto.show + object derivedInstances: case class Foo(x: ADTs.Foo) derives Show case class Outer(x: ADTs.Outer) derives Show diff --git a/core/src/test/scala-3/cats/derived/TraverseSuite.scala b/core/src/test/scala-3/cats/derived/TraverseSuite.scala index 9bf28a0b..ca2ae778 100644 --- a/core/src/test/scala-3/cats/derived/TraverseSuite.scala +++ b/core/src/test/scala-3/cats/derived/TraverseSuite.scala @@ -2,6 +2,8 @@ package cats.derived import cats.{Eq, Traverse} import cats.laws.discipline.* +import shapeless3.deriving.Const + import scala.compiletime.* class TraverseSuite extends KittensSuite: @@ -35,6 +37,11 @@ class TraverseSuite extends KittensSuite: import semiInstances.given validate("semiauto.traverse") + locally: + import strictInstances.given + validate("strict.semiauto.traverse") + testNoInstance("strict.semiauto.traverse", "TopK") + locally: import derivedInstances.* val instance = "derived.traverse" @@ -73,6 +80,24 @@ object TraverseSuite: given Traverse[Singletons] = semiauto.traverse given Traverse[Search] = semiauto.traverse + object strictInstances: + given [T]: Traverse[Const[T]] = semiauto.traverse + given [F[_]: Traverse, G[_]: Traverse]: Traverse[[x] =>> F[G[x]]] = Traverse[F].compose[G] + given Traverse[Snoc] = strict.semiauto.traverse + given Traverse[IList] = strict.semiauto.traverse + given Traverse[Tree] = strict.semiauto.traverse + given Traverse[GenericAdt] = strict.semiauto.traverse + given Traverse[OptList] = strict.semiauto.traverse + given Traverse[ListSnoc] = strict.semiauto.traverse + given Traverse[AndChar] = strict.semiauto.traverse + given Traverse[Interleaved] = strict.semiauto.traverse + given Traverse[EnumK1] = strict.semiauto.traverse + given Traverse[Many] = strict.semiauto.traverse + given Traverse[AtLeastOne] = strict.semiauto.traverse + given Traverse[AtMostOne] = strict.semiauto.traverse + given Traverse[Singletons] = strict.semiauto.traverse + given Traverse[Search] = strict.semiauto.traverse + object derivedInstances: case class IList[A](x: ADTs.IList[A]) derives Traverse case class Tree[A](x: ADTs.Tree[A]) derives Traverse