diff options
author | Jason Zaugg <jzaugg@gmail.com> | 2014-04-06 17:47:41 +0200 |
---|---|---|
committer | Jason Zaugg <jzaugg@gmail.com> | 2014-04-06 17:47:41 +0200 |
commit | dc5ee63a57109c7f0dabb439306a311a850e87f5 (patch) | |
tree | 45d6288e890897045348b6b7b084c54626a3daba | |
parent | f53c3bb75be003c12fa6b999ed34eba2a2a38b41 (diff) | |
parent | 92ab5b74abcff8b49a408f4bf46c285c0016a44b (diff) | |
download | scala-async-dc5ee63a57109c7f0dabb439306a311a850e87f5.tar.gz scala-async-dc5ee63a57109c7f0dabb439306a311a850e87f5.tar.bz2 scala-async-dc5ee63a57109c7f0dabb439306a311a850e87f5.zip |
Merge pull request #71 from retronym/topic/quasiquote-applied
Update to Scala 2.11.0-RC4, adapting to change in quasiquotes
-rw-r--r-- | build.sbt | 2 | ||||
-rw-r--r-- | src/main/scala/scala/async/internal/AnfTransform.scala | 18 | ||||
-rw-r--r-- | src/main/scala/scala/async/internal/TransformUtils.scala | 68 |
3 files changed, 71 insertions, 17 deletions
@@ -1,4 +1,4 @@ -scalaVersion := "2.11.0-RC3" +scalaVersion := "2.11.0-RC4" // Uncomment to test with a locally built copy of Scala. // scalaHome := Some(file("/code/scala2/build/pack")) diff --git a/src/main/scala/scala/async/internal/AnfTransform.scala b/src/main/scala/scala/async/internal/AnfTransform.scala index 0e58fa7..e54eb54 100644 --- a/src/main/scala/scala/async/internal/AnfTransform.scala +++ b/src/main/scala/scala/async/internal/AnfTransform.scala @@ -161,7 +161,7 @@ private[async] trait AnfTransform { val stats :+ expr1 = linearize.transformToList(expr) stats :+ treeCopy.Typed(tree, expr1, tpt) - case q"$fun[..$targs](...$argss)" if argss.nonEmpty => + case Applied(fun, targs, argss) if argss.nonEmpty => // we can assume that no await call appears in a by-name argument position, // this has already been checked. val funStats :+ simpleFun = linearize.transformToList(fun) @@ -188,21 +188,7 @@ private[async] trait AnfTransform { } } - - /** The depth of the nested applies: e.g. Apply(Apply(Apply(_, _), _), _) - * has depth 3. Continues through type applications (without counting them.) - */ - def applyDepth: Int = { - def loop(tree: Tree): Int = tree match { - case Apply(fn, _) => 1 + loop(fn) - case TypeApply(fn, _) => loop(fn) - case AppliedTypeTree(fn, _) => loop(fn) - case _ => 0 - } - loop(tree) - } - - val typedNewApply = copyApplied(tree, applyDepth) + val typedNewApply = copyApplied(tree, argss.length) funStats ++ argStatss.flatten.flatten :+ typedNewApply diff --git a/src/main/scala/scala/async/internal/TransformUtils.scala b/src/main/scala/scala/async/internal/TransformUtils.scala index 5d0a96f..a01a801 100644 --- a/src/main/scala/scala/async/internal/TransformUtils.scala +++ b/src/main/scala/scala/async/internal/TransformUtils.scala @@ -41,6 +41,74 @@ private[async] trait TransformUtils { def isAwait(fun: Tree) = fun.symbol == defn.Async_await + // Copy pasted from TreeInfo in the compiler. + // Using a quasiquote pattern like `case q"$fun[..$targs](...$args)" => is not + // sufficient since https://github.com/scala/scala/pull/3656 as it doesn't match + // constructor invocations. + class Applied(val tree: Tree) { + /** The tree stripped of the possibly nested applications. + * The original tree if it's not an application. + */ + def callee: Tree = { + def loop(tree: Tree): Tree = tree match { + case Apply(fn, _) => loop(fn) + case tree => tree + } + loop(tree) + } + + /** The `callee` unwrapped from type applications. + * The original `callee` if it's not a type application. + */ + def core: Tree = callee match { + case TypeApply(fn, _) => fn + case AppliedTypeTree(fn, _) => fn + case tree => tree + } + + /** The type arguments of the `callee`. + * `Nil` if the `callee` is not a type application. + */ + def targs: List[Tree] = callee match { + case TypeApply(_, args) => args + case AppliedTypeTree(_, args) => args + case _ => Nil + } + + /** (Possibly multiple lists of) value arguments of an application. + * `Nil` if the `callee` is not an application. + */ + def argss: List[List[Tree]] = { + def loop(tree: Tree): List[List[Tree]] = tree match { + case Apply(fn, args) => loop(fn) :+ args + case _ => Nil + } + loop(tree) + } + } + + /** Returns a wrapper that knows how to destructure and analyze applications. + */ + def dissectApplied(tree: Tree) = new Applied(tree) + + /** Destructures applications into important subparts described in `Applied` class, + * namely into: core, targs and argss (in the specified order). + * + * Trees which are not applications are also accepted. Their callee and core will + * be equal to the input, while targs and argss will be Nil. + * + * The provided extractors don't expose all the API of the `Applied` class. + * For advanced use, call `dissectApplied` explicitly and use its methods instead of pattern matching. + */ + object Applied { + def apply(tree: Tree): Applied = new Applied(tree) + + def unapply(applied: Applied): Option[(Tree, List[Tree], List[List[Tree]])] = + Some((applied.core, applied.targs, applied.argss)) + + def unapply(tree: Tree): Option[(Tree, List[Tree], List[List[Tree]])] = + unapply(dissectApplied(tree)) + } private lazy val Boolean_ShortCircuits: Set[Symbol] = { import definitions.BooleanClass def BooleanTermMember(name: String) = BooleanClass.typeSignature.member(newTermName(name).encodedName) |