From 59cc8181e3bd0adc97af23c596c150e8908a8f53 Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Thu, 28 Mar 2019 23:33:46 +0000 Subject: [PATCH] Replace machinist macros by plain forwarders Partial fix for #2553. After removing the machinist dependency, the build failed on simulacrum annotations because scala-reflect wasn't on the classpath anymore, so we add it as an explicit dependency. Co-authored-by: drdozer --- build.sbt | 6 +++-- core/src/main/scala/cats/syntax/eq.scala | 6 ++--- core/src/main/scala/cats/syntax/group.scala | 8 +++---- core/src/main/scala/cats/syntax/hash.scala | 4 +--- core/src/main/scala/cats/syntax/order.scala | 9 ++++---- .../main/scala/cats/syntax/partialOrder.scala | 18 +++++++-------- .../main/scala/cats/syntax/semigroup.scala | 8 +++---- docs/src/main/tut/faq.md | 7 ------ macros/src/main/scala/cats/macros/Ops.scala | 22 ------------------- 9 files changed, 25 insertions(+), 63 deletions(-) delete mode 100644 macros/src/main/scala/cats/macros/Ops.scala diff --git a/build.sbt b/build.sbt index 5284ccfef1..67f1a8a5dd 100644 --- a/build.sbt +++ b/build.sbt @@ -99,13 +99,15 @@ def macroDependencies(scalaVersion: String) = lazy val catsSettings = Seq( incOptions := incOptions.value.withLogRecompileOnMacro(false), libraryDependencies ++= Seq( - "org.typelevel" %%% "machinist" % "0.6.8", compilerPlugin("org.typelevel" %% "kind-projector" % kindProjectorVersion) ) ++ macroDependencies(scalaVersion.value) ) ++ commonSettings ++ publishSettings ++ scoverageSettings ++ simulacrumSettings lazy val simulacrumSettings = Seq( - libraryDependencies += "com.github.mpilquist" %%% "simulacrum" % "0.19.0" % Provided, + libraryDependencies ++= Seq( + scalaOrganization.value % "scala-reflect" % scalaVersion.value % Provided, + "com.github.mpilquist" %%% "simulacrum" % "0.19.0" % Provided + ), pomPostProcess := { (node: xml.Node) => new RuleTransformer(new RewriteRule { override def transform(node: xml.Node): Seq[xml.Node] = node match { diff --git a/core/src/main/scala/cats/syntax/eq.scala b/core/src/main/scala/cats/syntax/eq.scala index fed77872a7..66130d300e 100644 --- a/core/src/main/scala/cats/syntax/eq.scala +++ b/core/src/main/scala/cats/syntax/eq.scala @@ -1,8 +1,6 @@ package cats package syntax -import cats.macros.Ops - trait EqSyntax { /** not final so it can be disabled in favor of scalactic equality in tests */ @@ -11,8 +9,8 @@ trait EqSyntax { } final class EqOps[A: Eq](lhs: A) { - def ===(rhs: A): Boolean = macro Ops.binop[A, Boolean] - def =!=(rhs: A): Boolean = macro Ops.binop[A, Boolean] + def ===(rhs: A): Boolean = Eq[A].eqv(lhs, rhs) + def =!=(rhs: A): Boolean = Eq[A].neqv(lhs, rhs) def eqv(rhs: A): Boolean = Eq[A].eqv(lhs, rhs) def neqv(rhs: A): Boolean = Eq[A].neqv(lhs, rhs) } diff --git a/core/src/main/scala/cats/syntax/group.scala b/core/src/main/scala/cats/syntax/group.scala index 01d29cf3ae..f8214d42ea 100644 --- a/core/src/main/scala/cats/syntax/group.scala +++ b/core/src/main/scala/cats/syntax/group.scala @@ -1,8 +1,6 @@ package cats package syntax -import cats.macros.Ops - trait GroupSyntax extends SemigroupSyntax { // TODO: use simulacrum instances eventually implicit final def catsSyntaxGroup[A: Group](a: A): GroupOps[A] = @@ -10,7 +8,7 @@ trait GroupSyntax extends SemigroupSyntax { } final class GroupOps[A: Group](lhs: A) { - def |-|(rhs: A): A = macro Ops.binop[A, A] - def remove(rhs: A): A = macro Ops.binop[A, A] - def inverse(): A = macro Ops.unop[A] + def |-|(rhs: A): A = Group[A].remove(lhs, rhs) + def remove(rhs: A): A = Group[A].remove(lhs, rhs) + def inverse(): A = Group[A].inverse(lhs) } diff --git a/core/src/main/scala/cats/syntax/hash.scala b/core/src/main/scala/cats/syntax/hash.scala index 93333515f1..ff2595f2d4 100644 --- a/core/src/main/scala/cats/syntax/hash.scala +++ b/core/src/main/scala/cats/syntax/hash.scala @@ -1,8 +1,6 @@ package cats package syntax -import cats.macros.Ops - trait HashSyntax { implicit def catsSyntaxHash[A: Hash](a: A): HashOps[A] = @@ -15,5 +13,5 @@ final class HashOps[A: Hash](a: A) { /** * Gets the hash code of this object given an implicit `Hash` instance. */ - def hash: Int = macro Ops.unop0[Int] + def hash: Int = Hash[A].hash(a) } diff --git a/core/src/main/scala/cats/syntax/order.scala b/core/src/main/scala/cats/syntax/order.scala index 36c33386a3..f49ab378c3 100644 --- a/core/src/main/scala/cats/syntax/order.scala +++ b/core/src/main/scala/cats/syntax/order.scala @@ -1,7 +1,6 @@ package cats package syntax -import cats.macros.Ops import cats.kernel.Comparison trait OrderSyntax extends PartialOrderSyntax { @@ -10,8 +9,8 @@ trait OrderSyntax extends PartialOrderSyntax { } final class OrderOps[A: Order](lhs: A) { - def compare(rhs: A): Int = macro Ops.binop[A, Int] - def min(rhs: A): A = macro Ops.binop[A, A] - def max(rhs: A): A = macro Ops.binop[A, A] - def comparison(rhs: A): Comparison = macro Ops.binop[A, Comparison] + def compare(rhs: A): Int = Order[A].compare(lhs, rhs) + def min(rhs: A): A = Order[A].min(lhs, rhs) + def max(rhs: A): A = Order[A].max(lhs, rhs) + def comparison(rhs: A): Comparison = Order[A].comparison(lhs, rhs) } diff --git a/core/src/main/scala/cats/syntax/partialOrder.scala b/core/src/main/scala/cats/syntax/partialOrder.scala index 3e5d2e0489..7a4b38c04a 100644 --- a/core/src/main/scala/cats/syntax/partialOrder.scala +++ b/core/src/main/scala/cats/syntax/partialOrder.scala @@ -1,21 +1,19 @@ package cats package syntax -import cats.macros.Ops - trait PartialOrderSyntax extends EqSyntax { implicit final def catsSyntaxPartialOrder[A: PartialOrder](a: A): PartialOrderOps[A] = new PartialOrderOps[A](a) } final class PartialOrderOps[A](lhs: A)(implicit A: PartialOrder[A]) { - def >(rhs: A): Boolean = macro Ops.binop[A, Boolean] - def >=(rhs: A): Boolean = macro Ops.binop[A, Boolean] - def <(rhs: A): Boolean = macro Ops.binop[A, Boolean] - def <=(rhs: A): Boolean = macro Ops.binop[A, Boolean] + def >(rhs: A): Boolean = A.gt(lhs, rhs) + def >=(rhs: A): Boolean = A.gteqv(lhs, rhs) + def <(rhs: A): Boolean = A.lt(lhs, rhs) + def <=(rhs: A): Boolean = A.lteqv(lhs, rhs) - def partialCompare(rhs: A): Double = macro Ops.binop[A, Double] - def tryCompare(rhs: A): Option[Int] = macro Ops.binop[A, Option[Int]] - def pmin(rhs: A): Option[A] = macro Ops.binop[A, Option[A]] - def pmax(rhs: A): Option[A] = macro Ops.binop[A, Option[A]] + def partialCompare(rhs: A): Double = A.partialCompare(lhs, rhs) + def tryCompare(rhs: A): Option[Int] = A.tryCompare(lhs, rhs) + def pmin(rhs: A): Option[A] = A.pmin(lhs, rhs) + def pmax(rhs: A): Option[A] = A.pmax(lhs, rhs) } diff --git a/core/src/main/scala/cats/syntax/semigroup.scala b/core/src/main/scala/cats/syntax/semigroup.scala index 54338b7ff0..7afd259086 100644 --- a/core/src/main/scala/cats/syntax/semigroup.scala +++ b/core/src/main/scala/cats/syntax/semigroup.scala @@ -1,8 +1,6 @@ package cats package syntax -import cats.macros.Ops - trait SemigroupSyntax { // TODO: use simulacrum instances eventually implicit final def catsSyntaxSemigroup[A: Semigroup](a: A): SemigroupOps[A] = @@ -10,7 +8,7 @@ trait SemigroupSyntax { } final class SemigroupOps[A: Semigroup](lhs: A) { - def |+|(rhs: A): A = macro Ops.binop[A, A] - def combine(rhs: A): A = macro Ops.binop[A, A] - def combineN(rhs: Int): A = macro Ops.binop[A, A] + def |+|(rhs: A): A = Semigroup[A].combine(lhs, rhs) + def combine(rhs: A): A = Semigroup[A].combine(lhs, rhs) + def combineN(rhs: Int): A = Semigroup[A].combineN(lhs, rhs) } diff --git a/docs/src/main/tut/faq.md b/docs/src/main/tut/faq.md index 5533bbd777..23485eb7b0 100644 --- a/docs/src/main/tut/faq.md +++ b/docs/src/main/tut/faq.md @@ -21,7 +21,6 @@ position: 40 * [Where is `IO`/`Task`?](#task) * [What does `@typeclass` mean?](#simulacrum) * [What do types like `?` and `λ` mean?](#kind-projector) - * [What does `macro Ops` do? What is `cats.macros.Ops`?](#machinist) * [What is `tailRecM`?](#tailrecm) * [What does this symbol mean?](#symbol) * [How can I test instances against their type classes' laws?](#law-testing) @@ -155,12 +154,6 @@ Cats defines a wealth of type classes and type class instances. For a number of **Enter [kind-projector](https://github.com/non/kind-projector)!** kind-projector is a compiler plugin which provides a convenient syntax for dealing with type lambdas. The symbols `?` and `λ` are treated specially by kind-projector, and expanded into the more verbose definitions that would be required were it not to be used. You can read more about kind-projector at the [project page](https://github.com/non/kind-projector). -## What does `macro Ops` do? What is `cats.macros.Ops`? - -`macro Ops` invokes the [Machinist](https://github.com/typelevel/machinist) Ops macro, and is used in Cats in a number of places to enrich types with operations with the minimal possible cost when those operations are called in code. Machinist supports an extension mechanism where users of the macro can provide a mapping between symbolic operator names and method names. The `cats.macros.Ops` class uses this extension mechanism to supply the set of mappings that the Cats project is interested in. - -More about the history of machinist and how it works can be discovered at the [project page](https://github.com/typelevel/machinist), or [this article on the typelevel blog](http://typelevel.org/blog/2013/10/13/spires-ops-macros.html). - ## What is `tailRecM`? The `FlatMap` type class has a `tailRecM` method with the following signature: diff --git a/macros/src/main/scala/cats/macros/Ops.scala b/macros/src/main/scala/cats/macros/Ops.scala deleted file mode 100644 index 0a832019bb..0000000000 --- a/macros/src/main/scala/cats/macros/Ops.scala +++ /dev/null @@ -1,22 +0,0 @@ -package cats -package macros - -import scala.reflect.NameTransformer - -object Ops extends machinist.Ops { - - val operatorNames: Map[String, String] = - List( - ("===", "eqv"), - ("=!=", "neqv"), - (">", "gt"), - (">=", "gteqv"), - ("<", "lt"), - ("<=", "lteqv"), - ("|+|", "combine"), - ("|-|", "remove") - ).map { - case (k, v) => - (NameTransformer.encode(k), v) - }.toMap -}