diff options
author | Jason Zaugg <jzaugg@gmail.com> | 2012-11-22 17:50:50 +0100 |
---|---|---|
committer | Jason Zaugg <jzaugg@gmail.com> | 2012-11-22 17:50:50 +0100 |
commit | 087d1e4e138eccf4b2d420298affb4289632bf73 (patch) | |
tree | fd0fc1c034f4cbc2d92fa7958c6b03c59e23aa92 /src/main/scala/scala/async/AnfTransform.scala | |
parent | 1c91fec998d09e31c2c52760452af1771a092182 (diff) | |
download | scala-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.scala | 54 |
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") } } + } |