aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilipp Haller <hallerp@gmail.com>2013-04-26 17:21:10 +0200
committerPhilipp Haller <hallerp@gmail.com>2013-04-26 17:27:03 +0200
commit9d134adc8e448906ee6ab6cb4db59320557a880c (patch)
treee7002282979262c23c8ab16501f3ae239e8f414a
parent6f8dc1bd2c44b896c1beb2c94cc3a6bc2c7843de (diff)
downloadscala-async-9d134adc8e448906ee6ab6cb4db59320557a880c.tar.gz
scala-async-9d134adc8e448906ee6ab6cb4db59320557a880c.tar.bz2
scala-async-9d134adc8e448906ee6ab6cb4db59320557a880c.zip
Abstract from Try's get and isFailure methods
Adds the following methods to `FutureSystem#Ops`: def isFailedResult(name: TermName): Expr[Boolean] def resultValue(name: TermName, resultType: Type): Tree Introduces `TryBasedFutureSystem` trait.
-rw-r--r--src/main/scala/scala/async/ExprBuilder.scala4
-rw-r--r--src/main/scala/scala/async/FutureSystem.scala67
-rw-r--r--src/main/scala/scala/async/TransformUtils.scala11
3 files changed, 51 insertions, 31 deletions
diff --git a/src/main/scala/scala/async/ExprBuilder.scala b/src/main/scala/scala/async/ExprBuilder.scala
index b8b24c2..18b809a 100644
--- a/src/main/scala/scala/async/ExprBuilder.scala
+++ b/src/main/scala/scala/async/ExprBuilder.scala
@@ -76,7 +76,7 @@ private[async] final case class ExprBuilder[C <: Context, FS <: FutureSystem](c:
val tryGetTree =
Assign(
Ident(awaitable.resultName),
- TypeApply(Select(Select(Ident(name.tr), Try_get), newTermName("asInstanceOf")), List(TypeTree(awaitable.resultType)))
+ futureSystemOps.resultValue(name.tr, awaitable.resultType)
)
/* if (tr.isFailure)
@@ -88,7 +88,7 @@ private[async] final case class ExprBuilder[C <: Context, FS <: FutureSystem](c:
* }
*/
val ifIsFailureTree =
- If(Select(Ident(name.tr), Try_isFailure),
+ If(futureSystemOps.isFailedResult(name.tr).tree,
futureSystemOps.completePromWithFailedResult[T](
c.Expr[futureSystem.Prom[T]](Ident(name.result)),
name.tr).tree,
diff --git a/src/main/scala/scala/async/FutureSystem.scala b/src/main/scala/scala/async/FutureSystem.scala
index c151d51..7e14c44 100644
--- a/src/main/scala/scala/async/FutureSystem.scala
+++ b/src/main/scala/scala/async/FutureSystem.scala
@@ -26,9 +26,9 @@ trait FutureSystem {
type ExecContext
trait Ops {
- val context: reflect.macros.Context
+ val c: reflect.macros.Context
- import context.universe._
+ import c.universe._
/** Lookup the execution context, typically with an implicit search */
def execContext: Expr[ExecContext]
@@ -58,16 +58,47 @@ trait FutureSystem {
/** Complete a promise with a failed result */
def completePromWithFailedResult[A: WeakTypeTag](prom: Expr[Prom[A]], resultName: TermName): Expr[Unit]
- def spawn(tree: context.Tree): context.Tree =
- future(context.Expr[Unit](tree))(execContext).tree
+ /** Test if the given result is failed */
+ def isFailedResult(name: TermName): Expr[Boolean]
+
+ /** Result value of a completion */
+ def resultValue(name: TermName, resultType: Type): Tree
+
+ def spawn(tree: Tree): Tree =
+ future(c.Expr[Unit](tree))(execContext).tree
def castTo[A: WeakTypeTag](future: Expr[Fut[Any]]): Expr[Fut[A]]
}
- def mkOps(c: Context): Ops { val context: c.type }
+ def mkOps(ctx: Context): Ops { val c: ctx.type }
+}
+
+trait TryBasedFutureSystem extends FutureSystem {
+
+ trait OpsWithTry extends Ops {
+ import c.universe._
+
+ /** `methodSym( (_: Foo).bar(null: A, null: B)` will return the symbol of `bar`, after overload resolution. */
+ private def methodSym(apply: c.Expr[Any]): Symbol = {
+ val tree2: Tree = c.typeCheck(apply.tree)
+ tree2.collect {
+ case s: SymTree if s.symbol.isMethod => s.symbol
+ }.headOption.getOrElse(sys.error(s"Unable to find a method symbol in ${apply.tree}"))
+ }
+
+ lazy val Try_isFailure = methodSym(reify((null: scala.util.Try[Any]).isFailure))
+ lazy val Try_get = methodSym(reify((null: scala.util.Try[Any]).get))
+
+ def isFailedResult(name: TermName): Expr[Boolean] =
+ c.Expr[Boolean](Select(Ident(name), Try_isFailure))
+
+ def resultValue(name: TermName, resultType: Type): Tree =
+ TypeApply(Select(Select(Ident(name), Try_get), newTermName("asInstanceOf")), List(TypeTree(resultType)))
+ }
+
}
-object ScalaConcurrentFutureSystem extends FutureSystem {
+object ScalaConcurrentFutureSystem extends TryBasedFutureSystem {
import scala.concurrent._
@@ -75,10 +106,10 @@ object ScalaConcurrentFutureSystem extends FutureSystem {
type Fut[A] = Future[A]
type ExecContext = ExecutionContext
- def mkOps(c: Context): Ops {val context: c.type} = new Ops {
- val context: c.type = c
+ def mkOps(ctx: Context): Ops { val c: ctx.type } = new OpsWithTry {
+ val c: ctx.type = ctx
- import context.universe._
+ import c.universe._
def execContext: Expr[ExecContext] = c.Expr(c.inferImplicitValue(c.weakTypeOf[ExecutionContext]) match {
case EmptyTree => c.abort(c.macroApplication.pos, "Unable to resolve implicit ExecutionContext")
@@ -107,12 +138,12 @@ object ScalaConcurrentFutureSystem extends FutureSystem {
def completeProm[A: WeakTypeTag](prom: Expr[Prom[A]], value: Expr[A]): Expr[Unit] = reify {
prom.splice.success(value.splice)
- context.literalUnit.splice
+ c.literalUnit.splice
}
def completePromWithExceptionTopLevel[A: WeakTypeTag](prom: Expr[Prom[A]], exception: Expr[Throwable]): Expr[Unit] = reify {
prom.splice.failure(exception.splice)
- context.literalUnit.splice
+ c.literalUnit.splice
}
def completePromWithFailedResult[A: WeakTypeTag](prom: Expr[Prom[A]], resultName: TermName): Expr[Unit] = {
@@ -121,7 +152,7 @@ object ScalaConcurrentFutureSystem extends FutureSystem {
List(TypeTree(weakTypeOf[scala.util.Try[A]]))))
reify {
prom.splice.complete(result.splice)
- context.literalUnit.splice
+ c.literalUnit.splice
}
}
@@ -135,17 +166,17 @@ object ScalaConcurrentFutureSystem extends FutureSystem {
* A trivial implementation of [[scala.async.FutureSystem]] that performs computations
* on the current thread. Useful for testing.
*/
-object IdentityFutureSystem extends FutureSystem {
+object IdentityFutureSystem extends TryBasedFutureSystem {
class Prom[A](var a: A)
type Fut[A] = A
type ExecContext = Unit
- def mkOps(c: Context): Ops {val context: c.type} = new Ops {
- val context: c.type = c
+ def mkOps(ctx: Context): Ops { val c: ctx.type } = new OpsWithTry {
+ val c: ctx.type = ctx
- import context.universe._
+ import c.universe._
def execContext: Expr[ExecContext] = c.literalUnit
@@ -165,12 +196,12 @@ object IdentityFutureSystem extends FutureSystem {
def onComplete[A, U](future: Expr[Fut[A]], fun: Expr[scala.util.Try[A] => U],
execContext: Expr[ExecContext]): Expr[Unit] = reify {
fun.splice.apply(util.Success(future.splice))
- context.literalUnit.splice
+ c.literalUnit.splice
}
def completeProm[A: WeakTypeTag](prom: Expr[Prom[A]], value: Expr[A]): Expr[Unit] = reify {
prom.splice.a = value.splice
- context.literalUnit.splice
+ c.literalUnit.splice
}
def completePromWithExceptionTopLevel[A: WeakTypeTag](prom: Expr[Prom[A]], exception: Expr[Throwable]): Expr[Unit] = reify {
diff --git a/src/main/scala/scala/async/TransformUtils.scala b/src/main/scala/scala/async/TransformUtils.scala
index ebd546f..d6f2643 100644
--- a/src/main/scala/scala/async/TransformUtils.scala
+++ b/src/main/scala/scala/async/TransformUtils.scala
@@ -186,9 +186,6 @@ private[async] final case class TransformUtils[C <: Context](c: C) {
self.splice.get
}
- val Try_get = methodSym(reify((null: scala.util.Try[Any]).get))
- val Try_isFailure = methodSym(reify((null: scala.util.Try[Any]).isFailure))
-
val TryClass = c.mirror.staticClass("scala.util.Try")
val TryAnyType = appliedType(TryClass.toType, List(definitions.AnyTpe))
val NonFatalClass = c.mirror.staticModule("scala.util.control.NonFatal")
@@ -202,14 +199,6 @@ private[async] final case class TransformUtils[C <: Context](c: C) {
val Async_await = asyncMember("await")
}
- /** `termSym( (_: Foo).bar(null: A, null: B)` will return the symbol of `bar`, after overload resolution. */
- private def methodSym(apply: c.Expr[Any]): Symbol = {
- val tree2: Tree = c.typeCheck(apply.tree)
- tree2.collect {
- case s: SymTree if s.symbol.isMethod => s.symbol
- }.headOption.getOrElse(sys.error(s"Unable to find a method symbol in ${apply.tree}"))
- }
-
/**
* Using [[scala.reflect.api.Trees.TreeCopier]] copies more than we would like:
* we don't want to copy types and symbols to the new trees in some cases.