aboutsummaryrefslogtreecommitdiff
path: root/src/main/scala/scala
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/scala/scala')
-rw-r--r--src/main/scala/scala/async/internal/AnfTransform.scala9
-rw-r--r--src/main/scala/scala/async/internal/ExprBuilder.scala8
-rw-r--r--src/main/scala/scala/async/internal/TransformUtils.scala13
3 files changed, 27 insertions, 3 deletions
diff --git a/src/main/scala/scala/async/internal/AnfTransform.scala b/src/main/scala/scala/async/internal/AnfTransform.scala
index f19a87a..8518cf5 100644
--- a/src/main/scala/scala/async/internal/AnfTransform.scala
+++ b/src/main/scala/scala/async/internal/AnfTransform.scala
@@ -162,7 +162,14 @@ private[async] trait AnfTransform {
def _transformToList(tree: Tree): List[Tree] = trace(tree) {
val containsAwait = tree exists isAwait
if (!containsAwait) {
- List(tree)
+ tree match {
+ case Block(stats, expr) =>
+ // avoids nested block in `while(await(false)) ...`.
+ // TODO I think `containsAwait` really should return true if the code contains a label jump to an enclosing
+ // while/doWhile and there is an await *anywhere* inside that construct.
+ stats :+ expr
+ case _ => List(tree)
+ }
} else tree match {
case Select(qual, sel) =>
val stats :+ expr = linearize.transformToList(qual)
diff --git a/src/main/scala/scala/async/internal/ExprBuilder.scala b/src/main/scala/scala/async/internal/ExprBuilder.scala
index 85e0953..b0cd914 100644
--- a/src/main/scala/scala/async/internal/ExprBuilder.scala
+++ b/src/main/scala/scala/async/internal/ExprBuilder.scala
@@ -127,7 +127,11 @@ trait ExprBuilder {
private var nextJumpState: Option[Int] = None
def +=(stat: Tree): this.type = {
- assert(nextJumpState.isEmpty, s"statement appeared after a label jump: $stat")
+ stat match {
+ case Literal(Constant(())) => // This case occurs in do/while
+ case _ =>
+ assert(nextJumpState.isEmpty, s"statement appeared after a label jump: $stat")
+ }
def addStat() = stats += stat
stat match {
case Apply(fun, Nil) =>
@@ -228,7 +232,7 @@ trait ExprBuilder {
currState = afterAwaitState
stateBuilder = new AsyncStateBuilder(currState, symLookup)
- case If(cond, thenp, elsep) if stat exists isAwait =>
+ case If(cond, thenp, elsep) if (stat exists isAwait) || containsForiegnLabelJump(stat) =>
checkForUnsupportedAwait(cond)
val thenStartState = nextState()
diff --git a/src/main/scala/scala/async/internal/TransformUtils.scala b/src/main/scala/scala/async/internal/TransformUtils.scala
index 71fddaa..e382c62 100644
--- a/src/main/scala/scala/async/internal/TransformUtils.scala
+++ b/src/main/scala/scala/async/internal/TransformUtils.scala
@@ -96,6 +96,19 @@ private[async] trait TransformUtils {
treeInfo.isExprSafeToInline(tree)
}
+ // `while(await(x))` ... or `do { await(x); ... } while(...)` contain an `If` that loops;
+ // we must break that `If` into states so that it convert the label jump into a state machine
+ // transition
+ final def containsForiegnLabelJump(t: Tree): Boolean = {
+ val labelDefs = t.collect {
+ case ld: LabelDef => ld.symbol
+ }.toSet
+ t.exists {
+ case rt: RefTree => !(labelDefs contains rt.symbol)
+ case _ => false
+ }
+ }
+
/** Map a list of arguments to:
* - A list of argument Trees
* - A list of auxillary results.