@@ -41,6 +41,74 @@ private[async] trait TransformUtils {
4141 def isAwait (fun : Tree ) =
4242 fun.symbol == defn.Async_await
4343
44+ // Copy pasted from TreeInfo in the compiler.
45+ // Using a quasiquote pattern like `case q"$fun[..$targs](...$args)" => is not
46+ // sufficient since https://github.com/scala/scala/pull/3656 as it doesn't match
47+ // constructor invocations.
48+ class Applied (val tree : Tree ) {
49+ /** The tree stripped of the possibly nested applications.
50+ * The original tree if it's not an application.
51+ */
52+ def callee : Tree = {
53+ def loop (tree : Tree ): Tree = tree match {
54+ case Apply (fn, _) => loop(fn)
55+ case tree => tree
56+ }
57+ loop(tree)
58+ }
59+
60+ /** The `callee` unwrapped from type applications.
61+ * The original `callee` if it's not a type application.
62+ */
63+ def core : Tree = callee match {
64+ case TypeApply (fn, _) => fn
65+ case AppliedTypeTree (fn, _) => fn
66+ case tree => tree
67+ }
68+
69+ /** The type arguments of the `callee`.
70+ * `Nil` if the `callee` is not a type application.
71+ */
72+ def targs : List [Tree ] = callee match {
73+ case TypeApply (_, args) => args
74+ case AppliedTypeTree (_, args) => args
75+ case _ => Nil
76+ }
77+
78+ /** (Possibly multiple lists of) value arguments of an application.
79+ * `Nil` if the `callee` is not an application.
80+ */
81+ def argss : List [List [Tree ]] = {
82+ def loop (tree : Tree ): List [List [Tree ]] = tree match {
83+ case Apply (fn, args) => loop(fn) :+ args
84+ case _ => Nil
85+ }
86+ loop(tree)
87+ }
88+ }
89+
90+ /** Returns a wrapper that knows how to destructure and analyze applications.
91+ */
92+ def dissectApplied (tree : Tree ) = new Applied (tree)
93+
94+ /** Destructures applications into important subparts described in `Applied` class,
95+ * namely into: core, targs and argss (in the specified order).
96+ *
97+ * Trees which are not applications are also accepted. Their callee and core will
98+ * be equal to the input, while targs and argss will be Nil.
99+ *
100+ * The provided extractors don't expose all the API of the `Applied` class.
101+ * For advanced use, call `dissectApplied` explicitly and use its methods instead of pattern matching.
102+ */
103+ object Applied {
104+ def apply (tree : Tree ): Applied = new Applied (tree)
105+
106+ def unapply (applied : Applied ): Option [(Tree , List [Tree ], List [List [Tree ]])] =
107+ Some ((applied.core, applied.targs, applied.argss))
108+
109+ def unapply (tree : Tree ): Option [(Tree , List [Tree ], List [List [Tree ]])] =
110+ unapply(dissectApplied(tree))
111+ }
44112 private lazy val Boolean_ShortCircuits : Set [Symbol ] = {
45113 import definitions .BooleanClass
46114 def BooleanTermMember (name : String ) = BooleanClass .typeSignature.member(newTermName(name).encodedName)
0 commit comments