From 93898302564456f453a0cd283c89030a2b783e7f Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Sat, 5 Apr 2014 23:03:58 +0200 Subject: Update to Scala 2.11.0-RC4, adapting to change in quasiquotes Namely: https://github.com/scala/scala/pull/3656 I can't find a way to express a QQ that matches an constructor invocation *and* lets me bind a reference to the `New` tree. So I've dropped down to a borrowed version of `TreeInfo#Applied`. --- .../scala/scala/async/internal/AnfTransform.scala | 3 +- .../scala/async/internal/TransformUtils.scala | 68 ++++++++++++++++++++++ 2 files changed, 69 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/main/scala/scala/async/internal/AnfTransform.scala b/src/main/scala/scala/async/internal/AnfTransform.scala index 0e58fa7..a0f722f 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 ap @ 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,7 +188,6 @@ 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.) */ 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) -- cgit v1.2.3