diff --git a/core/src/main/scala/cats/arrow/FunctionK.scala b/core/src/main/scala/cats/arrow/FunctionK.scala index af628dca051..612286649fb 100644 --- a/core/src/main/scala/cats/arrow/FunctionK.scala +++ b/core/src/main/scala/cats/arrow/FunctionK.scala @@ -1,7 +1,6 @@ package cats package arrow -import scala.reflect.macros.blackbox.Context import cats.data.{EitherK, Tuple2K} @@ -78,85 +77,15 @@ object FunctionK { * val lifted: FunctionK[List, Option] = FunctionK.lift(headOption) * }}} * - * Note: This method has a macro implementation that returns a new - * `FunctionK` instance as follows: - * - * {{{ - * new FunctionK[F, G] { - * def apply[A](fa: F[A]): G[A] = f(fa) - * } - * }}} - * - * Additionally, the type parameters on `f` must not be specified. + * Note: The weird `τ[F, G]` parameter is there to compensate for + * the lack of polymorphic function types in Scala 2. */ - def lift[F[_], G[_]](f: (F[α] => G[α]) forSome { type α }): FunctionK[F, G] = - macro FunctionKMacros.lift[F, G] - -} - -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) - - 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") - } - - 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") + def lift[F[_], G[_]](f: F[τ[F, G]] => G[τ[F, G]]): FunctionK[F, G] = + new FunctionK[F, G] { + def apply[A](fa: F[A]): G[A] = + f.asInstanceOf[F[A] => G[A]](fa) } - } - + /** Used in the signature of `lift` to emulate a polymorphic function type */ + private[this] sealed trait τ[F[_], G[_]] }