diff options
author | Philipp Haller <hallerp@gmail.com> | 2012-11-26 10:32:37 -0800 |
---|---|---|
committer | Philipp Haller <hallerp@gmail.com> | 2012-11-26 10:32:37 -0800 |
commit | 54c97691f78dcd811cd5dad66d0b7d9406fb9ed6 (patch) | |
tree | 31fd1d999bd88275d1202c0ef7f7c8a7fa4f0928 /src/main/scala/scala/async/AsyncAnalysis.scala | |
parent | 4518c96f9b54a1b7ca14d82b3ed31d7014a67f57 (diff) | |
parent | 6c3c0f0a37d337aa297f5b2481d4727ea2a20434 (diff) | |
download | scala-async-54c97691f78dcd811cd5dad66d0b7d9406fb9ed6.tar.gz scala-async-54c97691f78dcd811cd5dad66d0b7d9406fb9ed6.tar.bz2 scala-async-54c97691f78dcd811cd5dad66d0b7d9406fb9ed6.zip |
Merge pull request #41 from phaller/ticket/35-synth-object-2
Ticket/35 synth object 2
Diffstat (limited to 'src/main/scala/scala/async/AsyncAnalysis.scala')
-rw-r--r-- | src/main/scala/scala/async/AsyncAnalysis.scala | 66 |
1 files changed, 47 insertions, 19 deletions
diff --git a/src/main/scala/scala/async/AsyncAnalysis.scala b/src/main/scala/scala/async/AsyncAnalysis.scala index 645d9f5..8bb5bcd 100644 --- a/src/main/scala/scala/async/AsyncAnalysis.scala +++ b/src/main/scala/scala/async/AsyncAnalysis.scala @@ -11,6 +11,7 @@ private[async] final case class AsyncAnalysis[C <: Context](c: C) { import c.universe._ val utils = TransformUtils[c.type](c) + import utils._ /** @@ -30,10 +31,11 @@ private[async] final case class AsyncAnalysis[C <: Context](c: C) { * * Must be called on the ANF transformed tree. */ - def valDefsUsedInSubsequentStates(tree: Tree): List[ValDef] = { + def defTreesUsedInSubsequentStates(tree: Tree): List[DefTree] = { val analyzer = new AsyncDefinitionUseAnalyzer analyzer.traverse(tree) - analyzer.valDefsToLift.toList + val liftable: List[DefTree] = (analyzer.valDefsToLift ++ analyzer.nestedMethodsToLift).toList.distinct + liftable } private class UnsupportedAwaitAnalyzer extends AsyncTraverser { @@ -41,7 +43,8 @@ private[async] final case class AsyncAnalysis[C <: Context](c: C) { val kind = if (classDef.symbol.asClass.isTrait) "trait" else "class" if (!reportUnsupportedAwait(classDef, s"nested $kind")) { // do not allow local class definitions, because of SI-5467 (specific to case classes, though) - c.error(classDef.pos, s"Local class ${classDef.name.decoded} illegal within `async` block") + if (classDef.symbol.asClass.isCaseClass) + c.error(classDef.pos, s"Local case class ${classDef.name.decoded} illegal within `async` block") } } @@ -70,12 +73,9 @@ private[async] final case class AsyncAnalysis[C <: Context](c: C) { case Try(_, _, _) if containsAwait => reportUnsupportedAwait(tree, "try/catch") super.traverse(tree) - case If(cond, _, _) if containsAwait => - reportUnsupportedAwait(cond, "condition") - super.traverse(tree) - case Return(_) => + case Return(_) => c.abort(tree.pos, "return is illegal within a async block") - case _ => + case _ => super.traverse(tree) } } @@ -92,7 +92,7 @@ private[async] final case class AsyncAnalysis[C <: Context](c: C) { c.error(tree.pos, s"await must not be used under a $whyUnsupported.") } badAwaits.nonEmpty - } + } } private class AsyncDefinitionUseAnalyzer extends AsyncTraverser { @@ -102,40 +102,67 @@ private[async] final case class AsyncAnalysis[C <: Context](c: C) { private var valDefChunkId = Map[Symbol, (ValDef, Int)]() - val valDefsToLift = mutable.Set[ValDef]() + val valDefsToLift : mutable.Set[ValDef] = collection.mutable.Set() + val nestedMethodsToLift: mutable.Set[DefDef] = collection.mutable.Set() + + override def nestedMethod(defDef: DefDef) { + nestedMethodsToLift += defDef + defDef.rhs foreach { + case rt: RefTree => + valDefChunkId.get(rt.symbol) match { + case Some((vd, defChunkId)) => + valDefsToLift += vd // lift all vals referred to by nested methods. + case _ => + } + case _ => + } + } + + override def function(function: Function) { + function foreach { + case rt: RefTree => + valDefChunkId.get(rt.symbol) match { + case Some((vd, defChunkId)) => + valDefsToLift += vd // lift all vals referred to by nested functions. + case _ => + } + case _ => + } + } override def traverse(tree: Tree) = { tree match { - case If(cond, thenp, elsep) if tree exists isAwait => + case If(cond, thenp, elsep) if tree exists isAwait => traverseChunks(List(cond, thenp, elsep)) - case Match(selector, cases) if tree exists isAwait => + case Match(selector, cases) if tree exists isAwait => traverseChunks(selector :: cases) case LabelDef(name, params, rhs) if rhs exists isAwait => traverseChunks(rhs :: Nil) - case Apply(fun, args) if isAwait(fun) => + case Apply(fun, args) if isAwait(fun) => super.traverse(tree) nextChunk() - case vd: ValDef => + case vd: ValDef => super.traverse(tree) valDefChunkId += (vd.symbol ->(vd, chunkId)) - if (isAwait(vd.rhs)) valDefsToLift += vd - case as: Assign => + val isPatternBinder = vd.name.toString.contains(name.bindSuffix) + if (isAwait(vd.rhs) || isPatternBinder) valDefsToLift += vd + case as: Assign => if (isAwait(as.rhs)) { - assert(as.lhs.symbol != null, "internal error: null symbol for Assign tree:" + as + " " + as.lhs.symbol) + assert(as.lhs.symbol != null, "internal error: null symbol for Assign tree:" + as + " " + as.lhs.symbol) // TODO test the orElse case, try to remove the restriction. val (vd, defBlockId) = valDefChunkId.getOrElse(as.lhs.symbol, c.abort(as.pos, s"await may only be assigned to a var/val defined in the async block. ${as.lhs} ${as.lhs.symbol}")) valDefsToLift += vd } super.traverse(tree) - case rt: RefTree => + case rt: RefTree => valDefChunkId.get(rt.symbol) match { case Some((vd, defChunkId)) if defChunkId != chunkId => valDefsToLift += vd case _ => } super.traverse(tree) - case _ => super.traverse(tree) + case _ => super.traverse(tree) } } @@ -145,4 +172,5 @@ private[async] final case class AsyncAnalysis[C <: Context](c: C) { } } } + } |