diff --git a/src/compiler/scala/tools/nsc/transform/async/AnfTransform.scala b/src/compiler/scala/tools/nsc/transform/async/AnfTransform.scala index 69ac07cc3387..8e85536f92b4 100644 --- a/src/compiler/scala/tools/nsc/transform/async/AnfTransform.scala +++ b/src/compiler/scala/tools/nsc/transform/async/AnfTransform.scala @@ -164,6 +164,8 @@ private[async] trait AnfTransform extends TransformUtils { case ld @ LabelDef(name, params, rhs) => treeCopy.LabelDef(tree, name, params, transformNewControlFlowBlock(rhs)) + case t @ Typed(expr, tpt) => + transform(expr).setType(t.tpe) case _ => super.transform(tree) } diff --git a/src/compiler/scala/tools/nsc/transform/async/AsyncNames.scala b/src/compiler/scala/tools/nsc/transform/async/AsyncNames.scala index cb30576914c1..29fa11a714e9 100644 --- a/src/compiler/scala/tools/nsc/transform/async/AsyncNames.scala +++ b/src/compiler/scala/tools/nsc/transform/async/AsyncNames.scala @@ -43,6 +43,7 @@ final class AsyncNames[U <: reflect.internal.Names with Singleton](val u: U) { } private val matchRes: TermNameCache = new TermNameCache("match") private val ifRes: TermNameCache = new TermNameCache("if") + private val qual: TermNameCache = new TermNameCache("qual") private val await: TermNameCache = new TermNameCache("await") @@ -54,6 +55,7 @@ final class AsyncNames[U <: reflect.internal.Names with Singleton](val u: U) { class AsyncName { final val matchRes = new NameSource[U#TermName](self.matchRes) final val ifRes = new NameSource[U#TermName](self.ifRes) + final val qual = new NameSource[U#TermName](self.qual) final val await = new NameSource[U#TermName](self.await) private val seenPrefixes = mutable.AnyRefMap[Name, AtomicInteger]() diff --git a/src/compiler/scala/tools/nsc/transform/async/ExprBuilder.scala b/src/compiler/scala/tools/nsc/transform/async/ExprBuilder.scala index 5a5c79dd0aab..aec329ea2a54 100644 --- a/src/compiler/scala/tools/nsc/transform/async/ExprBuilder.scala +++ b/src/compiler/scala/tools/nsc/transform/async/ExprBuilder.scala @@ -113,7 +113,14 @@ trait ExprBuilder extends TransformUtils { // An exception should bubble out to the enclosing handler, don't insert a complete call. } else { val expr = stats.remove(stats.size - 1) - stats += completeSuccess(expr) + def pushIntoMatchEnd(t: Tree): Tree = { + t match { + case MatchEnd(ld) => treeCopy.LabelDef(ld, ld.name, ld.params, pushIntoMatchEnd(ld.rhs)) + case b@Block(caseStats, caseExpr) => assignUnitType(treeCopy.Block(b, caseStats, pushIntoMatchEnd(caseExpr))) + case expr => completeSuccess(expr) + } + } + stats += pushIntoMatchEnd(expr) } stats += typed(Return(literalUnit).setSymbol(currentTransformState.applySym)) allNextStates -= nextState @@ -243,7 +250,7 @@ trait ExprBuilder extends TransformUtils { } case ld @ LabelDef(name, params, rhs) => - if (isCaseLabel(ld.symbol) || isMatchEndLabel(ld.symbol)) { + if (isCaseLabel(ld.symbol) || (isMatchEndLabel(ld.symbol) && labelDefStates.contains(ld.symbol))) { // LabelDefs from patterns are a bit trickier as they can (forward) branch to each other. labelDefStates.get(ld.symbol).foreach { startLabelState => @@ -259,7 +266,7 @@ trait ExprBuilder extends TransformUtils { } val afterLabelState = afterState() - val (inlinedState, nestedStates) = buildNestedStatesFirstForInlining(rhs, afterLabelState) + val (inlinedState, nestedStates) = buildNestedStatesFirstForInlining(rhs, afterLabelState) // Leave this label here for synchronous jumps from previous cases. This is // allowed even if this case has its own state (ie if there is an asynchrounous path @@ -288,7 +295,6 @@ trait ExprBuilder extends TransformUtils { checkForUnsupportedAwait(stat) stateBuilder += stat } - case _ => checkForUnsupportedAwait(stat) stateBuilder += stat diff --git a/test/junit/scala/tools/nsc/async/AnnotationDrivenAsync.scala b/test/junit/scala/tools/nsc/async/AnnotationDrivenAsync.scala index fb68c2b420a1..d2e4680056fc 100644 --- a/test/junit/scala/tools/nsc/async/AnnotationDrivenAsync.scala +++ b/test/junit/scala/tools/nsc/async/AnnotationDrivenAsync.scala @@ -34,6 +34,43 @@ class AnnotationDrivenAsync { assertEquals(3, run(code)) } + @Test + def patternTailPosition(): Unit = { + val code = + """ + |import scala.concurrent._, duration.Duration, ExecutionContext.Implicits.global + |import scala.tools.partest.async.Async.{async, await} + |import Future.{successful => f} + | + |object Test { + | def test = async { + | { + | await(f(1)) + | "foo" match { + | case x if "".isEmpty => x + | } + | }: AnyRef + | } + |} + |""".stripMargin + assertEquals("foo", run(code)) + } + + @Test + def awaitTyped(): Unit = { + val code = + """ + |import scala.concurrent._, duration.Duration, ExecutionContext.Implicits.global + |import scala.tools.partest.async.Async.{async, await} + |import Future.{successful => f} + | + |object Test { + | def test = async {(("msg: " + await(f(0))): String).toString} + |} + |""".stripMargin + assertEquals("msg: 0", run(code)) + } + @Test def testBooleanAndOr(): Unit = { val code = @@ -646,8 +683,8 @@ class AnnotationDrivenAsync { // settings.debug.value = true // settings.uniqid.value = true - // settings.processArgumentString("-Xprint:async -nowarn") - // settings.log.value = List("async") + settings.processArgumentString("-Xprint:async -nowarn") + settings.log.value = List("async") // NOTE: edit ANFTransform.traceAsync to `= true` to get additional diagnostic tracing.