diff options
Diffstat (limited to 'src/main/scala/scala/async/internal/ExprBuilder.scala')
-rw-r--r-- | src/main/scala/scala/async/internal/ExprBuilder.scala | 125 |
1 files changed, 71 insertions, 54 deletions
diff --git a/src/main/scala/scala/async/internal/ExprBuilder.scala b/src/main/scala/scala/async/internal/ExprBuilder.scala index 5314ae0..2dd485d 100644 --- a/src/main/scala/scala/async/internal/ExprBuilder.scala +++ b/src/main/scala/scala/async/internal/ExprBuilder.scala @@ -27,7 +27,7 @@ trait ExprBuilder { def nextStates: List[Int] - def mkHandlerCaseForState: CaseDef + def mkHandlerCaseForState[T: WeakTypeTag]: CaseDef def mkOnCompleteHandler[T: WeakTypeTag]: Option[CaseDef] = None @@ -51,8 +51,8 @@ trait ExprBuilder { def nextStates: List[Int] = List(nextState) - def mkHandlerCaseForState: CaseDef = - mkHandlerCase(state, stats :+ mkStateTree(nextState, symLookup) :+ mkResumeApply(symLookup)) + def mkHandlerCaseForState[T: WeakTypeTag]: CaseDef = + mkHandlerCase(state, stats :+ mkStateTree(nextState, symLookup)) override val toString: String = s"AsyncState #$state, next = $nextState" @@ -62,7 +62,7 @@ trait ExprBuilder { * a branch of an `if` or a `match`. */ final class AsyncStateWithoutAwait(var stats: List[Tree], val state: Int, val nextStates: List[Int]) extends AsyncState { - override def mkHandlerCaseForState: CaseDef = + override def mkHandlerCaseForState[T: WeakTypeTag]: CaseDef = mkHandlerCase(state, stats) override val toString: String = @@ -72,45 +72,54 @@ trait ExprBuilder { /** A sequence of statements that concludes with an `await` call. The `onComplete` * handler will unconditionally transition to `nextState`. */ - final class AsyncStateWithAwait(var stats: List[Tree], val state: Int, nextState: Int, + final class AsyncStateWithAwait(var stats: List[Tree], val state: Int, onCompleteState: Int, nextState: Int, val awaitable: Awaitable, symLookup: SymLookup) extends AsyncState { def nextStates: List[Int] = List(nextState) - override def mkHandlerCaseForState: CaseDef = { - val callOnComplete = futureSystemOps.onComplete(Expr(awaitable.expr), - Expr(This(tpnme.EMPTY)), Expr(Ident(name.execContext))).tree - mkHandlerCase(state, stats :+ callOnComplete) + override def mkHandlerCaseForState[T: WeakTypeTag]: CaseDef = { + val fun = This(tpnme.EMPTY) + val callOnComplete = futureSystemOps.onComplete[Any, Unit](Expr[futureSystem.Fut[Any]](awaitable.expr), + Expr[futureSystem.Tryy[Any] => Unit](fun), Expr[futureSystem.ExecContext](Ident(name.execContext))).tree + val tryGetOrCallOnComplete = + if (futureSystemOps.continueCompletedFutureOnSameThread) + If(futureSystemOps.isCompleted(Expr[futureSystem.Fut[_]](awaitable.expr)).tree, + Block(ifIsFailureTree[T](futureSystemOps.getCompleted[Any](Expr[futureSystem.Fut[Any]](awaitable.expr)).tree) :: Nil, literalUnit), + Block(callOnComplete :: Nil, Return(literalUnit))) + else + Block(callOnComplete :: Nil, Return(literalUnit)) + mkHandlerCase(state, stats ++ List(mkStateTree(onCompleteState, symLookup), tryGetOrCallOnComplete)) } + private def tryGetTree(tryReference: => Tree) = + Assign( + Ident(awaitable.resultName), + TypeApply(Select(futureSystemOps.tryyGet[Any](Expr[futureSystem.Tryy[Any]](tryReference)).tree, newTermName("asInstanceOf")), List(TypeTree(awaitable.resultType))) + ) + + /* if (tr.isFailure) + * result.complete(tr.asInstanceOf[Try[T]]) + * else { + * <resultName> = tr.get.asInstanceOf[<resultType>] + * <nextState> + * <mkResumeApply> + * } + */ + def ifIsFailureTree[T: WeakTypeTag](tryReference: => Tree) = + If(futureSystemOps.tryyIsFailure(Expr[futureSystem.Tryy[T]](tryReference)).tree, + Block(futureSystemOps.completeProm[T]( + Expr[futureSystem.Prom[T]](symLookup.memberRef(name.result)), + Expr[futureSystem.Tryy[T]]( + TypeApply(Select(tryReference, newTermName("asInstanceOf")), + List(TypeTree(futureSystemOps.tryType[T]))))).tree :: Nil, + Return(literalUnit)), + Block(List(tryGetTree(tryReference)), mkStateTree(nextState, symLookup)) + ) + override def mkOnCompleteHandler[T: WeakTypeTag]: Option[CaseDef] = { - val tryGetTree = - Assign( - Ident(awaitable.resultName), - TypeApply(Select(futureSystemOps.tryyGet[T](Expr[futureSystem.Tryy[T]](Ident(symLookup.applyTrParam))).tree, newTermName("asInstanceOf")), List(TypeTree(awaitable.resultType))) - ) - - /* if (tr.isFailure) - * result.complete(tr.asInstanceOf[Try[T]]) - * else { - * <resultName> = tr.get.asInstanceOf[<resultType>] - * <nextState> - * <mkResumeApply> - * } - */ - val ifIsFailureTree = - If(futureSystemOps.tryyIsFailure(Expr[futureSystem.Tryy[T]](Ident(symLookup.applyTrParam))).tree, - futureSystemOps.completeProm[T]( - Expr[futureSystem.Prom[T]](symLookup.memberRef(name.result)), - Expr[futureSystem.Tryy[T]]( - TypeApply(Select(Ident(symLookup.applyTrParam), newTermName("asInstanceOf")), - List(TypeTree(futureSystemOps.tryType[T]))))).tree, - Block(List(tryGetTree, mkStateTree(nextState, symLookup)), mkResumeApply(symLookup)) - ) - - Some(mkHandlerCase(state, List(ifIsFailureTree))) + Some(mkHandlerCase(onCompleteState, List(ifIsFailureTree[T](Ident(symLookup.applyTrParam))))) } override val toString: String = @@ -146,9 +155,10 @@ trait ExprBuilder { } def resultWithAwait(awaitable: Awaitable, + onCompleteState: Int, nextState: Int): AsyncState = { val effectiveNextState = nextJumpState.getOrElse(nextState) - new AsyncStateWithAwait(stats.toList, state, effectiveNextState, awaitable, symLookup) + new AsyncStateWithAwait(stats.toList, state, onCompleteState, effectiveNextState, awaitable, symLookup) } def resultSimple(nextState: Int): AsyncState = { @@ -157,7 +167,7 @@ trait ExprBuilder { } def resultWithIf(condTree: Tree, thenState: Int, elseState: Int): AsyncState = { - def mkBranch(state: Int) = Block(mkStateTree(state, symLookup) :: Nil, mkResumeApply(symLookup)) + def mkBranch(state: Int) = mkStateTree(state, symLookup) this += If(condTree, mkBranch(thenState), mkBranch(elseState)) new AsyncStateWithoutAwait(stats.toList, state, List(thenState, elseState)) } @@ -177,7 +187,7 @@ trait ExprBuilder { val newCases = for ((cas, num) <- cases.zipWithIndex) yield cas match { case CaseDef(pat, guard, rhs) => val bindAssigns = rhs.children.takeWhile(isSyntheticBindVal) - CaseDef(pat, guard, Block(bindAssigns :+ mkStateTree(caseStates(num), symLookup), mkResumeApply(symLookup))) + CaseDef(pat, guard, Block(bindAssigns, mkStateTree(caseStates(num), symLookup))) } // 2. insert changed match tree at the end of the current state this += Match(scrutTree, newCases) @@ -185,7 +195,7 @@ trait ExprBuilder { } def resultWithLabel(startLabelState: Int, symLookup: SymLookup): AsyncState = { - this += Block(mkStateTree(startLabelState, symLookup) :: Nil, mkResumeApply(symLookup)) + this += mkStateTree(startLabelState, symLookup) new AsyncStateWithoutAwait(stats.toList, state, List(startLabelState)) } @@ -226,9 +236,10 @@ trait ExprBuilder { for (stat <- stats) stat match { // the val name = await(..) pattern case vd @ ValDef(mods, name, tpt, Apply(fun, arg :: Nil)) if isAwait(fun) => + val onCompleteState = nextState() val afterAwaitState = nextState() val awaitable = Awaitable(arg, stat.symbol, tpt.tpe, vd) - asyncStates += stateBuilder.resultWithAwait(awaitable, afterAwaitState) // complete with await + asyncStates += stateBuilder.resultWithAwait(awaitable, onCompleteState, afterAwaitState) // complete with await currState = afterAwaitState stateBuilder = new AsyncStateBuilder(currState, symLookup) @@ -296,8 +307,6 @@ trait ExprBuilder { def asyncStates: List[AsyncState] def onCompleteHandler[T: WeakTypeTag]: Tree - - def resumeFunTree[T: WeakTypeTag]: DefDef } case class SymLookup(stateMachineClass: Symbol, applyTrParam: Symbol) { @@ -330,13 +339,13 @@ trait ExprBuilder { val lastStateBody = Expr[T](lastState.body) val rhs = futureSystemOps.completeProm( Expr[futureSystem.Prom[T]](symLookup.memberRef(name.result)), futureSystemOps.tryySuccess[T](lastStateBody)) - mkHandlerCase(lastState.state, rhs.tree) + mkHandlerCase(lastState.state, Block(rhs.tree, Return(literalUnit))) } asyncStates.toList match { case s :: Nil => List(caseForLastState) case _ => - val initCases = for (state <- asyncStates.toList.init) yield state.mkHandlerCaseForState + val initCases = for (state <- asyncStates.toList.init) yield state.mkHandlerCaseForState[T] initCases :+ caseForLastState } } @@ -362,18 +371,23 @@ trait ExprBuilder { * } * } */ - def resumeFunTree[T: WeakTypeTag]: DefDef = - DefDef(Modifiers(), name.resume, Nil, List(Nil), Ident(definitions.UnitClass), + private def resumeFunTree[T: WeakTypeTag]: Tree = Try( - Match(symLookup.memberRef(name.state), mkCombinedHandlerCases[T]), + Match(symLookup.memberRef(name.state), mkCombinedHandlerCases[T] ++ initStates.flatMap(_.mkOnCompleteHandler[T]) ), List( CaseDef( Bind(name.t, Ident(nme.WILDCARD)), Apply(Ident(defn.NonFatalClass), List(Ident(name.t))), { val t = Expr[Throwable](Ident(name.t)) - futureSystemOps.completeProm[T]( + val complete = futureSystemOps.completeProm[T]( Expr[futureSystem.Prom[T]](symLookup.memberRef(name.result)), futureSystemOps.tryyFailure[T](t)).tree - })), EmptyTree)) + Block(complete :: Nil, Return(literalUnit)) + })), EmptyTree) + + def forever(t: Tree): Tree = { + val labelName = name.fresh("while$") + LabelDef(labelName, Nil, Block(t :: Nil, Apply(Ident(labelName), Nil))) + } /** * Builds a `match` expression used as an onComplete handler. @@ -387,8 +401,12 @@ trait ExprBuilder { * resume() * } */ - def onCompleteHandler[T: WeakTypeTag]: Tree = - Match(symLookup.memberRef(name.state), initStates.flatMap(_.mkOnCompleteHandler[T]).toList) + def onCompleteHandler[T: WeakTypeTag]: Tree = { + val onCompletes = initStates.flatMap(_.mkOnCompleteHandler[T]).toList + forever { + Block(resumeFunTree :: Nil, literalUnit) + } + } } } @@ -399,9 +417,6 @@ trait ExprBuilder { case class Awaitable(expr: Tree, resultName: Symbol, resultType: Type, resultValDef: ValDef) - private def mkResumeApply(symLookup: SymLookup) = - Apply(symLookup.memberRef(name.resume), Nil) - private def mkStateTree(nextState: Int, symLookup: SymLookup): Tree = Assign(symLookup.memberRef(name.state), Literal(Constant(nextState))) @@ -411,5 +426,7 @@ trait ExprBuilder { private def mkHandlerCase(num: Int, rhs: Tree): CaseDef = CaseDef(Literal(Constant(num)), EmptyTree, rhs) - private def literalUnit = Literal(Constant(())) + def literalUnit = Literal(Constant(())) + + def literalNull = Literal(Constant(null)) } |