File tree Expand file tree Collapse file tree 5 files changed +73
-34
lines changed
main/scala/scala/async/internal Expand file tree Collapse file tree 5 files changed +73
-34
lines changed Original file line number Diff line number Diff line change @@ -162,7 +162,14 @@ private[async] trait AnfTransform {
162
162
def _transformToList (tree : Tree ): List [Tree ] = trace(tree) {
163
163
val containsAwait = tree exists isAwait
164
164
if (! containsAwait) {
165
- List (tree)
165
+ tree match {
166
+ case Block (stats, expr) =>
167
+ // avoids nested block in `while(await(false)) ...`.
168
+ // TODO I think `containsAwait` really should return true if the code contains a label jump to an enclosing
169
+ // while/doWhile and there is an await *anywhere* inside that construct.
170
+ stats :+ expr
171
+ case _ => List (tree)
172
+ }
166
173
} else tree match {
167
174
case Select (qual, sel) =>
168
175
val stats :+ expr = linearize.transformToList(qual)
Original file line number Diff line number Diff line change @@ -127,7 +127,11 @@ trait ExprBuilder {
127
127
private var nextJumpState : Option [Int ] = None
128
128
129
129
def += (stat : Tree ): this .type = {
130
- assert(nextJumpState.isEmpty, s " statement appeared after a label jump: $stat" )
130
+ stat match {
131
+ case Literal (Constant (())) => // This case occurs in do/while
132
+ case _ =>
133
+ assert(nextJumpState.isEmpty, s " statement appeared after a label jump: $stat" )
134
+ }
131
135
def addStat () = stats += stat
132
136
stat match {
133
137
case Apply (fun, Nil ) =>
@@ -228,7 +232,7 @@ trait ExprBuilder {
228
232
currState = afterAwaitState
229
233
stateBuilder = new AsyncStateBuilder (currState, symLookup)
230
234
231
- case If (cond, thenp, elsep) if stat exists isAwait =>
235
+ case If (cond, thenp, elsep) if ( stat exists isAwait) || containsForiegnLabelJump(stat) =>
232
236
checkForUnsupportedAwait(cond)
233
237
234
238
val thenStartState = nextState()
Original file line number Diff line number Diff line change @@ -96,6 +96,19 @@ private[async] trait TransformUtils {
96
96
treeInfo.isExprSafeToInline(tree)
97
97
}
98
98
99
+ // `while(await(x))` ... or `do { await(x); ... } while(...)` contain an `If` that loops;
100
+ // we must break that `If` into states so that it convert the label jump into a state machine
101
+ // transition
102
+ final def containsForiegnLabelJump (t : Tree ): Boolean = {
103
+ val labelDefs = t.collect {
104
+ case ld : LabelDef => ld.symbol
105
+ }.toSet
106
+ t.exists {
107
+ case rt : RefTree => ! (labelDefs contains rt.symbol)
108
+ case _ => false
109
+ }
110
+ }
111
+
99
112
/** Map a list of arguments to:
100
113
* - A list of argument Trees
101
114
* - A list of auxillary results.
Original file line number Diff line number Diff line change @@ -66,43 +66,18 @@ object TreeInterrogation extends App {
66
66
withDebug {
67
67
val cm = reflect.runtime.currentMirror
68
68
val tb = mkToolbox(" -cp ${toolboxClasspath} -Xprint:typer -uniqid" )
69
- import scala .async .internal .AsyncTestLV ._
69
+ import scala .async .internal .AsyncId ._
70
70
val tree = tb.parse(
71
71
"""
72
- | import scala.async.internal.AsyncTestLV._
73
- | import scala.async.internal.AsyncTestLV
74
- |
75
- | case class MCell[T](var v: T)
76
- | val f = async { MCell(1) }
77
- |
78
- | def m1(x: MCell[Int], y: Int): Int =
79
- | async { x.v + y }
80
- | case class Cell[T](v: T)
81
- |
72
+ | import scala.async.internal.AsyncId._
82
73
| async {
83
- | // state #1
84
- | val a: MCell[Int] = await(f) // await$13$1
85
- | // state #2
86
- | var y = MCell(0)
87
- |
88
- | while (a.v < 10) {
89
- | // state #4
90
- | a.v = a.v + 1
91
- | y = MCell(await(a).v + 1) // await$14$1
92
- | // state #7
74
+ | var b = true
75
+ | while(await(b)) {
76
+ | b = false
93
77
| }
94
- |
95
- | // state #3
96
- | assert(AsyncTestLV.log.exists(entry => entry._1 == "await$14$1"))
97
- |
98
- | val b = await(m1(a, y.v)) // await$15$1
99
- | // state #8
100
- | assert(AsyncTestLV.log.exists(_ == ("a$1" -> MCell(10))))
101
- | assert(AsyncTestLV.log.exists(_ == ("y$1" -> MCell(11))))
102
- | b
78
+ | await(b)
103
79
| }
104
80
|
105
- |
106
81
| """ .stripMargin)
107
82
println(tree)
108
83
val tree1 = tb.typeCheck(tree.duplicate)
Original file line number Diff line number Diff line change @@ -76,4 +76,44 @@ class WhileSpec {
76
76
}
77
77
result mustBe ()
78
78
}
79
+
80
+ @ Test def doWhile () {
81
+ import AsyncId ._
82
+ val result = async {
83
+ var b = 0
84
+ var x = " "
85
+ await(do {
86
+ x += " 1"
87
+ x += await(" 2" )
88
+ x += " 3"
89
+ b += await(1 )
90
+ } while (b < 2 ))
91
+ await(x)
92
+ }
93
+ result mustBe " 123123"
94
+ }
95
+
96
+ @ Test def whileAwaitCondition () {
97
+ import AsyncId ._
98
+ val result = async {
99
+ var b = true
100
+ while (await(b)) {
101
+ b = false
102
+ }
103
+ await(b)
104
+ }
105
+ result mustBe false
106
+ }
107
+
108
+ @ Test def doWhileAwaitCondition () {
109
+ import AsyncId ._
110
+ val result = async {
111
+ var b = true
112
+ do {
113
+ b = false
114
+ } while (await(b))
115
+ b
116
+ }
117
+ result mustBe false
118
+ }
79
119
}
You can’t perform that action at this time.
0 commit comments