aboutsummaryrefslogtreecommitdiff
path: root/src/main/scala/scala/async/internal/AsyncAnalysis.scala
diff options
context:
space:
mode:
authorJason Zaugg <jzaugg@gmail.com>2013-07-07 10:48:11 +1000
committerJason Zaugg <jzaugg@gmail.com>2013-07-07 10:48:11 +1000
commit2d8506a64392cd7192b6831c38798cc9a7c8bfed (patch)
tree84eafcf1a9a179eeaa97dd1e3595c18351b2b814 /src/main/scala/scala/async/internal/AsyncAnalysis.scala
parentc60c38ca6098402f7a9cc6d6746b664bb2b1306c (diff)
downloadscala-async-2d8506a64392cd7192b6831c38798cc9a7c8bfed.tar.gz
scala-async-2d8506a64392cd7192b6831c38798cc9a7c8bfed.tar.bz2
scala-async-2d8506a64392cd7192b6831c38798cc9a7c8bfed.zip
Move implementation details to scala.async.internal._.
If we intend to keep CPS fallback around for any length of time it should probably move there too.
Diffstat (limited to 'src/main/scala/scala/async/internal/AsyncAnalysis.scala')
-rw-r--r--src/main/scala/scala/async/internal/AsyncAnalysis.scala91
1 files changed, 91 insertions, 0 deletions
diff --git a/src/main/scala/scala/async/internal/AsyncAnalysis.scala b/src/main/scala/scala/async/internal/AsyncAnalysis.scala
new file mode 100644
index 0000000..62842c9
--- /dev/null
+++ b/src/main/scala/scala/async/internal/AsyncAnalysis.scala
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2012 Typesafe Inc. <http://www.typesafe.com>
+ */
+
+package scala.async.internal
+
+import scala.reflect.macros.Context
+import scala.collection.mutable
+
+trait AsyncAnalysis {
+ self: AsyncMacro =>
+
+ import global._
+
+ /**
+ * Analyze the contents of an `async` block in order to:
+ * - Report unsupported `await` calls under nested templates, functions, by-name arguments.
+ *
+ * Must be called on the original tree, not on the ANF transformed tree.
+ */
+ def reportUnsupportedAwaits(tree: Tree, report: Boolean): Boolean = {
+ val analyzer = new UnsupportedAwaitAnalyzer(report)
+ analyzer.traverse(tree)
+ analyzer.hasUnsupportedAwaits
+ }
+
+ private class UnsupportedAwaitAnalyzer(report: Boolean) extends AsyncTraverser {
+ var hasUnsupportedAwaits = false
+
+ override def nestedClass(classDef: ClassDef) {
+ val kind = if (classDef.symbol.isTrait) "trait" else "class"
+ reportUnsupportedAwait(classDef, s"nested ${kind}")
+ }
+
+ override def nestedModule(module: ModuleDef) {
+ reportUnsupportedAwait(module, "nested object")
+ }
+
+ override def nestedMethod(defDef: DefDef) {
+ reportUnsupportedAwait(defDef, "nested method")
+ }
+
+ override def byNameArgument(arg: Tree) {
+ reportUnsupportedAwait(arg, "by-name argument")
+ }
+
+ override def function(function: Function) {
+ reportUnsupportedAwait(function, "nested function")
+ }
+
+ override def patMatFunction(tree: Match) {
+ reportUnsupportedAwait(tree, "nested function")
+ }
+
+ override def traverse(tree: Tree) {
+ def containsAwait = tree exists isAwait
+ tree match {
+ case Try(_, _, _) if containsAwait =>
+ reportUnsupportedAwait(tree, "try/catch")
+ super.traverse(tree)
+ case Return(_) =>
+ abort(tree.pos, "return is illegal within a async block")
+ case ValDef(mods, _, _, _) if mods.hasFlag(Flag.LAZY) =>
+ // TODO lift this restriction
+ abort(tree.pos, "lazy vals are illegal within an async block")
+ case _ =>
+ super.traverse(tree)
+ }
+ }
+
+ /**
+ * @return true, if the tree contained an unsupported await.
+ */
+ private def reportUnsupportedAwait(tree: Tree, whyUnsupported: String): Boolean = {
+ val badAwaits: List[RefTree] = tree collect {
+ case rt: RefTree if isAwait(rt) => rt
+ }
+ badAwaits foreach {
+ tree =>
+ reportError(tree.pos, s"await must not be used under a $whyUnsupported.")
+ }
+ badAwaits.nonEmpty
+ }
+
+ private def reportError(pos: Position, msg: String) {
+ hasUnsupportedAwaits = true
+ if (report)
+ abort(pos, msg)
+ }
+ }
+}