Skip to content

Commit c44d2ca

Browse files
committed
Merge pull request #99 from retronym/merge/2.10.x-to-master-20141219
Merge/2.10.x to master 20141219
2 parents 4951474 + 697f584 commit c44d2ca

File tree

9 files changed

+166
-88
lines changed

9 files changed

+166
-88
lines changed

src/main/scala/scala/async/internal/AsyncTransform.scala

Lines changed: 7 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -26,31 +26,24 @@ trait AsyncTransform {
2626

2727
val anfTree = futureSystemOps.postAnfTransform(anfTree0)
2828

29-
val resumeFunTreeDummyBody = DefDef(Modifiers(), name.resume, Nil, List(Nil), Ident(definitions.UnitClass), Literal(Constant(())))
30-
3129
val applyDefDefDummyBody: DefDef = {
3230
val applyVParamss = List(List(ValDef(Modifiers(Flag.PARAM), name.tr, TypeTree(futureSystemOps.tryType[Any]), EmptyTree)))
33-
DefDef(NoMods, name.apply, Nil, applyVParamss, TypeTree(definitions.UnitTpe), Literal(Constant(())))
31+
DefDef(NoMods, name.apply, Nil, applyVParamss, TypeTree(definitions.UnitTpe), literalUnit)
3432
}
3533

3634
// Create `ClassDef` of state machine with empty method bodies for `resume` and `apply`.
3735
val stateMachine: ClassDef = {
3836
val body: List[Tree] = {
39-
val stateVar = ValDef(Modifiers(Flag.MUTABLE | Flag.PRIVATE | Flag.LOCAL), name.state, TypeTree(definitions.IntTpe), Literal(Constant(0)))
37+
val stateVar = ValDef(Modifiers(Flag.MUTABLE | Flag.PRIVATE | Flag.LOCAL), name.state, TypeTree(definitions.IntTpe), Literal(Constant(StateAssigner.Initial)))
4038
val result = ValDef(NoMods, name.result, TypeTree(futureSystemOps.promType[T](uncheckedBoundsResultTag)), futureSystemOps.createProm[T](uncheckedBoundsResultTag).tree)
4139
val execContextValDef = ValDef(NoMods, name.execContext, TypeTree(), execContext)
4240

4341
val apply0DefDef: DefDef = {
4442
// We extend () => Unit so we can pass this class as the by-name argument to `Future.apply`.
45-
// See SI-1247 for the the optimization that avoids creatio
46-
DefDef(NoMods, name.apply, Nil, Nil, TypeTree(definitions.UnitTpe), Apply(Ident(name.resume), Nil))
47-
}
48-
val extraValDef: ValDef = {
49-
// We extend () => Unit so we can pass this class as the by-name argument to `Future.apply`.
50-
// See SI-1247 for the the optimization that avoids creatio
51-
ValDef(NoMods, newTermName("extra"), TypeTree(definitions.UnitTpe), Literal(Constant(())))
43+
// See SI-1247 for the the optimization that avoids creation.
44+
DefDef(NoMods, name.apply, Nil, Nil, TypeTree(definitions.UnitTpe), Apply(Ident(name.apply), literalNull :: Nil))
5245
}
53-
List(emptyConstructor, stateVar, result, execContextValDef) ++ List(resumeFunTreeDummyBody, applyDefDefDummyBody, apply0DefDef, extraValDef)
46+
List(emptyConstructor, stateVar, result, execContextValDef) ++ List(applyDefDefDummyBody, apply0DefDef)
5447
}
5548

5649
val tryToUnit = appliedType(definitions.FunctionClass(1), futureSystemOps.tryType[Any], typeOf[Unit])
@@ -92,8 +85,7 @@ trait AsyncTransform {
9285
val stateMachineSpliced: Tree = spliceMethodBodies(
9386
liftedFields,
9487
stateMachine,
95-
atMacroPos(asyncBlock.onCompleteHandler[T]),
96-
atMacroPos(asyncBlock.resumeFunTree[T].rhs)
88+
atMacroPos(asyncBlock.onCompleteHandler[T])
9789
)
9890

9991
def selectStateMachine(selection: TermName) = Select(Ident(name.stateMachine), selection)
@@ -133,10 +125,9 @@ trait AsyncTransform {
133125
* @param liftables trees of definitions that are lifted to fields of the state machine class
134126
* @param tree `ClassDef` tree of the state machine class
135127
* @param applyBody tree of onComplete handler (`apply` method)
136-
* @param resumeBody RHS of definition tree of `resume` method
137128
* @return transformed `ClassDef` tree of the state machine class
138129
*/
139-
def spliceMethodBodies(liftables: List[Tree], tree: ClassDef, applyBody: Tree, resumeBody: Tree): Tree = {
130+
def spliceMethodBodies(liftables: List[Tree], tree: ClassDef, applyBody: Tree): Tree = {
140131
val liftedSyms = liftables.map(_.symbol).toSet
141132
val stateMachineClass = tree.symbol
142133
liftedSyms.foreach {
@@ -202,12 +193,6 @@ trait AsyncTransform {
202193
(api: TypingTransformApi) =>
203194
val typedTree = fixup(dd, applyBody.changeOwner(enclosingOwner, dd.symbol), api)
204195
typedTree
205-
206-
case dd@DefDef(_, name.resume, _, _, _, _) if dd.symbol.owner == stateMachineClass =>
207-
(api: TypingTransformApi) =>
208-
val changed = resumeBody.changeOwner(enclosingOwner, dd.symbol)
209-
val res = fixup(dd, changed, api)
210-
res
211196
}
212197
result
213198
}

src/main/scala/scala/async/internal/ExprBuilder.scala

Lines changed: 71 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ trait ExprBuilder {
2828

2929
def nextStates: List[Int]
3030

31-
def mkHandlerCaseForState: CaseDef
31+
def mkHandlerCaseForState[T: WeakTypeTag]: CaseDef
3232

3333
def mkOnCompleteHandler[T: WeakTypeTag]: Option[CaseDef] = None
3434

@@ -52,8 +52,8 @@ trait ExprBuilder {
5252
def nextStates: List[Int] =
5353
List(nextState)
5454

55-
def mkHandlerCaseForState: CaseDef =
56-
mkHandlerCase(state, stats :+ mkStateTree(nextState, symLookup) :+ mkResumeApply(symLookup))
55+
def mkHandlerCaseForState[T: WeakTypeTag]: CaseDef =
56+
mkHandlerCase(state, stats :+ mkStateTree(nextState, symLookup))
5757

5858
override val toString: String =
5959
s"AsyncState #$state, next = $nextState"
@@ -63,7 +63,7 @@ trait ExprBuilder {
6363
* a branch of an `if` or a `match`.
6464
*/
6565
final class AsyncStateWithoutAwait(var stats: List[Tree], val state: Int, val nextStates: List[Int]) extends AsyncState {
66-
override def mkHandlerCaseForState: CaseDef =
66+
override def mkHandlerCaseForState[T: WeakTypeTag]: CaseDef =
6767
mkHandlerCase(state, stats)
6868

6969
override val toString: String =
@@ -73,45 +73,54 @@ trait ExprBuilder {
7373
/** A sequence of statements that concludes with an `await` call. The `onComplete`
7474
* handler will unconditionally transition to `nextState`.
7575
*/
76-
final class AsyncStateWithAwait(var stats: List[Tree], val state: Int, nextState: Int,
76+
final class AsyncStateWithAwait(var stats: List[Tree], val state: Int, onCompleteState: Int, nextState: Int,
7777
val awaitable: Awaitable, symLookup: SymLookup)
7878
extends AsyncState {
7979

8080
def nextStates: List[Int] =
8181
List(nextState)
8282

83-
override def mkHandlerCaseForState: CaseDef = {
84-
val callOnComplete = futureSystemOps.onComplete(c.Expr(awaitable.expr),
85-
c.Expr(This(tpnme.EMPTY)), c.Expr(Ident(name.execContext))).tree
86-
mkHandlerCase(state, stats :+ callOnComplete)
83+
override def mkHandlerCaseForState[T: WeakTypeTag]: CaseDef = {
84+
val fun = This(tpnme.EMPTY)
85+
val callOnComplete = futureSystemOps.onComplete[Any, Unit](c.Expr[futureSystem.Fut[Any]](awaitable.expr),
86+
c.Expr[futureSystem.Tryy[Any] => Unit](fun), c.Expr[futureSystem.ExecContext](Ident(name.execContext))).tree
87+
val tryGetOrCallOnComplete =
88+
if (futureSystemOps.continueCompletedFutureOnSameThread)
89+
If(futureSystemOps.isCompleted(c.Expr[futureSystem.Fut[_]](awaitable.expr)).tree,
90+
Block(ifIsFailureTree[T](futureSystemOps.getCompleted[Any](c.Expr[futureSystem.Fut[Any]](awaitable.expr)).tree) :: Nil, literalUnit),
91+
Block(callOnComplete :: Nil, Return(literalUnit)))
92+
else
93+
Block(callOnComplete :: Nil, Return(literalUnit))
94+
mkHandlerCase(state, stats ++ List(mkStateTree(onCompleteState, symLookup), tryGetOrCallOnComplete))
8795
}
8896

97+
private def tryGetTree(tryReference: => Tree) =
98+
Assign(
99+
Ident(awaitable.resultName),
100+
TypeApply(Select(futureSystemOps.tryyGet[Any](c.Expr[futureSystem.Tryy[Any]](tryReference)).tree, newTermName("asInstanceOf")), List(TypeTree(awaitable.resultType)))
101+
)
102+
103+
/* if (tr.isFailure)
104+
* result.complete(tr.asInstanceOf[Try[T]])
105+
* else {
106+
* <resultName> = tr.get.asInstanceOf[<resultType>]
107+
* <nextState>
108+
* <mkResumeApply>
109+
* }
110+
*/
111+
def ifIsFailureTree[T: WeakTypeTag](tryReference: => Tree) =
112+
If(futureSystemOps.tryyIsFailure(c.Expr[futureSystem.Tryy[T]](tryReference)).tree,
113+
Block(futureSystemOps.completeProm[T](
114+
c.Expr[futureSystem.Prom[T]](symLookup.memberRef(name.result)),
115+
c.Expr[futureSystem.Tryy[T]](
116+
TypeApply(Select(tryReference, newTermName("asInstanceOf")),
117+
List(TypeTree(futureSystemOps.tryType[T]))))).tree :: Nil,
118+
Return(literalUnit)),
119+
Block(List(tryGetTree(tryReference)), mkStateTree(nextState, symLookup))
120+
)
121+
89122
override def mkOnCompleteHandler[T: WeakTypeTag]: Option[CaseDef] = {
90-
val tryGetTree =
91-
Assign(
92-
Ident(awaitable.resultName),
93-
TypeApply(Select(futureSystemOps.tryyGet[T](c.Expr[futureSystem.Tryy[T]](Ident(symLookup.applyTrParam))).tree, newTermName("asInstanceOf")), List(TypeTree(awaitable.resultType)))
94-
)
95-
96-
/* if (tr.isFailure)
97-
* result.complete(tr.asInstanceOf[Try[T]])
98-
* else {
99-
* <resultName> = tr.get.asInstanceOf[<resultType>]
100-
* <nextState>
101-
* <mkResumeApply>
102-
* }
103-
*/
104-
val ifIsFailureTree =
105-
If(futureSystemOps.tryyIsFailure(c.Expr[futureSystem.Tryy[T]](Ident(symLookup.applyTrParam))).tree,
106-
futureSystemOps.completeProm[T](
107-
c.Expr[futureSystem.Prom[T]](symLookup.memberRef(name.result)),
108-
c.Expr[futureSystem.Tryy[T]](
109-
TypeApply(Select(Ident(symLookup.applyTrParam), newTermName("asInstanceOf")),
110-
List(TypeTree(futureSystemOps.tryType[T]))))).tree,
111-
Block(List(tryGetTree, mkStateTree(nextState, symLookup)), mkResumeApply(symLookup))
112-
)
113-
114-
Some(mkHandlerCase(state, List(ifIsFailureTree)))
123+
Some(mkHandlerCase(onCompleteState, List(ifIsFailureTree[T](Ident(symLookup.applyTrParam)))))
115124
}
116125

117126
override val toString: String =
@@ -147,9 +156,10 @@ trait ExprBuilder {
147156
}
148157

149158
def resultWithAwait(awaitable: Awaitable,
159+
onCompleteState: Int,
150160
nextState: Int): AsyncState = {
151161
val effectiveNextState = nextJumpState.getOrElse(nextState)
152-
new AsyncStateWithAwait(stats.toList, state, effectiveNextState, awaitable, symLookup)
162+
new AsyncStateWithAwait(stats.toList, state, onCompleteState, effectiveNextState, awaitable, symLookup)
153163
}
154164

155165
def resultSimple(nextState: Int): AsyncState = {
@@ -158,7 +168,7 @@ trait ExprBuilder {
158168
}
159169

160170
def resultWithIf(condTree: Tree, thenState: Int, elseState: Int): AsyncState = {
161-
def mkBranch(state: Int) = Block(mkStateTree(state, symLookup) :: Nil, mkResumeApply(symLookup))
171+
def mkBranch(state: Int) = mkStateTree(state, symLookup)
162172
this += If(condTree, mkBranch(thenState), mkBranch(elseState))
163173
new AsyncStateWithoutAwait(stats.toList, state, List(thenState, elseState))
164174
}
@@ -178,15 +188,15 @@ trait ExprBuilder {
178188
val newCases = for ((cas, num) <- cases.zipWithIndex) yield cas match {
179189
case CaseDef(pat, guard, rhs) =>
180190
val bindAssigns = rhs.children.takeWhile(isSyntheticBindVal)
181-
CaseDef(pat, guard, Block(bindAssigns :+ mkStateTree(caseStates(num), symLookup), mkResumeApply(symLookup)))
191+
CaseDef(pat, guard, Block(bindAssigns, mkStateTree(caseStates(num), symLookup)))
182192
}
183193
// 2. insert changed match tree at the end of the current state
184194
this += Match(scrutTree, newCases)
185195
new AsyncStateWithoutAwait(stats.toList, state, caseStates)
186196
}
187197

188198
def resultWithLabel(startLabelState: Int, symLookup: SymLookup): AsyncState = {
189-
this += Block(mkStateTree(startLabelState, symLookup) :: Nil, mkResumeApply(symLookup))
199+
this += mkStateTree(startLabelState, symLookup)
190200
new AsyncStateWithoutAwait(stats.toList, state, List(startLabelState))
191201
}
192202

@@ -227,9 +237,10 @@ trait ExprBuilder {
227237
for (stat <- stats) stat match {
228238
// the val name = await(..) pattern
229239
case vd @ ValDef(mods, name, tpt, Apply(fun, arg :: Nil)) if isAwait(fun) =>
240+
val onCompleteState = nextState()
230241
val afterAwaitState = nextState()
231242
val awaitable = Awaitable(arg, stat.symbol, tpt.tpe, vd)
232-
asyncStates += stateBuilder.resultWithAwait(awaitable, afterAwaitState) // complete with await
243+
asyncStates += stateBuilder.resultWithAwait(awaitable, onCompleteState, afterAwaitState) // complete with await
233244
currState = afterAwaitState
234245
stateBuilder = new AsyncStateBuilder(currState, symLookup)
235246

@@ -297,8 +308,6 @@ trait ExprBuilder {
297308
def asyncStates: List[AsyncState]
298309

299310
def onCompleteHandler[T: WeakTypeTag]: Tree
300-
301-
def resumeFunTree[T: WeakTypeTag]: DefDef
302311
}
303312

304313
case class SymLookup(stateMachineClass: Symbol, applyTrParam: Symbol) {
@@ -331,13 +340,13 @@ trait ExprBuilder {
331340
val lastStateBody = c.Expr[T](lastState.body)
332341
val rhs = futureSystemOps.completeProm(
333342
c.Expr[futureSystem.Prom[T]](symLookup.memberRef(name.result)), futureSystemOps.tryySuccess[T](lastStateBody))
334-
mkHandlerCase(lastState.state, rhs.tree)
343+
mkHandlerCase(lastState.state, Block(rhs.tree, Return(literalUnit)))
335344
}
336345
asyncStates.toList match {
337346
case s :: Nil =>
338347
List(caseForLastState)
339348
case _ =>
340-
val initCases = for (state <- asyncStates.toList.init) yield state.mkHandlerCaseForState
349+
val initCases = for (state <- asyncStates.toList.init) yield state.mkHandlerCaseForState[T]
341350
initCases :+ caseForLastState
342351
}
343352
}
@@ -363,18 +372,23 @@ trait ExprBuilder {
363372
* }
364373
* }
365374
*/
366-
def resumeFunTree[T: WeakTypeTag]: DefDef =
367-
DefDef(Modifiers(), name.resume, Nil, List(Nil), Ident(definitions.UnitClass),
375+
private def resumeFunTree[T: WeakTypeTag]: Tree =
368376
Try(
369-
Match(symLookup.memberRef(name.state), mkCombinedHandlerCases[T]),
377+
Match(symLookup.memberRef(name.state), mkCombinedHandlerCases[T] ++ initStates.flatMap(_.mkOnCompleteHandler[T]) ),
370378
List(
371379
CaseDef(
372380
Bind(name.t, Ident(nme.WILDCARD)),
373381
Apply(Ident(defn.NonFatalClass), List(Ident(name.t))), {
374382
val t = c.Expr[Throwable](Ident(name.t))
375-
futureSystemOps.completeProm[T](
383+
val complete = futureSystemOps.completeProm[T](
376384
c.Expr[futureSystem.Prom[T]](symLookup.memberRef(name.result)), futureSystemOps.tryyFailure[T](t)).tree
377-
})), EmptyTree))
385+
Block(complete :: Nil, Return(literalUnit))
386+
})), EmptyTree)
387+
388+
def forever(t: Tree): Tree = {
389+
val labelName = name.fresh("while$")
390+
LabelDef(labelName, Nil, Block(t :: Nil, Apply(Ident(labelName), Nil)))
391+
}
378392

379393
/**
380394
* Builds a `match` expression used as an onComplete handler.
@@ -388,8 +402,12 @@ trait ExprBuilder {
388402
* resume()
389403
* }
390404
*/
391-
def onCompleteHandler[T: WeakTypeTag]: Tree =
392-
Match(symLookup.memberRef(name.state), initStates.flatMap(_.mkOnCompleteHandler[T]).toList)
405+
def onCompleteHandler[T: WeakTypeTag]: Tree = {
406+
val onCompletes = initStates.flatMap(_.mkOnCompleteHandler[T]).toList
407+
forever {
408+
Block(resumeFunTree :: Nil, literalUnit)
409+
}
410+
}
393411
}
394412
}
395413

@@ -400,9 +418,6 @@ trait ExprBuilder {
400418

401419
case class Awaitable(expr: Tree, resultName: Symbol, resultType: Type, resultValDef: ValDef)
402420

403-
private def mkResumeApply(symLookup: SymLookup) =
404-
Apply(symLookup.memberRef(name.resume), Nil)
405-
406421
private def mkStateTree(nextState: Int, symLookup: SymLookup): Tree =
407422
Assign(symLookup.memberRef(name.state), Literal(Constant(nextState)))
408423

@@ -412,5 +427,7 @@ trait ExprBuilder {
412427
private def mkHandlerCase(num: Int, rhs: Tree): CaseDef =
413428
CaseDef(Literal(Constant(num)), EmptyTree, rhs)
414429

415-
private def literalUnit = Literal(Constant(()))
430+
def literalUnit = Literal(Constant(()))
431+
432+
def literalNull = Literal(Constant(null))
416433
}

src/main/scala/scala/async/internal/FutureSystem.scala

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,12 @@ trait FutureSystem {
4747
def onComplete[A, U](future: Expr[Fut[A]], fun: Expr[Tryy[A] => U],
4848
execContext: Expr[ExecContext]): Expr[Unit]
4949

50+
def continueCompletedFutureOnSameThread = false
51+
def isCompleted(future: Expr[Fut[_]]): Expr[Boolean] =
52+
throw new UnsupportedOperationException("isCompleted not supported by this FutureSystem")
53+
def getCompleted[A: WeakTypeTag](future: Expr[Fut[A]]): Expr[Tryy[A]] =
54+
throw new UnsupportedOperationException("getCompleted not supported by this FutureSystem")
55+
5056
/** Complete a promise with a value */
5157
def completeProm[A](prom: Expr[Prom[A]], value: Expr[Tryy[A]]): Expr[Unit]
5258

@@ -100,6 +106,15 @@ object ScalaConcurrentFutureSystem extends FutureSystem {
100106
future.splice.onComplete(fun.splice)(execContext.splice)
101107
}
102108

109+
override def continueCompletedFutureOnSameThread: Boolean = true
110+
111+
override def isCompleted(future: Expr[Fut[_]]): Expr[Boolean] = reify {
112+
future.splice.isCompleted
113+
}
114+
override def getCompleted[A: WeakTypeTag](future: Expr[Fut[A]]): Expr[Tryy[A]] = reify {
115+
future.splice.value.get
116+
}
117+
103118
def completeProm[A](prom: Expr[Prom[A]], value: Expr[scala.util.Try[A]]): Expr[Unit] = reify {
104119
prom.splice.complete(value.splice)
105120
c.Expr[Unit](Literal(Constant(()))).splice

src/main/scala/scala/async/internal/StateAssigner.scala

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@
55
package scala.async.internal
66

77
private[async] final class StateAssigner {
8-
private var current = -1
8+
private var current = StateAssigner.Initial
99

10-
def nextState(): Int = {
11-
current += 1
12-
current
13-
}
10+
def nextState(): Int =
11+
try current finally current += 1
1412
}
13+
14+
object StateAssigner {
15+
final val Initial = 0
16+
}

src/main/scala/scala/async/internal/TransformUtils.scala

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ private[async] trait TransformUtils {
119119

120120
private def isByName(fun: Tree): ((Int, Int) => Boolean) = {
121121
if (Boolean_ShortCircuits contains fun.symbol) (i, j) => true
122+
else if (fun.tpe == null) (x, y) => false
122123
else {
123124
val paramss = fun.tpe.paramss
124125
val byNamess = paramss.map(_.map(_.asTerm.isByNameParam))
@@ -140,10 +141,6 @@ private[async] trait TransformUtils {
140141
self.splice.contains(elem.splice)
141142
}
142143

143-
def mkFunction_apply[A, B](self: Expr[Function1[A, B]])(arg: Expr[A]) = reify {
144-
self.splice.apply(arg.splice)
145-
}
146-
147144
def mkAny_==(self: Expr[Any])(other: Expr[Any]) = reify {
148145
self.splice == other.splice
149146
}

0 commit comments

Comments
 (0)