the great beautification

- reify() all trees, no bricolage
- use rediscovered c.TypeTag factory to splice in calculated types
- give meaningful names to type parameters and humunguosly explode val
  names
This commit is contained in:
Roland 2013-01-25 22:00:11 +01:00
parent e55e57060b
commit f5934b9cca
7 changed files with 99 additions and 120 deletions

View file

@ -87,16 +87,19 @@ trait Channels[P <: ChannelList, C <: ChannelList] extends Actor {
* } * }
* }}} * }}}
*/ */
def channel[T]: Channels[P, C]#Behaviorist[Nothing, T] = macro macros.Channel.impl[T, C, P] def channel[T]: (Nothing Unit) = macro macros.Channel.impl[ChannelList, ChannelList, T, C, P]
class Behaviorist[-R, Ch](tt: ru.TypeTag[Ch], wrapped: Boolean) { def behaviorist[R, Ch: ru.TypeTag](wrapped: Boolean): (R Unit) = new Behaviorist[R, Ch](wrapped)
private class Behaviorist[-R, Ch: ru.TypeTag](wrapped: Boolean) extends (R Unit) {
private def ff(recv: R): FF = private def ff(recv: R): FF =
if (wrapped) if (wrapped)
F1(recv.asInstanceOf[(WrappedMessage[ChannelList], ChannelRef[ChannelList]) Unit]) F1(recv.asInstanceOf[(WrappedMessage[ChannelList], ChannelRef[ChannelList]) Unit])
else else
F2(recv.asInstanceOf[(Any, ChannelRef[ChannelList]) Unit]) F2(recv.asInstanceOf[(Any, ChannelRef[ChannelList]) Unit])
def apply(recv: R): Unit = def apply(recv: R): Unit = {
val tt = implicitly[ru.TypeTag[Ch]]
behavior ++= (for (t inputChannels(ru)(tt.tpe)) yield tt.mirror.runtimeClass(t.widen) -> ff(recv)) behavior ++= (for (t inputChannels(ru)(tt.tpe)) yield tt.mirror.runtimeClass(t.widen) -> ff(recv))
}
} }
/* /*
@ -105,7 +108,7 @@ trait Channels[P <: ChannelList, C <: ChannelList] extends Actor {
* Id like to keep this a trait, but traits cannot have constructor * Id like to keep this a trait, but traits cannot have constructor
* arguments, not even TypeTags. * arguments, not even TypeTags.
*/ */
protected var channelListTypeTag: TypeTag[C] = _ var channelListTypeTag: TypeTag[C] = _
/** /**
* Sort so that subtypes always precede their supertypes, but without * Sort so that subtypes always precede their supertypes, but without

View file

@ -14,51 +14,51 @@ import scala.reflect.api.{ TypeCreator }
object Ask { object Ask {
import Helpers._ import Helpers._
def impl[A, T <: ChannelList: c.WeakTypeTag, M: c.WeakTypeTag](c: Context { def impl[ReturnT, Channel <: ChannelList: c.WeakTypeTag, Msg: c.WeakTypeTag](c: Context {
type PrefixType = ChannelRef[T] type PrefixType = ChannelRef[Channel]
})(msg: c.Expr[M]): c.Expr[Future[A]] = { })(msg: c.Expr[Msg]): c.Expr[Future[ReturnT]] = {
import c.universe._ import c.universe._
val chT = weakTypeOf[T] val tpeChannel = weakTypeOf[Channel]
val msgT = weakTypeOf[M] val tpeMsg = weakTypeOf[Msg]
val out = replyChannels(c.universe)(chT, msgT) val out = replyChannels(c.universe)(tpeChannel, tpeMsg)
if (out.isEmpty) if (out.isEmpty)
abort(c, s"This ChannelRef does not support messages of type $msgT") abort(c, s"This ChannelRef does not support messages of type $tpeMsg")
implicit val tA = weakTT[A](c)(c.universe.lub(out)) implicit val ttReturn = c.TypeTag[ReturnT](c.universe.lub(out))
reify(askOps[A](c.prefix.splice.actorRef, msg.splice)(imp[Timeout](c).splice)) reify(askOps[ReturnT](c.prefix.splice.actorRef, msg.splice)(imp[Timeout](c).splice))
} }
def opsImpl[A, T <: ChannelList: c.WeakTypeTag, M: c.WeakTypeTag](c: Context { def opsImpl[ReturnT, Channel <: ChannelList: c.WeakTypeTag, Msg: c.WeakTypeTag](c: Context {
type PrefixType = AnyOps[M] type PrefixType = AnyOps[Msg]
})(channel: c.Expr[ChannelRef[T]]): c.Expr[Future[A]] = { })(channel: c.Expr[ChannelRef[Channel]]): c.Expr[Future[ReturnT]] = {
import c.universe._ import c.universe._
val chT = weakTypeOf[T] val tpeChannel = weakTypeOf[Channel]
val msgT = weakTypeOf[M] val tpeMsg = weakTypeOf[Msg]
val out = replyChannels(c.universe)(chT, msgT) val out = replyChannels(c.universe)(tpeChannel, tpeMsg)
if (out.isEmpty) if (out.isEmpty)
abort(c, s"This ChannelRef does not support messages of type $msgT") abort(c, s"This ChannelRef does not support messages of type $tpeMsg")
implicit val tA = weakTT[A](c)(c.universe.lub(out)) implicit val ttReturn = c.TypeTag[ReturnT](c.universe.lub(out))
reify(askOps[A](channel.splice.actorRef, c.prefix.splice.value)(imp[Timeout](c).splice)) reify(askOps[ReturnT](channel.splice.actorRef, c.prefix.splice.value)(imp[Timeout](c).splice))
} }
def futureImpl[A, T <: ChannelList: c.WeakTypeTag, M: c.WeakTypeTag](c: Context { def futureImpl[ReturnT, Channel <: ChannelList: c.WeakTypeTag, Msg: c.WeakTypeTag](c: Context {
type PrefixType = FutureOps[M] type PrefixType = FutureOps[Msg]
})(channel: c.Expr[ChannelRef[T]]): c.Expr[Future[A]] = { })(channel: c.Expr[ChannelRef[Channel]]): c.Expr[Future[ReturnT]] = {
import c.universe._ import c.universe._
val chT = weakTypeOf[T] val tpeChannel = weakTypeOf[Channel]
val msgT = weakTypeOf[M] val tpeMsg = weakTypeOf[Msg]
val reply = replyChannels(c.universe)(chT, msgT) match { val reply = replyChannels(c.universe)(tpeChannel, tpeMsg) match {
case Nil abort(c, s"This ChannelRef does not support messages of type $msgT") case Nil abort(c, s"This ChannelRef does not support messages of type $tpeMsg")
case x :: Nil x case x :: Nil x
case xs toChannels(c.universe)(xs) case xs toChannels(c.universe)(xs)
} }
implicit val tA = weakTT[A](c)(reply) implicit val ttReturn = c.TypeTag[ReturnT](reply)
reify(askFuture[M, A](channel.splice.actorRef, c.prefix.splice.future)(imp[Timeout](c).splice)) reify(askFuture[Msg, ReturnT](channel.splice.actorRef, c.prefix.splice.future)(imp[Timeout](c).splice))
} }
@inline def askOps[T](target: ActorRef, msg: Any)(implicit t: Timeout): Future[T] = akka.pattern.ask(target, msg).asInstanceOf[Future[T]] @inline def askOps[T](target: ActorRef, msg: Any)(implicit t: Timeout): Future[T] = akka.pattern.ask(target, msg).asInstanceOf[Future[T]]

View file

@ -1,8 +1,7 @@
package akka.channels.macros package akka.channels.macros
import akka.channels._ import akka.channels._
import scala.reflect.runtime.{ universe ru } import scala.reflect.runtime.universe
import ru.TypeTag
import scala.reflect.macros.Context import scala.reflect.macros.Context
import scala.reflect.api.Universe import scala.reflect.api.Universe
@ -18,59 +17,41 @@ object Channel {
* C is the channel list of the enclosing Channels * C is the channel list of the enclosing Channels
* P is the parent channel list * P is the parent channel list
*/ */
def impl[T: c.WeakTypeTag, C <: ChannelList: c.WeakTypeTag, P <: ChannelList: c.WeakTypeTag]( def impl[ReplyChannels <: ChannelList, MsgTChan <: ChannelList, MsgT: c.WeakTypeTag, MyChannels <: ChannelList: c.WeakTypeTag, ParentChannels <: ChannelList: c.WeakTypeTag](
c: Context { c: Context {
type PrefixType = Channels[P, C] type PrefixType = Channels[ParentChannels, MyChannels]
}): c.Expr[Channels[P, C]#Behaviorist[Nothing, T]] = { }): c.Expr[(Nothing Unit)] = {
val tT = c.weakTypeOf[T] val tpeMsgT = c.weakTypeOf[MsgT]
val tC = c.weakTypeOf[C] val tpeMyChannels = c.weakTypeOf[MyChannels]
import c.universe._ import c.universe._
val undefined = missingChannels(c.universe)(tC, inputChannels(c.universe)(tT)) val undefined = missingChannels(c.universe)(tpeMyChannels, inputChannels(c.universe)(tpeMsgT))
if (undefined.nonEmpty) { if (undefined.nonEmpty) {
c.error(c.enclosingPosition, s"no channel defined for types ${undefined mkString ", "}") c.abort(c.enclosingPosition, s"no channel defined for types ${undefined mkString ", "}")
reify(null)
} else { } else {
checkUnique(c.universe)(tT, tC) foreach (c.error(c.enclosingPosition, _)) checkUnique(c.universe)(tpeMsgT, tpeMyChannels) foreach (c.error(c.enclosingPosition, _))
val channels = toChannels(c.universe)(replyChannels(c.universe)(tC, tT)) val channels = toChannels(c.universe)(replyChannels(c.universe)(tpeMyChannels, tpeMsgT))
val (receive, wrapped) = val wrapped = tpeMsgT <:< typeOf[ChannelList]
if (tT <:< typeOf[ChannelList]) { implicit val ttMyChannels = c.TypeTag[MyChannels](tpeMyChannels)
appliedType(typeOf[Function2[_, _, _]].typeConstructor, List( implicit val ttReplyChannels = c.TypeTag[ReplyChannels](channels)
appliedType(typeOf[WrappedMessage[_]].typeConstructor, List(tT)), implicit val ttMsgT = c.TypeTag[MsgT](tpeMsgT)
appliedType(typeOf[ChannelRef[_]].typeConstructor, List(channels)), implicit val ttMsgTChan = c.TypeTag[MsgTChan](tpeMsgT) // this is MsgT reinterpreted as <: ChannelList
typeOf[Unit])) -> true val prepTree = reify(if (c.prefix.splice.channelListTypeTag == null)
} else { c.prefix.splice.channelListTypeTag = universe.typeTag[MyChannels])
appliedType(typeOf[Function2[_, _, _]].typeConstructor, List( if (wrapped)
tT, reify {
appliedType(typeOf[ChannelRef[_]].typeConstructor, List(channels)), prepTree.splice
typeOf[Unit])) -> false c.prefix.splice.behaviorist[(WrappedMessage[MsgTChan], ChannelRef[ReplyChannels]) Unit, MsgT](
bool(c, wrapped).splice)(universe.typeTag[MsgT])
}
else
reify {
prepTree.splice
c.prefix.splice.behaviorist[(MsgT, ChannelRef[ReplyChannels]) Unit, MsgT](
bool(c, wrapped).splice)(universe.typeTag[MsgT])
} }
c.Expr(
Block(List(
If(
{
val cltt = c.Expr(Select(c.prefix.tree, "channelListTypeTag"))
reify(cltt.splice == null).tree
},
Apply(
Select(c.prefix.tree, "channelListTypeTag_$eq"),
List(TypeApply(
Select(Select(Select(Select(Select(Ident("scala"), "reflect"), "runtime"), nme.PACKAGE), "universe"), "typeTag"),
List(TypeTree().setType(c.weakTypeOf[C]))))),
c.literalUnit.tree)),
Apply(
Select(
New(AppliedTypeTree(Select(c.prefix.tree, newTypeName("Behaviorist")), List(
TypeTree().setType(receive),
TypeTree().setType(tT)))),
nme.CONSTRUCTOR),
List(
TypeApply(
Select(Select(Select(Select(Select(Ident("scala"), "reflect"), "runtime"), nme.PACKAGE), "universe"), "typeTag"),
List(TypeTree().setType(tT))),
Literal(Constant(wrapped))))))
} }
} }

View file

@ -10,25 +10,26 @@ import akka.actor.Props
object CreateChild { object CreateChild {
import Helpers._ import Helpers._
def impl[C <: ChannelList: c.WeakTypeTag, Pa <: ChannelList: c.WeakTypeTag, Ch <: ChannelList: c.WeakTypeTag]( def impl[MyChannels <: ChannelList: c.WeakTypeTag, ParentChannels <: ChannelList: c.WeakTypeTag, ChildChannels <: ChannelList: c.WeakTypeTag](
c: Context { c: Context {
type PrefixType = Channels[_, C] type PrefixType = Channels[_, MyChannels]
})(factory: c.Expr[Channels[Pa, Ch]]): c.Expr[ChannelRef[Ch]] = { })(factory: c.Expr[Channels[ParentChannels, ChildChannels]]): c.Expr[ChannelRef[ChildChannels]] = {
import c.universe._ import c.universe._
if (weakTypeOf[Pa] =:= weakTypeOf[Nothing]) {
if (weakTypeOf[ParentChannels] =:= weakTypeOf[Nothing]) {
c.abort(c.enclosingPosition, "Parent argument must not be Nothing") c.abort(c.enclosingPosition, "Parent argument must not be Nothing")
} }
if (weakTypeOf[Ch] =:= weakTypeOf[Nothing]) { if (weakTypeOf[ChildChannels] =:= weakTypeOf[Nothing]) {
c.abort(c.enclosingPosition, "channel list must not be Nothing") c.abort(c.enclosingPosition, "channel list must not be Nothing")
} }
val missing = missingChannels(c.universe)(weakTypeOf[C], inputChannels(c.universe)(weakTypeOf[Pa]))
val missing = missingChannels(c.universe)(weakTypeOf[MyChannels], inputChannels(c.universe)(weakTypeOf[ParentChannels]))
if (missing.isEmpty) { if (missing.isEmpty) {
implicit val t = c.TypeTag[Ch](c.weakTypeOf[Ch]) implicit val t = c.TypeTag[ChildChannels](c.weakTypeOf[ChildChannels])
reify(new ChannelRef[Ch](c.prefix.splice.context.actorOf(Props(factory.splice)))) reify(new ChannelRef[ChildChannels](c.prefix.splice.context.actorOf(Props(factory.splice))))
} else { } else {
c.error(c.enclosingPosition, s"This actor cannot support a child requiring channels ${missing mkString ", "}") c.abort(c.enclosingPosition, s"This actor cannot support a child requiring channels ${missing mkString ", "}")
reify(???)
} }
} }

View file

@ -25,13 +25,7 @@ object Helpers {
c.Expr[T](TypeApply(Ident("implicitly"), List(TypeTree().setType(weakTypeOf[T])))) c.Expr[T](TypeApply(Ident("implicitly"), List(TypeTree().setType(weakTypeOf[T]))))
} }
def weakTT[T](c: Context)(tpe: c.universe.Type): c.WeakTypeTag[T] = def bool(c: Context, b: Boolean): c.Expr[Boolean] = c.Expr[Boolean](c.universe.Literal(c.universe.Constant(b)))
c.universe.WeakTypeTag[T](c.mirror, new TypeCreator {
def apply[U <: Universe with Singleton](m: scala.reflect.api.Mirror[U]) = {
val imp = m.universe.mkImporter(c.universe)
imp.importType(tpe)
}
})
def checkUnique(u: Universe)(channel: u.Type, list: u.Type): Option[String] = { def checkUnique(u: Universe)(channel: u.Type, list: u.Type): Option[String] = {
val channels = inputChannels(u)(list) groupBy (_.erasure) val channels = inputChannels(u)(list) groupBy (_.erasure)

View file

@ -9,16 +9,16 @@ import scala.reflect.api.Universe
object Narrow { object Narrow {
import Helpers._ import Helpers._
def impl[C <: ChannelList: c.WeakTypeTag, T <: ChannelList: c.WeakTypeTag]( def impl[Desired <: ChannelList: c.WeakTypeTag, MyChannels <: ChannelList: c.WeakTypeTag](
c: Context { c: Context {
type PrefixType = ChannelRef[T] type PrefixType = ChannelRef[MyChannels]
}): c.Expr[ChannelRef[C]] = { }): c.Expr[ChannelRef[Desired]] = {
import c.{ universe u } import c.{ universe u }
narrowCheck(u)(u.weakTypeOf[T], u.weakTypeOf[C]) match { narrowCheck(u)(u.weakTypeOf[MyChannels], u.weakTypeOf[Desired]) match {
case Nil // okay case Nil // okay
case err :: Nil c.error(c.enclosingPosition, err) case err :: Nil c.error(c.enclosingPosition, err)
case list c.error(c.enclosingPosition, list mkString ("multiple errors:\n - ", "\n - ", "")) case list c.error(c.enclosingPosition, list mkString ("multiple errors:\n - ", "\n - ", ""))
} }
u.reify(c.prefix.splice.asInstanceOf[ChannelRef[C]]) u.reify(c.prefix.splice.asInstanceOf[ChannelRef[Desired]])
} }
} }

View file

@ -14,40 +14,40 @@ import akka.dispatch.ExecutionContexts
object Tell { object Tell {
import Helpers._ import Helpers._
def impl[T <: ChannelList: c.WeakTypeTag, M: c.WeakTypeTag](c: Context { def impl[MyChannels <: ChannelList: c.WeakTypeTag, Msg: c.WeakTypeTag](c: Context {
type PrefixType = ChannelRef[T] type PrefixType = ChannelRef[MyChannels]
})(msg: c.Expr[M]): c.Expr[Unit] = { })(msg: c.Expr[Msg]): c.Expr[Unit] = {
val tT = c.universe.weakTypeOf[T] val tpeMyChannels = c.universe.weakTypeOf[MyChannels]
val (tS, senderTree, sender) = getSenderChannel(c) val (tpeSender, senderTree, sender) = getSenderChannel(c)
verify(c)(senderTree, c.universe.weakTypeOf[M], tS, tT) verify(c)(senderTree, c.universe.weakTypeOf[Msg], tpeSender, tpeMyChannels)
c.universe.reify(c.prefix.splice.actorRef.tell(msg.splice, sender.splice)) c.universe.reify(c.prefix.splice.actorRef.tell(msg.splice, sender.splice))
} }
def opsImpl[T <: ChannelList: c.WeakTypeTag, M: c.WeakTypeTag](c: Context { def opsImpl[MyChannels <: ChannelList: c.WeakTypeTag, Msg: c.WeakTypeTag](c: Context {
type PrefixType = AnyOps[M] type PrefixType = AnyOps[Msg]
})(channel: c.Expr[ChannelRef[T]]): c.Expr[Unit] = { })(channel: c.Expr[ChannelRef[MyChannels]]): c.Expr[Unit] = {
val tT = c.universe.weakTypeOf[T] val tpeMyChannels = c.universe.weakTypeOf[MyChannels]
val (tS, senderTree, sender) = getSenderChannel(c) val (tpeSender, senderTree, sender) = getSenderChannel(c)
verify(c)(senderTree, c.universe.weakTypeOf[M], tS, tT) verify(c)(senderTree, c.universe.weakTypeOf[Msg], tpeSender, tpeMyChannels)
c.universe.reify(channel.splice.actorRef.tell(c.prefix.splice.value, sender.splice)) c.universe.reify(channel.splice.actorRef.tell(c.prefix.splice.value, sender.splice))
} }
def futureImpl[T <: ChannelList: c.WeakTypeTag, M: c.WeakTypeTag](c: Context { def futureImpl[MyChannels <: ChannelList: c.WeakTypeTag, Msg: c.WeakTypeTag](c: Context {
type PrefixType = FutureOps[M] type PrefixType = FutureOps[Msg]
})(channel: c.Expr[ChannelRef[T]]): c.Expr[Future[M]] = { })(channel: c.Expr[ChannelRef[MyChannels]]): c.Expr[Future[Msg]] = {
val tT = c.universe.weakTypeOf[T] val tpeMyChannels = c.universe.weakTypeOf[MyChannels]
val (tS, senderTree, sender) = getSenderChannel(c) val (tpeSender, senderTree, sender) = getSenderChannel(c)
verify(c)(senderTree, c.universe.weakTypeOf[M], tS, tT) verify(c)(senderTree, c.universe.weakTypeOf[Msg], tpeSender, tpeMyChannels)
c.universe.reify(pipeTo[M](c.prefix.splice, channel.splice, sender.splice)) c.universe.reify(pipeTo[Msg](c.prefix.splice, channel.splice, sender.splice))
} }
@inline def pipeTo[M](f: FutureOps[M], c: ChannelRef[_], snd: ActorRef): Future[M] = @inline def pipeTo[Msg](f: FutureOps[Msg], c: ChannelRef[_], snd: ActorRef): Future[Msg] =
f.future.andThen { f.future.andThen {
case Success(s) c.actorRef.tell(s, snd) case Success(s) c.actorRef.tell(s, snd)
case _ case _