From c04ea663eca5ad6c5ad39859cccdb0588310310f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Koz=C5=82owski?= Date: Tue, 21 Jan 2025 00:45:27 +0100 Subject: [PATCH 1/4] Widen parLiftN's constraint to NonEmptyParallel --- project/Boilerplate.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/Boilerplate.scala b/project/Boilerplate.scala index 58955aa3c4..c912eaa68b 100644 --- a/project/Boilerplate.scala +++ b/project/Boilerplate.scala @@ -639,7 +639,7 @@ object Boilerplate { | -private[syntax] final class Function${arity}ApplyOps[T, ${`A..N`}](private val f: $function) extends AnyVal with Serializable { - def liftN[F[_]: Functor: Semigroupal]($typedParams): F[T] = Semigroupal.map$arity(${`a..n`})(f) - - def parLiftN[F[_]: Parallel]($typedParams): F[T] = Parallel.parMap$arity(${`a..n`})(f) + - def parLiftN[F[_]: NonEmptyParallel]($typedParams): F[T] = Parallel.parMap$arity(${`a..n`})(f) -} """ } From eb5a531b6ea48003164c940b094ac4eb39a9074a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Koz=C5=82owski?= Date: Tue, 21 Jan 2025 00:49:41 +0100 Subject: [PATCH 2/4] new base who dis? --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index 3d7293d477..3703da6f74 100644 --- a/build.sbt +++ b/build.sbt @@ -1,4 +1,4 @@ -ThisBuild / tlBaseVersion := "2.12" +ThisBuild / tlBaseVersion := "2.13" val scalaCheckVersion = "1.18.1" From 547dd8588d31444827d2712c73d62b2605f2b4a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Koz=C5=82owski?= Date: Tue, 21 Jan 2025 01:13:56 +0100 Subject: [PATCH 3/4] mima hacks --- core/src/main/scala/cats/syntax/apply.scala | 2 +- project/Boilerplate.scala | 34 +++++++++++++++++-- .../test/scala/cats/tests/SyntaxSuite.scala | 24 +++++++++++++ 3 files changed, 56 insertions(+), 4 deletions(-) diff --git a/core/src/main/scala/cats/syntax/apply.scala b/core/src/main/scala/cats/syntax/apply.scala index dcb0d95a67..55fd2fd87e 100644 --- a/core/src/main/scala/cats/syntax/apply.scala +++ b/core/src/main/scala/cats/syntax/apply.scala @@ -22,7 +22,7 @@ package cats package syntax -trait ApplySyntax extends TupleSemigroupalSyntax with FunctionApplySyntax { +trait ApplySyntax extends TupleSemigroupalSyntax with FunctionApplySyntax with FunctionApplySyntax2 { @deprecated("Kept for binary compatibility", "2.10.0") final def catsSyntaxApply[F[_], A](fa: F[A], F: Apply[F]): Apply.Ops[F, A] = new Apply.Ops[F, A] { diff --git a/project/Boilerplate.scala b/project/Boilerplate.scala index c912eaa68b..a902bb9011 100644 --- a/project/Boilerplate.scala +++ b/project/Boilerplate.scala @@ -33,6 +33,7 @@ object Boilerplate { GenParallelArityFunctions2, GenFoldableArityFunctions, GenFunctionSyntax, + GenFunctionSyntax2, GenTupleParallelSyntax, GenTupleShowInstances, GenTupleMonadInstances, @@ -624,9 +625,6 @@ object Boilerplate { |package cats |package syntax | - |import cats.Functor - |import cats.Semigroupal - | |trait FunctionApplySyntax { | implicit def catsSyntaxFunction1Apply[T, A0](f: Function1[A0, T]): Function1ApplyOps[T, A0] = new Function1ApplyOps(f) - implicit def catsSyntaxFunction${arity}Apply[T, ${`A..N`}](f: $function): Function${arity}ApplyOps[T, ${`A..N`}] = new Function${arity}ApplyOps(f) @@ -639,6 +637,36 @@ object Boilerplate { | -private[syntax] final class Function${arity}ApplyOps[T, ${`A..N`}](private val f: $function) extends AnyVal with Serializable { - def liftN[F[_]: Functor: Semigroupal]($typedParams): F[T] = Semigroupal.map$arity(${`a..n`})(f) + - private[syntax] def parLiftN[F[_]: Parallel]($typedParams): F[T] = Parallel.parMap$arity(${`a..n`})(f) + -} + """ + } + } + + object GenFunctionSyntax2 extends Template { + def filename(root: File) = root / "cats" / "syntax" / "FunctionApplySyntax2.scala" + + override def range = 2 to maxArity + + def content(tv: TemplateVals) = { + import tv._ + + val function = s"Function$arity[${`A..N`}, T]" + + val typedParams = synVals.zip(synTypes).map { case (v, t) => s"$v: F[$t]" }.mkString(", ") + + // arity 1 left out intentionally, for it's part of GenFunctionSyntax already. + // SyntaxSuite ensures that it exists. + + block""" + |package cats + |package syntax + | + |trait FunctionApplySyntax2 { + - implicit def catsSyntaxFunction${arity}Apply2[T, ${`A..N`}](f: $function): Function${arity}ApplyOps2[T, ${`A..N`}] = new Function${arity}ApplyOps2(f) + |} + | + -private[syntax] final class Function${arity}ApplyOps2[T, ${`A..N`}](private val f: $function) extends AnyVal with Serializable { - def parLiftN[F[_]: NonEmptyParallel]($typedParams): F[T] = Parallel.parMap$arity(${`a..n`})(f) -} """ diff --git a/tests/shared/src/test/scala/cats/tests/SyntaxSuite.scala b/tests/shared/src/test/scala/cats/tests/SyntaxSuite.scala index 2b7f19277d..53ff1c14b0 100644 --- a/tests/shared/src/test/scala/cats/tests/SyntaxSuite.scala +++ b/tests/shared/src/test/scala/cats/tests/SyntaxSuite.scala @@ -345,6 +345,30 @@ object SyntaxSuite { result3: F[T] } + def testParLiftNNonEmpty[F[_]: NonEmptyParallel: Functor, A, B, C, T] = { + val fa = mock[F[A]] + val fb = mock[F[B]] + val fc = mock[F[C]] + + val fapply1 = mock[A => T] + + val result1 = fapply1.parLiftN(fa) + + result1: F[T] + + val fapply2 = mock[(A, B) => T] + + val result2 = fapply2.parLiftN(fa, fb) + + result2: F[T] + + val fapply3 = mock[(A, B, C) => T] + + val result3 = fapply3.parLiftN(fa, fb, fc) + + result3: F[T] + } + def testParallelBi[M[_], F[_], T[_, _]: Bitraverse, A, B, C, D](implicit P: Parallel.Aux[M, F]): Unit = { val tab = mock[T[A, B]] val f = mock[A => M[C]] From 2d82b53c0a79a3a806684b31e779566455ad2847 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Koz=C5=82owski?= Date: Tue, 21 Jan 2025 01:24:02 +0100 Subject: [PATCH 4/4] proper mima workaround --- project/Boilerplate.scala | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/project/Boilerplate.scala b/project/Boilerplate.scala index a902bb9011..b773de55e8 100644 --- a/project/Boilerplate.scala +++ b/project/Boilerplate.scala @@ -626,8 +626,8 @@ object Boilerplate { |package syntax | |trait FunctionApplySyntax { - | implicit def catsSyntaxFunction1Apply[T, A0](f: Function1[A0, T]): Function1ApplyOps[T, A0] = new Function1ApplyOps(f) - - implicit def catsSyntaxFunction${arity}Apply[T, ${`A..N`}](f: $function): Function${arity}ApplyOps[T, ${`A..N`}] = new Function${arity}ApplyOps(f) + | def catsSyntaxFunction1Apply[T, A0](f: Function1[A0, T]): Function1ApplyOps[T, A0] = new Function1ApplyOps(f) + - def catsSyntaxFunction${arity}Apply[T, ${`A..N`}](f: $function): Function${arity}ApplyOps[T, ${`A..N`}] = new Function${arity}ApplyOps(f) |} | |private[syntax] final class Function1ApplyOps[T, A0](private val f: Function1[A0, T]) extends AnyVal with Serializable { @@ -637,7 +637,7 @@ object Boilerplate { | -private[syntax] final class Function${arity}ApplyOps[T, ${`A..N`}](private val f: $function) extends AnyVal with Serializable { - def liftN[F[_]: Functor: Semigroupal]($typedParams): F[T] = Semigroupal.map$arity(${`a..n`})(f) - - private[syntax] def parLiftN[F[_]: Parallel]($typedParams): F[T] = Parallel.parMap$arity(${`a..n`})(f) + - def parLiftN[F[_]: Parallel]($typedParams): F[T] = Parallel.parMap$arity(${`a..n`})(f) -} """ } @@ -655,18 +655,22 @@ object Boilerplate { val typedParams = synVals.zip(synTypes).map { case (v, t) => s"$v: F[$t]" }.mkString(", ") - // arity 1 left out intentionally, for it's part of GenFunctionSyntax already. - // SyntaxSuite ensures that it exists. - block""" |package cats |package syntax | |trait FunctionApplySyntax2 { + | implicit def catsSyntaxFunction1Apply2[T, A0](f: Function1[A0, T]): Function1ApplyOps2[T, A0] = new Function1ApplyOps2(f) - implicit def catsSyntaxFunction${arity}Apply2[T, ${`A..N`}](f: $function): Function${arity}ApplyOps2[T, ${`A..N`}] = new Function${arity}ApplyOps2(f) |} + | + |private[syntax] final class Function1ApplyOps2[T, A0](private val f: Function1[A0, T]) extends AnyVal with Serializable { + | def liftN[F[_]: Functor](a0: F[A0]): F[T] = Functor[F].map(a0)(f) + | def parLiftN[F[_]: Functor](a0: F[A0]): F[T] = Functor[F].map(a0)(f) + |} | -private[syntax] final class Function${arity}ApplyOps2[T, ${`A..N`}](private val f: $function) extends AnyVal with Serializable { + - def liftN[F[_]: Functor: Semigroupal]($typedParams): F[T] = Semigroupal.map$arity(${`a..n`})(f) - def parLiftN[F[_]: NonEmptyParallel]($typedParams): F[T] = Parallel.parMap$arity(${`a..n`})(f) -} """