diff options
author | Jason Zaugg <jzaugg@gmail.com> | 2012-11-26 18:20:00 +0100 |
---|---|---|
committer | Jason Zaugg <jzaugg@gmail.com> | 2012-11-27 08:36:30 +0100 |
commit | fe9a0023e685a2924cba10ec738e8babe9e7bd7b (patch) | |
tree | c337362ca36e9ee8fdd768653202cbc3ad8dab85 /src | |
parent | 456fd6e561a52f34040d9af041cc2b74880e5579 (diff) | |
download | scala-async-fe9a0023e685a2924cba10ec738e8babe9e7bd7b.tar.gz scala-async-fe9a0023e685a2924cba10ec738e8babe9e7bd7b.tar.bz2 scala-async-fe9a0023e685a2924cba10ec738e8babe9e7bd7b.zip |
Fix semantics of by-name application
- If we lift one arg, we must lift them all.
This preserves evaluation order.
- But, never lift an by-name arg
Addresses the first half of #33.
Diffstat (limited to 'src')
-rw-r--r-- | src/main/scala/scala/async/AnfTransform.scala | 24 | ||||
-rw-r--r-- | src/test/scala/scala/async/run/anf/AnfTransformSpec.scala | 22 |
2 files changed, 38 insertions, 8 deletions
diff --git a/src/main/scala/scala/async/AnfTransform.scala b/src/main/scala/scala/async/AnfTransform.scala index a2d21f6..449ea7b 100644 --- a/src/main/scala/scala/async/AnfTransform.scala +++ b/src/main/scala/scala/async/AnfTransform.scala @@ -170,12 +170,12 @@ private[async] final case class AnfTransform[C <: Context](c: C) { vd.setPos(pos) vd } + } - private def defineVal(prefix: String, lhs: Tree, pos: Position): ValDef = { - val vd = ValDef(NoMods, name.fresh(prefix), TypeTree(), lhs) - vd.setPos(pos) - vd - } + private def defineVal(prefix: String, lhs: Tree, pos: Position): ValDef = { + val vd = ValDef(NoMods, name.fresh(prefix), TypeTree(), lhs) + vd.setPos(pos) + vd } private object anf { @@ -190,10 +190,18 @@ private[async] final case class AnfTransform[C <: Context](c: C) { case Apply(fun, args) if containsAwait => // we an assume that no await call appears in a by-name argument position, // this has already been checked. - + val isByName: (Int) => Boolean = utils.isByName(fun) val funStats :+ simpleFun = inline.transformToList(fun) - val argLists = args map inline.transformToList - val allArgStats = argLists flatMap (_.init) + val argLists: List[List[Tree]] = args.zipWithIndex map { + case (arg, i) if isByName(i) => List(arg) + case (arg, i) => inline.transformToList(arg) match { + case stats :+ expr => + val valDef = defineVal(s"arg$i", expr, arg.pos) + stats ::: List(valDef, Ident(valDef.name)) + case xs => xs + } + } + val allArgStats = argLists flatMap (_.init) val simpleArgs = argLists map (_.last) funStats ++ allArgStats :+ attachCopy(tree)(Apply(simpleFun, simpleArgs).setSymbol(tree.symbol)) diff --git a/src/test/scala/scala/async/run/anf/AnfTransformSpec.scala b/src/test/scala/scala/async/run/anf/AnfTransformSpec.scala index 6dd4db7..595fa6c 100644 --- a/src/test/scala/scala/async/run/anf/AnfTransformSpec.scala +++ b/src/test/scala/scala/async/run/anf/AnfTransformSpec.scala @@ -205,4 +205,26 @@ class AnfTransformSpec { } result mustBe (true) } + + @Test + def byNameExpressionsArentLifted() { + import _root_.scala.async.AsyncId.{async, await} + def foo(ignored: => Any, b: Int) = b + val result = async { + foo(???, await(1)) + } + result mustBe (1) + } + + @Test + def evaluationOrderRespected() { + import scala.async.AsyncId.{async, await} + def foo(a: Int, b: Int) = (a, b) + val result = async { + var i = 0 + def next() = {i += 1; i} + foo(next(), await(next())) + } + result mustBe ((1, 2)) + } } |