From f6dcbd47815206b4b017eb0f1c0779bd56a7d6c1 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/6] 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 741430ca03..8811ff035a 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 37f75b3dae5928d6130cbc016fa5d516e027a51f 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 2/6] 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 8811ff035a..e3a0863a82 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 3e18524138..cfd0505031 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 09aebbd90220d5fad5c0dc6e4670a1d8dc5a16db 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 3/6] 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 e3a0863a82..a27b6763e8 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) -} """ From 40cebce285fb84cecaeeccb6b8e685286317d400 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Koz=C5=82owski?= Date: Tue, 5 May 2026 03:15:50 +0200 Subject: [PATCH 4/6] bump source breaking version --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index 411db18ae9..800da678cc 100644 --- a/build.sbt +++ b/build.sbt @@ -1,4 +1,4 @@ -ThisBuild / tlBaseVersion := "2.13" +ThisBuild / tlBaseVersion := "2.14" val scalaCheckVersion = "1.19.0" From 6188794b40fae2a2d2c3855acdce63bd5b47a75b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Koz=C5=82owski?= Date: Tue, 5 May 2026 03:22:37 +0200 Subject: [PATCH 5/6] format --- project/Boilerplate.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/Boilerplate.scala b/project/Boilerplate.scala index a27b6763e8..2ec12a4805 100644 --- a/project/Boilerplate.scala +++ b/project/Boilerplate.scala @@ -649,7 +649,7 @@ object Boilerplate { override def range = 2 to maxArity def content(tv: TemplateVals) = { - import tv._ + import tv.* val function = s"Function$arity[${`A..N`}, T]" From 6a1bb37352ca6d578bf846da4267ba656250d524 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Koz=C5=82owski?= Date: Tue, 5 May 2026 03:34:53 +0200 Subject: [PATCH 6/6] empty commit to kick ci for unrelated failure