diff --git a/core/src/main/scala/cats/arrow/FunctionK.scala b/core/src/main/scala/cats/arrow/FunctionK.scala index 201d3e5b00..454da3bbc5 100644 --- a/core/src/main/scala/cats/arrow/FunctionK.scala +++ b/core/src/main/scala/cats/arrow/FunctionK.scala @@ -43,15 +43,41 @@ object FunctionKMacros extends MacroCompat { 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]] = + 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 unblock(tree: Tree): Tree = tree match { + 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 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 } - def punchHole(tpe: Type): Tree = tpe match { + private[this] def punchHole(tpe: Type): Tree = tpe match { case PolyType(undet :: Nil, underlying: TypeRef) ⇒ val α = compatNewTypeName(c, "α") def rebind(typeRef: TypeRef): Tree = @@ -71,29 +97,6 @@ object FunctionKMacros extends MacroCompat { c.abort(c.enclosingPosition, s"Unexpected type $tpe when lifting to FunctionK") } - val tree = unblock(f.tree) match { - case q"""($param) => $trans[..$typeArgs](${ arg: Ident })""" if param.name == arg.name ⇒ - - typeArgs - .collect { case tt: TypeTree => tt } - .find(_.original != null) - .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 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") - } - - c.Expr[FunctionK[F, G]](tree) } }