From fe9a0023e685a2924cba10ec738e8babe9e7bd7b Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Mon, 26 Nov 2012 18:20:00 +0100 Subject: 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. --- src/main/scala/scala/async/AnfTransform.scala | 24 ++++++++++++++-------- .../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)) + } } -- cgit v1.2.3