aboutsummaryrefslogtreecommitdiff
path: root/src/main/scala/scala/async/AnfTransform.scala
diff options
context:
space:
mode:
authorJason Zaugg <jzaugg@gmail.com>2012-11-22 17:50:50 +0100
committerJason Zaugg <jzaugg@gmail.com>2012-11-22 17:50:50 +0100
commit087d1e4e138eccf4b2d420298affb4289632bf73 (patch)
treefd0fc1c034f4cbc2d92fa7958c6b03c59e23aa92 /src/main/scala/scala/async/AnfTransform.scala
parent1c91fec998d09e31c2c52760452af1771a092182 (diff)
downloadscala-async-087d1e4e138eccf4b2d420298affb4289632bf73.tar.gz
scala-async-087d1e4e138eccf4b2d420298affb4289632bf73.tar.bz2
scala-async-087d1e4e138eccf4b2d420298affb4289632bf73.zip
Support match as an expression.
- corrects detection of await calls in the ANF transform. - Split AsyncAnalyzer into two parts. Unsupported await detection must happen prior to the async transform to prevent the ANF lifting out by-name arguments to vals and hence changing the semantics.
Diffstat (limited to 'src/main/scala/scala/async/AnfTransform.scala')
-rw-r--r--src/main/scala/scala/async/AnfTransform.scala54
1 files changed, 43 insertions, 11 deletions
diff --git a/src/main/scala/scala/async/AnfTransform.scala b/src/main/scala/scala/async/AnfTransform.scala
index e1d7cd5..0921b55 100644
--- a/src/main/scala/scala/async/AnfTransform.scala
+++ b/src/main/scala/scala/async/AnfTransform.scala
@@ -3,6 +3,7 @@ package scala.async
import scala.reflect.macros.Context
class AnfTransform[C <: Context](override val c: C) extends TransformUtils(c) {
+
import c.universe._
import AsyncUtils._
@@ -11,7 +12,7 @@ class AnfTransform[C <: Context](override val c: C) extends TransformUtils(c) {
val stats :+ expr = anf.transformToList(tree)
expr match {
- case Apply(fun, args) if fun.toString.startsWith("scala.async.Async.await") =>
+ case Apply(fun, args) if isAwait(fun) =>
val liftedName = c.fresh("await$")
stats :+ ValDef(NoMods, liftedName, TypeTree(), expr) :+ Ident(liftedName)
@@ -27,17 +28,35 @@ class AnfTransform[C <: Context](override val c: C) extends TransformUtils(c) {
ValDef(Modifiers(Flag.MUTABLE), liftedName, TypeTree(expr.tpe), defaultValue(expr.tpe))
val thenWithAssign = thenp match {
case Block(thenStats, thenExpr) => Block(thenStats, Assign(Ident(liftedName), thenExpr))
- case _ => Assign(Ident(liftedName), thenp)
+ case _ => Assign(Ident(liftedName), thenp)
}
val elseWithAssign = elsep match {
case Block(elseStats, elseExpr) => Block(elseStats, Assign(Ident(liftedName), elseExpr))
- case _ => Assign(Ident(liftedName), elsep)
+ case _ => Assign(Ident(liftedName), elsep)
}
val ifWithAssign =
If(cond, thenWithAssign, elseWithAssign)
stats :+ varDef :+ ifWithAssign :+ Ident(liftedName)
}
- case _ =>
+
+ case Match(scrut, cases) =>
+ // if type of match is Unit don't introduce assignment,
+ // but add Unit value to bring it into form expected by async transform
+ if (expr.tpe =:= definitions.UnitTpe) {
+ stats :+ expr :+ Literal(Constant(()))
+ }
+ else {
+ val liftedName = c.fresh("matchres$")
+ val varDef =
+ ValDef(Modifiers(Flag.MUTABLE), liftedName, TypeTree(expr.tpe), defaultValue(expr.tpe))
+ val casesWithAssign = cases map {
+ case CaseDef(pat, guard, Block(caseStats, caseExpr)) => CaseDef(pat, guard, Block(caseStats, Assign(Ident(liftedName), caseExpr)))
+ case CaseDef(pat, guard, tree) => CaseDef(pat, guard, Assign(Ident(liftedName), tree))
+ }
+ val matchWithAssign = Match(scrut, casesWithAssign)
+ stats :+ varDef :+ matchWithAssign :+ Ident(liftedName)
+ }
+ case _ =>
stats :+ expr
}
}
@@ -46,6 +65,10 @@ class AnfTransform[C <: Context](override val c: C) extends TransformUtils(c) {
case fst :: rest => transformToList(fst) ++ transformToList(rest)
case Nil => Nil
}
+
+ def transformToBlock(tree: Tree): Block = transformToList(tree) match {
+ case stats :+ expr => Block(stats, expr)
+ }
}
object anf {
@@ -59,7 +82,7 @@ class AnfTransform[C <: Context](override val c: C) extends TransformUtils(c) {
val argLists = args map inline.transformToList
val allArgStats = argLists flatMap (_.init)
val simpleArgs = argLists map (_.last)
- funStats ++ allArgStats :+ Apply(simpleFun, simpleArgs)
+ funStats ++ allArgStats :+ Apply(simpleFun, simpleArgs).setSymbol(tree.symbol)
case Block(stats, expr) =>
inline.transformToList(stats) ++ inline.transformToList(expr)
@@ -74,13 +97,22 @@ class AnfTransform[C <: Context](override val c: C) extends TransformUtils(c) {
case If(cond, thenp, elsep) =>
val stats :+ expr = inline.transformToList(cond)
- val thenStats :+ thenExpr = inline.transformToList(thenp)
- val elseStats :+ elseExpr = inline.transformToList(elsep)
+ val thenBlock = inline.transformToBlock(thenp)
+ val elseBlock = inline.transformToBlock(elsep)
stats :+
- c.typeCheck(If(expr, Block(thenStats, thenExpr), Block(elseStats, elseExpr)))
+ c.typeCheck(If(expr, thenBlock, elseBlock))
+
+ case Match(scrut, cases) =>
+ val scrutStats :+ scrutExpr = inline.transformToList(scrut)
+ val caseDefs = cases map {
+ case CaseDef(pat, guard, body) =>
+ val block = inline.transformToBlock(body)
+ CaseDef(pat, guard, block)
+ }
+ scrutStats :+ c.typeCheck(Match(scrutExpr, caseDefs))
//TODO
- case Literal(_) | Ident(_) | This(_) | Match(_, _) | New(_) | Function(_, _) => List(tree)
+ case Literal(_) | Ident(_) | This(_) | New(_) | Function(_, _) => List(tree)
case TypeApply(fun, targs) =>
val funStats :+ simpleFun = inline.transformToList(fun)
@@ -94,8 +126,8 @@ class AnfTransform[C <: Context](override val c: C) extends TransformUtils(c) {
case ModuleDef(mods, name, impl) => List(tree)
case _ =>
- c.error(tree.pos, "Internal error while compiling `async` block")
- ???
+ c.abort(tree.pos, s"Internal error while compiling `async` block: $tree")
}
}
+
}