From 40da520a74fbb13b0ed1c5acb7ddf5c521fd8acc Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Sun, 11 Nov 2012 22:12:50 +0100 Subject: Add a test to interrogate the expanded tree. - checks that only one function is synthesized - checks the set of vars created (TODO minimize these) - use x$1 rather than x1 for the freshened names for lifted vars. - make execContext a val, not a var. --- src/main/scala/scala/async/Async.scala | 2 +- src/main/scala/scala/async/ExprBuilder.scala | 6 ++-- src/test/scala/scala/async/TestUtils.scala | 9 +++-- src/test/scala/scala/async/TreeInterrogation.scala | 38 ++++++++++++++++++++++ 4 files changed, 49 insertions(+), 6 deletions(-) create mode 100644 src/test/scala/scala/async/TreeInterrogation.scala (limited to 'src') diff --git a/src/main/scala/scala/async/Async.scala b/src/main/scala/scala/async/Async.scala index 9f43b0b..4f7fa01 100644 --- a/src/main/scala/scala/async/Async.scala +++ b/src/main/scala/scala/async/Async.scala @@ -139,7 +139,7 @@ abstract class AsyncBase { // Initialize the state var state$async = 0 // Resolve the execution context - var execContext$async = futureSystemOps.execContext.splice + val execContext$async = futureSystemOps.execContext.splice var onCompleteHandler$async: util.Try[Any] => Unit = null // Spawn a future to: diff --git a/src/main/scala/scala/async/ExprBuilder.scala b/src/main/scala/scala/async/ExprBuilder.scala index 09489d4..1a3f866 100644 --- a/src/main/scala/scala/async/ExprBuilder.scala +++ b/src/main/scala/scala/async/ExprBuilder.scala @@ -34,6 +34,8 @@ final class ExprBuilder[C <: Context, FS <: FutureSystem](val c: C, val futureSy val x1 = newTermName("x$1") val tr = newTermName("tr") val onCompleteHandler = suffixedName("onCompleteHandler") + + def fresh(name: TermName) = newTermName(c.fresh("" + name + "$")) } private val execContext = futureSystemOps.execContext @@ -295,7 +297,7 @@ final class ExprBuilder[C <: Context, FS <: FutureSystem](val c: C, val futureSy for (stat <- stats) stat match { // the val name = await(..) pattern case ValDef(mods, name, tpt, Apply(fun, args)) if fun.symbol == Async_await => - val newName = c.fresh(name) + val newName = builder.name.fresh(name) toRename += (stat.symbol -> newName) asyncStates += stateBuilder.complete(args.head, newName, tpt, toRename).result // complete with await @@ -309,7 +311,7 @@ final class ExprBuilder[C <: Context, FS <: FutureSystem](val c: C, val futureSy case ValDef(mods, name, tpt, rhs) => checkForUnsupportedAwait(rhs) - val newName = c.fresh(name) + val newName = builder.name.fresh(name) toRename += (stat.symbol -> newName) // when adding assignment need to take `toRename` into account stateBuilder.addVarDef(mods, newName, tpt, rhs, toRename) diff --git a/src/test/scala/scala/async/TestUtils.scala b/src/test/scala/scala/async/TestUtils.scala index 0920659..bac22a3 100644 --- a/src/test/scala/scala/async/TestUtils.scala +++ b/src/test/scala/scala/async/TestUtils.scala @@ -40,11 +40,14 @@ trait TestUtils { } def eval(code: String, compileOptions: String = ""): Any = { + val tb = mkToolbox(compileOptions) + tb.eval(tb.parse(code)) + } + + def mkToolbox(compileOptions: String = "") = { val m = scala.reflect.runtime.currentMirror import scala.tools.reflect.ToolBox - val tb = m.mkToolBox(options = compileOptions) - val result = tb.eval(tb.parse(code)) - result + m.mkToolBox(options = compileOptions) } def expectError(errorSnippet: String, compileOptions: String = "")(code: String) { diff --git a/src/test/scala/scala/async/TreeInterrogation.scala b/src/test/scala/scala/async/TreeInterrogation.scala new file mode 100644 index 0000000..7c277b1 --- /dev/null +++ b/src/test/scala/scala/async/TreeInterrogation.scala @@ -0,0 +1,38 @@ +package scala.async + +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 +import org.junit.Test +import AsyncId._ + +@RunWith(classOf[JUnit4]) +class TreeInterrogation { + @Test + def `a minimal set of vals are lifted to vars`() { + val cm = reflect.runtime.currentMirror + val tb = mkToolbox() + val tree = mkToolbox().parse( + """| import _root_.scala.async.AsyncId._ + | async { + | val x = await(1) + | val y = x * 2 + | val z = await(x * 3) + | z + | }""".stripMargin) + val tree1 = tb.typeCheck(tree) + + // println(cm.universe.showRaw(tree1)) + + import tb.mirror.universe._ + val functions = tree1.collect { + case f: Function => f + } + functions.size mustBe 1 + + val varDefs = tree1.collect { + case ValDef(mods, name, _, _) if mods.hasFlag(Flag.MUTABLE) => name + } + // TODO no need to lift `y` as it is only accessed from a single state. + varDefs.map(_.decoded).toSet mustBe(Set("state$async", "onCompleteHandler$async", "x$1", "z$1", "y$1")) + } +} -- cgit v1.2.3