Skip to content

Commit f304311

Browse files
committed
Move FunctionK macro into Scala 2-specific directory
1 parent 53165d5 commit f304311

File tree

3 files changed

+101
-92
lines changed

3 files changed

+101
-92
lines changed
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
package cats
2+
package arrow
3+
4+
import scala.reflect.macros.blackbox.Context
5+
6+
private[arrow] class FunctionKMacroMethods {
7+
8+
/**
9+
* Lifts function `f` of `F[A] => G[A]` into a `FunctionK[F, G]`.
10+
*
11+
* {{{
12+
* def headOption[A](list: List[A]): Option[A] = list.headOption
13+
* val lifted: FunctionK[List, Option] = FunctionK.lift(headOption)
14+
* }}}
15+
*
16+
* Note: This method has a macro implementation that returns a new
17+
* `FunctionK` instance as follows:
18+
*
19+
* {{{
20+
* new FunctionK[F, G] {
21+
* def apply[A](fa: F[A]): G[A] = f(fa)
22+
* }
23+
* }}}
24+
*
25+
* Additionally, the type parameters on `f` must not be specified.
26+
*/
27+
def lift[F[_], G[_]](f: (F[α] => G[α]) forSome { type α }): FunctionK[F, G] =
28+
macro FunctionKMacros.lift[F, G]
29+
}
30+
31+
private[arrow] object FunctionKMacros {
32+
33+
def lift[F[_], G[_]](c: Context)(
34+
f: c.Expr[(F[α] => G[α]) forSome { type α }]
35+
)(
36+
implicit evF: c.WeakTypeTag[F[_]],
37+
evG: c.WeakTypeTag[G[_]]
38+
): c.Expr[FunctionK[F, G]] =
39+
c.Expr[FunctionK[F, G]](new Lifter[c.type](c).lift[F, G](f.tree))
40+
// ^^note: extra space after c.type to appease scalastyle
41+
42+
private[this] class Lifter[C <: Context](val c: C) {
43+
import c.universe._
44+
45+
def lift[F[_], G[_]](tree: Tree)(
46+
implicit evF: c.WeakTypeTag[F[_]],
47+
evG: c.WeakTypeTag[G[_]]
48+
): Tree = unblock(tree) match {
49+
case q"($param) => $trans[..$typeArgs](${arg: Ident})" if param.name == arg.name =>
50+
typeArgs
51+
.collect { case tt: TypeTree => tt }
52+
.find(tt => Option(tt.original).isDefined)
53+
.foreach { param =>
54+
c.abort(param.pos, s"type parameter $param must not be supplied when lifting function $trans to FunctionK")
55+
}
56+
57+
val F = punchHole(evF.tpe)
58+
val G = punchHole(evG.tpe)
59+
60+
q"""
61+
new _root_.cats.arrow.FunctionK[$F, $G] {
62+
def apply[A](fa: $F[A]): $G[A] = $trans(fa)
63+
}
64+
"""
65+
case other =>
66+
c.abort(other.pos, s"Unexpected tree $other when lifting to FunctionK")
67+
}
68+
69+
private[this] def unblock(tree: Tree): Tree = tree match {
70+
case Block(Nil, expr) => expr
71+
case _ => tree
72+
}
73+
74+
private[this] def punchHole(tpe: Type): Tree = tpe match {
75+
case PolyType(undet :: Nil, underlying: TypeRef) =>
76+
val α = TypeName("α")
77+
def rebind(typeRef: TypeRef): Tree =
78+
if (typeRef.sym == undet) tq""
79+
else {
80+
val args = typeRef.args.map {
81+
case ref: TypeRef => rebind(ref)
82+
case arg => tq"$arg"
83+
}
84+
tq"${typeRef.sym}[..$args]"
85+
}
86+
val rebound = rebind(underlying)
87+
tq"""({type λ[] = $rebound})#λ"""
88+
case TypeRef(pre, sym, Nil) =>
89+
tq"$sym"
90+
case _ =>
91+
c.abort(c.enclosingPosition, s"Unexpected type $tpe when lifting to FunctionK")
92+
}
93+
94+
}
95+
96+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package cats
2+
package arrow
3+
4+
private[arrow] class FunctionKMacroMethods
Lines changed: 1 addition & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
package cats
22
package arrow
33

4-
import scala.reflect.macros.blackbox.Context
5-
64
import cats.data.{EitherK, Tuple2K}
75

86
/**
@@ -63,100 +61,11 @@ trait FunctionK[F[_], G[_]] extends Serializable { self =>
6361
λ[FunctionK[F, Tuple2K[G, H, *]]](fa => Tuple2K(self(fa), h(fa)))
6462
}
6563

66-
object FunctionK {
64+
object FunctionK extends FunctionKMacroMethods {
6765

6866
/**
6967
* The identity transformation of `F` to `F`
7068
*/
7169
def id[F[_]]: FunctionK[F, F] = λ[FunctionK[F, F]](fa => fa)
7270

73-
/**
74-
* Lifts function `f` of `F[A] => G[A]` into a `FunctionK[F, G]`.
75-
*
76-
* {{{
77-
* def headOption[A](list: List[A]): Option[A] = list.headOption
78-
* val lifted: FunctionK[List, Option] = FunctionK.lift(headOption)
79-
* }}}
80-
*
81-
* Note: This method has a macro implementation that returns a new
82-
* `FunctionK` instance as follows:
83-
*
84-
* {{{
85-
* new FunctionK[F, G] {
86-
* def apply[A](fa: F[A]): G[A] = f(fa)
87-
* }
88-
* }}}
89-
*
90-
* Additionally, the type parameters on `f` must not be specified.
91-
*/
92-
def lift[F[_], G[_]](f: (F[α] => G[α]) forSome { type α }): FunctionK[F, G] =
93-
macro FunctionKMacros.lift[F, G]
94-
95-
}
96-
97-
private[arrow] object FunctionKMacros {
98-
99-
def lift[F[_], G[_]](c: Context)(
100-
f: c.Expr[(F[α] => G[α]) forSome { type α }]
101-
)(
102-
implicit evF: c.WeakTypeTag[F[_]],
103-
evG: c.WeakTypeTag[G[_]]
104-
): c.Expr[FunctionK[F, G]] =
105-
c.Expr[FunctionK[F, G]](new Lifter[c.type](c).lift[F, G](f.tree))
106-
// ^^note: extra space after c.type to appease scalastyle
107-
108-
private[this] class Lifter[C <: Context](val c: C) {
109-
import c.universe._
110-
111-
def lift[F[_], G[_]](tree: Tree)(
112-
implicit evF: c.WeakTypeTag[F[_]],
113-
evG: c.WeakTypeTag[G[_]]
114-
): Tree = unblock(tree) match {
115-
case q"($param) => $trans[..$typeArgs](${arg: Ident})" if param.name == arg.name =>
116-
typeArgs
117-
.collect { case tt: TypeTree => tt }
118-
.find(tt => Option(tt.original).isDefined)
119-
.foreach { param =>
120-
c.abort(param.pos, s"type parameter $param must not be supplied when lifting function $trans to FunctionK")
121-
}
122-
123-
val F = punchHole(evF.tpe)
124-
val G = punchHole(evG.tpe)
125-
126-
q"""
127-
new _root_.cats.arrow.FunctionK[$F, $G] {
128-
def apply[A](fa: $F[A]): $G[A] = $trans(fa)
129-
}
130-
"""
131-
case other =>
132-
c.abort(other.pos, s"Unexpected tree $other when lifting to FunctionK")
133-
}
134-
135-
private[this] def unblock(tree: Tree): Tree = tree match {
136-
case Block(Nil, expr) => expr
137-
case _ => tree
138-
}
139-
140-
private[this] def punchHole(tpe: Type): Tree = tpe match {
141-
case PolyType(undet :: Nil, underlying: TypeRef) =>
142-
val α = TypeName("α")
143-
def rebind(typeRef: TypeRef): Tree =
144-
if (typeRef.sym == undet) tq""
145-
else {
146-
val args = typeRef.args.map {
147-
case ref: TypeRef => rebind(ref)
148-
case arg => tq"$arg"
149-
}
150-
tq"${typeRef.sym}[..$args]"
151-
}
152-
val rebound = rebind(underlying)
153-
tq"""({type λ[] = $rebound})#λ"""
154-
case TypeRef(pre, sym, Nil) =>
155-
tq"$sym"
156-
case _ =>
157-
c.abort(c.enclosingPosition, s"Unexpected type $tpe when lifting to FunctionK")
158-
}
159-
160-
}
161-
16271
}

0 commit comments

Comments
 (0)