From 9d134adc8e448906ee6ab6cb4db59320557a880c Mon Sep 17 00:00:00 2001 From: Philipp Haller Date: Fri, 26 Apr 2013 17:21:10 +0200 Subject: 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. --- src/main/scala/scala/async/ExprBuilder.scala | 4 +- src/main/scala/scala/async/FutureSystem.scala | 67 ++++++++++++++++++------- src/main/scala/scala/async/TransformUtils.scala | 11 ---- 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. -- cgit v1.2.3