change synthetic sender’s reply type to UnknownDoNotWriteMeDown

This commit is contained in:
Roland 2013-01-31 09:05:49 +01:00
parent aec29618e3
commit 5e763bbb38
5 changed files with 19 additions and 8 deletions

View file

@ -14,6 +14,14 @@ sealed trait TNil extends ChannelList
sealed trait :+:[A <: (_, _), B <: ChannelList] extends ChannelList
sealed trait ReplyChannels[T <: ChannelList] extends ChannelList
/**
* This type is used to stand in for the unknown reply types of the fabricated
* sender references; users dont need to write it down, and if they do, they
* know that theyre cheating (since these ref types must not escape their
* defining actor context).
*/
sealed trait UnknownDoNotWriteMeDown
class ActorRefOps(val ref: ActorRef) extends AnyVal {
import macros.Helpers._
def narrow[C <: ChannelList](implicit timeout: Timeout, ec: ExecutionContext, tt: ru.TypeTag[C]): Future[ChannelRef[C]] = {

View file

@ -31,7 +31,7 @@ object Ask {
Tell.verify(c)(null, unwrapped, typeOf[(Any, Nothing) :+: TNil], tpeChannel)
implicit val ttReturnChannels = c.TypeTag[ReturnChannels](toChannels(c.universe)(out))
implicit val ttReturnChannels = c.TypeTag[ReturnChannels](toChannels(c.universe)(out, weakTypeOf[Nothing]))
implicit val ttReturnLUB = c.TypeTag[ReturnLUB](c.universe.lub(out))
reify(askOps[WrappedMessage[ReturnChannels, ReturnLUB]](
c.prefix.splice.actorRef, toMsg(c)(msg, tpeMsg).splice)(imp[Timeout](c).splice))
@ -54,7 +54,7 @@ object Ask {
Tell.verify(c)(null, unwrapped, typeOf[(Any, Nothing) :+: TNil], tpeChannel)
implicit val ttReturnChannels = c.TypeTag[ReturnChannels](toChannels(c.universe)(out))
implicit val ttReturnChannels = c.TypeTag[ReturnChannels](toChannels(c.universe)(out, weakTypeOf[Nothing]))
implicit val ttReturnLUB = c.TypeTag[ReturnLUB](c.universe.lub(out))
val msg = reify(c.prefix.splice.value)
reify(askOps[WrappedMessage[ReturnChannels, ReturnLUB]](
@ -78,7 +78,7 @@ object Ask {
Tell.verify(c)(null, unwrapped, typeOf[(Any, Nothing) :+: TNil], tpeChannel)
implicit val ttReturnChannels = c.TypeTag[ReturnChannels](toChannels(c.universe)(out))
implicit val ttReturnChannels = c.TypeTag[ReturnChannels](toChannels(c.universe)(out, weakTypeOf[Nothing]))
implicit val ttReturnLUB = c.TypeTag[ReturnLUB](c.universe.lub(out))
if (tpeMsg <:< typeOf[ChannelList])
reify(askFutureWrapped[WrappedMessage[ReturnChannels, ReturnLUB]](

View file

@ -34,7 +34,7 @@ object Channel {
checkUnique(c.universe)(tpeMsgT, tpeMyChannels) foreach (c.error(c.enclosingPosition, _))
// need to calculate the intersection of the reply channel sets for all input channels
val intersection = inputChannels(c.universe)(tpeMsgT) map (replyChannels(c.universe)(tpeMyChannels, _).toSet) reduce (_ intersect _)
val channels = toChannels(c.universe)(intersection.toList)
val channels = toChannels(c.universe)(intersection.toList, weakTypeOf[UnknownDoNotWriteMeDown])
implicit val ttMyChannels = c.TypeTag[MyChannels](tpeMyChannels)
implicit val ttReplyChannels = c.TypeTag[ReplyChannels](channels)
implicit val ttMsgT = c.TypeTag[MsgT](tpeMsgT)

View file

@ -117,7 +117,7 @@ object Helpers {
* convert a list of types List(<T1>, <T2>, ...) into a ChannelList
* ( Channel[<T1>, Nothing] :=: Channel[<T2>, Nothing] :=: ... :=: TNil )
*/
final def toChannels(u: Universe)(list: List[u.Type]): u.Type = {
final def toChannels(u: Universe)(list: List[u.Type], out: u.Type): u.Type = {
import u._
def rec(l: List[Type], acc: Type): Type = l match {
case head :: (tail: List[Type])
@ -127,7 +127,7 @@ object Helpers {
appliedType(weakTypeOf[:+:[_, _]].typeConstructor, List(
appliedType(weakTypeOf[Tuple2[_, _]].typeConstructor, List(
head,
weakTypeOf[Nothing])),
out)),
acc)))
case _ acc
}

View file

@ -70,15 +70,18 @@ object Tell {
}
def verify(c: Context)(sender: c.universe.Tree, msgT: c.universe.Type, sndT: c.universe.Type, chT: c.universe.Type)(): Unit = {
val unknown = c.universe.weakTypeOf[UnknownDoNotWriteMeDown]
val nothing = c.universe.weakTypeOf[Nothing]
def ignoreUnknown(in: c.universe.Type): c.universe.Type = if (in =:= unknown) nothing else in
def rec(msg: Set[c.universe.Type], checked: Set[c.universe.Type], depth: Int): Unit =
if (msg.nonEmpty) {
val u: c.universe.type = c.universe
val replies = msg map (m m -> replyChannels(u)(chT, m))
val replies = msg map (m m -> (replyChannels(u)(chT, m) map (t => ignoreUnknown(t))))
val missing = replies collect { case (k, v) if v.size == 0 k }
if (missing.nonEmpty)
error(c, s"target ChannelRef does not support messages of types ${missing mkString ", "} (at depth $depth)")
else {
val nextSend = replies.map(_._2).flatten map (m m -> replyChannels(u)(sndT, m))
val nextSend = replies.map(_._2).flatten map (m m -> (replyChannels(u)(sndT, m) map (t => ignoreUnknown(t))))
val nextMissing = nextSend collect { case (k, v) if v.size == 0 k }
if (nextMissing.nonEmpty)
error(c, s"implicit sender `$sender` does not support messages of the reply types ${nextMissing mkString ", "} (at depth $depth)")