diff options
author | Jason Zaugg <jzaugg@gmail.com> | 2013-07-07 10:48:11 +1000 |
---|---|---|
committer | Jason Zaugg <jzaugg@gmail.com> | 2013-07-07 10:48:11 +1000 |
commit | 2d8506a64392cd7192b6831c38798cc9a7c8bfed (patch) | |
tree | 84eafcf1a9a179eeaa97dd1e3595c18351b2b814 /src/main/scala/scala/async/internal/AsyncAnalysis.scala | |
parent | c60c38ca6098402f7a9cc6d6746b664bb2b1306c (diff) | |
download | scala-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.scala | 91 |
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) + } + } +} |