diff --git a/binCompatTest/src/main/scala/catsBC/MimaExceptions.scala b/binCompatTest/src/main/scala/catsBC/MimaExceptions.scala index d76fcc94f3..8beaa353be 100644 --- a/binCompatTest/src/main/scala/catsBC/MimaExceptions.scala +++ b/binCompatTest/src/main/scala/catsBC/MimaExceptions.scala @@ -1,12 +1,14 @@ package catsBC import cats.implicits._ -import cats._, data._, cats.arrow._ object MimaExceptions { - import cats.implicits._ + + def headOption[A](list: List[A]): Option[A] = list.headOption + + import cats.arrow.FunctionK // needs to be imported because of a hygiene problem def isBinaryCompatible = ( - Monad[OptionT[List, ?]], + cats.Monad[cats.data.OptionT[List, ?]], cats.data.OptionT.catsDataTraverseForOptionT[List], cats.data.Kleisli.catsDataCommutativeArrowForKleisliId, cats.data.OptionT.catsDataMonoidKForOptionT[List], @@ -15,7 +17,8 @@ object MimaExceptions { cats.data.Kleisli.catsDataCommutativeArrowForKleisli[Option], cats.data.Kleisli.catsDataCommutativeFlatMapForKleisli[Option, Int], cats.data.IRWST.catsDataStrongForIRWST[List, Int, Int, Int], - cats.data.OptionT.catsDataMonadErrorMonadForOptionT[List] + cats.data.OptionT.catsDataMonadErrorMonadForOptionT[List], + FunctionK.lift(headOption) ) } diff --git a/build.sbt b/build.sbt index 1f5dc5bef7..2317950cc3 100644 --- a/build.sbt +++ b/build.sbt @@ -280,6 +280,12 @@ def mimaSettings(moduleName: String) = { exclude[DirectMissingMethodProblem]("cats.data.KleisliInstances4.catsDataCommutativeFlatMapForKleisli"), exclude[DirectMissingMethodProblem]("cats.data.IRWSTInstances1.catsDataStrongForIRWST"), exclude[DirectMissingMethodProblem]("cats.data.OptionTInstances1.catsDataMonadErrorMonadForOptionT") + ) ++ // Only compile-time abstractions (macros) allowed here + Seq( + exclude[IncompatibleMethTypeProblem]("cats.arrow.FunctionKMacros.lift"), + exclude[MissingTypesProblem]("cats.arrow.FunctionKMacros$"), + exclude[IncompatibleMethTypeProblem]("cats.arrow.FunctionKMacros#Lifter.this"), + exclude[IncompatibleResultTypeProblem]("cats.arrow.FunctionKMacros#Lifter.c") ) } ) @@ -516,10 +522,10 @@ lazy val binCompatTest = project else //We are not testing BC on Scala 2.13 yet. "org.typelevel" %% "cats-core" % version.value % Provided }, - "org.typelevel" %% "cats-core" % version.value % Test, "org.scalatest" %%% "scalatest" % scalatestVersion(scalaVersion.value) % Test ) ) + .dependsOn(coreJVM % Test) // cats-js is JS-only @@ -639,7 +645,7 @@ addCommandAlias("buildAlleycatsJVM", ";alleycatsCoreJVM/test;alleycatsLawsJVM/te addCommandAlias("buildJVM", ";buildKernelJVM;buildCoreJVM;buildTestsJVM;buildFreeJVM;buildAlleycatsJVM") -addCommandAlias("validateBC", ";catsJVM/publishLocal;binCompatTest/test;mimaReportBinaryIssues") +addCommandAlias("validateBC", ";binCompatTest/test;mimaReportBinaryIssues") addCommandAlias("validateJVM", ";scalastyle;buildJVM;bench/test;validateBC;makeMicrosite") diff --git a/core/src/main/scala/cats/arrow/FunctionK.scala b/core/src/main/scala/cats/arrow/FunctionK.scala index a7aa6cd47e..2316a71ce6 100644 --- a/core/src/main/scala/cats/arrow/FunctionK.scala +++ b/core/src/main/scala/cats/arrow/FunctionK.scala @@ -1,9 +1,9 @@ package cats package arrow -import cats.data.{EitherK, Tuple2K} +import scala.reflect.macros.blackbox.Context -import cats.macros.MacroCompat +import cats.data.{EitherK, Tuple2K} /** * `FunctionK[F[_], G[_]]` is a functor transformation from `F` to `G` @@ -95,7 +95,7 @@ object FunctionK { } -private[arrow] object FunctionKMacros extends MacroCompat { +private[arrow] object FunctionKMacros { def lift[F[_], G[_]](c: Context)( f: c.Expr[(F[α] ⇒ G[α]) forSome { type α }] @@ -124,7 +124,7 @@ private[arrow] object FunctionKMacros extends MacroCompat { val G = punchHole(evG.tpe) q""" - new FunctionK[$F, $G] { + new _root_.cats.arrow.FunctionK[$F, $G] { def apply[A](fa: $F[A]): $G[A] = $trans(fa) } """ @@ -139,7 +139,7 @@ private[arrow] object FunctionKMacros extends MacroCompat { private[this] def punchHole(tpe: Type): Tree = tpe match { case PolyType(undet :: Nil, underlying: TypeRef) ⇒ - val α = compatNewTypeName(c, "α") + val α = TypeName("α") def rebind(typeRef: TypeRef): Tree = if (typeRef.sym == undet) tq"$α" else { diff --git a/macros/src/main/scala/cats/macros/compat.scala b/macros/src/main/scala/cats/macros/compat.scala deleted file mode 100644 index 54f4ddd8fc..0000000000 --- a/macros/src/main/scala/cats/macros/compat.scala +++ /dev/null @@ -1,15 +0,0 @@ -package cats -package macros - -/** Macro compatibility. - * - * Used only to push deprecation errors in core off into - * the macros project, as warnings. - */ -private[cats] class MacroCompat { - - type Context = reflect.macros.Context - def compatNewTypeName(c: Context, name: String): c.TypeName = - c.universe.newTypeName(name) - -} diff --git a/tests/src/test/scala/cats/tests/FunctionKSuite.scala b/tests/src/test/scala/cats/tests/FunctionKSuite.scala index bdb7816be8..cc73ef4e3b 100644 --- a/tests/src/test/scala/cats/tests/FunctionKSuite.scala +++ b/tests/src/test/scala/cats/tests/FunctionKSuite.scala @@ -82,6 +82,15 @@ class FunctionKSuite extends CatsSuite { } } + test("hygiene") { + trait FunctionK + def optionToList[A](option: Option[A]): List[A] = option.toList + val fOptionToList = cats.arrow.FunctionK.lift(optionToList _) + forAll { (a: Option[Int]) => + fOptionToList(a) should === (optionToList(a)) + } + } + test("lift compound unary") { val fNelFromList = FunctionK.lift[List, λ[α ⇒ Option[NonEmptyList[α]]]](NonEmptyList.fromList _) forAll { (a: List[String]) =>