aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Zaugg <jzaugg@gmail.com>2012-11-26 18:20:00 +0100
committerJason Zaugg <jzaugg@gmail.com>2012-11-27 08:36:30 +0100
commitfe9a0023e685a2924cba10ec738e8babe9e7bd7b (patch)
treec337362ca36e9ee8fdd768653202cbc3ad8dab85
parent456fd6e561a52f34040d9af041cc2b74880e5579 (diff)
downloadscala-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.
-rw-r--r--src/main/scala/scala/async/AnfTransform.scala24
-rw-r--r--src/test/scala/scala/async/run/anf/AnfTransformSpec.scala22
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))
+ }
}