diff options
Diffstat (limited to 'src/main/scala/scala')
-rw-r--r-- | src/main/scala/scala/async/internal/AnfTransform.scala | 9 | ||||
-rw-r--r-- | src/main/scala/scala/async/internal/ExprBuilder.scala | 8 | ||||
-rw-r--r-- | src/main/scala/scala/async/internal/TransformUtils.scala | 13 |
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. |