diff --git a/core/src/main/scala/cats/arrow/FunctionK.scala b/core/src/main/scala/cats/arrow/FunctionK.scala index 019c27d232..413f72a501 100644 --- a/core/src/main/scala/cats/arrow/FunctionK.scala +++ b/core/src/main/scala/cats/arrow/FunctionK.scala @@ -89,74 +89,14 @@ object FunctionK { * * Additionally, the type parameters on `f` must not be specified. */ - def lift[F[_], G[_]](f: (F[α] ⇒ G[α]) forSome { type α }): FunctionK[F, G] = - macro FunctionKMacros.lift[F, G] + def lift[F[_]]: LiftPartiallyApplied[F] = new LiftPartiallyApplied -} - -private[arrow] object FunctionKMacros { - - def lift[F[_], G[_]](c: Context)( - f: c.Expr[(F[α] ⇒ G[α]) forSome { type α }] - )( - implicit evF: c.WeakTypeTag[F[_]], - evG: c.WeakTypeTag[G[_]] - ): c.Expr[FunctionK[F, G]] = - c.Expr[FunctionK[F, G]](new Lifter[c.type](c).lift[F, G](f.tree)) - // ^^note: extra space after c.type to appease scalastyle - - private[this] class Lifter[C <: Context](val c: C) { - import c.universe._ - - def lift[F[_], G[_]](tree: Tree)( - implicit evF: c.WeakTypeTag[F[_]], - evG: c.WeakTypeTag[G[_]] - ): Tree = unblock(tree) match { - case q"($param) => $trans[..$typeArgs](${arg: Ident})" if param.name == arg.name ⇒ - typeArgs - .collect { case tt: TypeTree => tt } - .find(tt => Option(tt.original).isDefined) - .foreach { param => - c.abort(param.pos, s"type parameter $param must not be supplied when lifting function $trans to FunctionK") - } - - val F = punchHole(evF.tpe) - val G = punchHole(evG.tpe) + private[arrow] final class LiftPartiallyApplied[F[_]](val dummy: Boolean = true) extends AnyVal { + type T - q""" - new _root_.cats.arrow.FunctionK[$F, $G] { - def apply[A](fa: $F[A]): $G[A] = $trans(fa) - } - """ - case other ⇒ - c.abort(other.pos, s"Unexpected tree $other when lifting to FunctionK") + def apply[G[_]](f: F[T] => G[T]): FunctionK[F, G] = new FunctionK[F, G] { + def apply[A](fa: F[A]): G[A] = f(fa.asInstanceOf[F[T]]).asInstanceOf[G[A]] } - - private[this] def unblock(tree: Tree): Tree = tree match { - case Block(Nil, expr) ⇒ expr - case _ ⇒ tree - } - - private[this] def punchHole(tpe: Type): Tree = tpe match { - case PolyType(undet :: Nil, underlying: TypeRef) ⇒ - val α = TypeName("α") - def rebind(typeRef: TypeRef): Tree = - if (typeRef.sym == undet) tq"$α" - else { - val args = typeRef.args.map { - case ref: TypeRef => rebind(ref) - case arg => tq"$arg" - } - tq"${typeRef.sym}[..$args]" - } - val rebound = rebind(underlying) - tq"""({type λ[$α] = $rebound})#λ""" - case TypeRef(pre, sym, Nil) ⇒ - tq"$sym" - case _ => - c.abort(c.enclosingPosition, s"Unexpected type $tpe when lifting to FunctionK") - } - } } diff --git a/core/src/main/scala/cats/syntax/eq.scala b/core/src/main/scala/cats/syntax/eq.scala index fed77872a7..01a6eb87bc 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,11 @@ 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 = implicitly[Eq[A]].eqv(lhs, rhs) + def =!=(rhs: A): Boolean = implicitly[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..27df00f6b6 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 = implicitly[Group[A]].remove(lhs, rhs) + def remove(rhs: A): A = implicitly[Group[A]].remove(lhs, rhs) + def inverse(): A = implicitly[Group[A]].inverse(lhs) } diff --git a/core/src/main/scala/cats/syntax/order.scala b/core/src/main/scala/cats/syntax/order.scala index 36c33386a3..99d1c281ee 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 = implicitly[Order[A]].compare(lhs, rhs) + def min(rhs: A): A = implicitly[Order[A]].min(lhs, rhs) + def max(rhs: A): A = implicitly[Order[A]].max(lhs, rhs) + def comparison(rhs: A): Comparison = implicitly[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..008da0802c 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 = implicitly[Semigroup[A]].combine(lhs, rhs) + def combine(rhs: A): A = implicitly[Semigroup[A]].combine(lhs, rhs) + def combineN(rhs: Int): A = implicitly[Semigroup[A]].combineN(lhs, rhs) }