summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugene Burmako <xeno.by@gmail.com>2014-01-31 15:47:56 +0100
committerEugene Burmako <xeno.by@gmail.com>2014-02-14 23:51:23 +0100
commit483bd3cacb34df3b3c2cc205338cb8e12cb89838 (patch)
treefb3986311fe90c2960405c05de4378138f258281
parentd7dd68faa4cd279714c32965ebf83e118c915e0a (diff)
downloadscala-483bd3cacb34df3b3c2cc205338cb8e12cb89838.tar.gz
scala-483bd3cacb34df3b3c2cc205338cb8e12cb89838.tar.bz2
scala-483bd3cacb34df3b3c2cc205338cb8e12cb89838.zip
adds Context.enclosingOwner
As per discussion at https://groups.google.com/forum/#!topic/scala-internals/nf_ooEBn6-k, this commit introduces the new c.enclosingOwner API that is going to serve two purposes: 1) provide a better controlled alternative to c.enclosingTree, 2) enable low-level tinkering with owner chains without having to cast to compiler internals. This solution is not ideal, because: 1) symbols are much more than I would like to expose about enclosing lexical contexts (after the aforementioned discussion I’m no longer completely sure whether exposing nothing is the right thing to do, but exposing symbol completers is definitely something that should be avoided), 2) we shouldn’t have to do that low-level stuff in the first place. However, let’s face the facts. This change represents both an improvement over the state of the art wrt #1 and a long-awaited capability wrt #2. I think this pretty much warrants its place in trunk in the spirit of gradual, evolutionary development of reflection API.
-rw-r--r--src/compiler/scala/reflect/macros/contexts/Enclosures.scala1
-rw-r--r--src/reflect/scala/reflect/macros/Enclosures.scala8
-rw-r--r--test/files/run/macro-enclosures.check2
-rw-r--r--test/files/run/macro-enclosures/Impls_Macros_1.scala22
4 files changed, 24 insertions, 9 deletions
diff --git a/src/compiler/scala/reflect/macros/contexts/Enclosures.scala b/src/compiler/scala/reflect/macros/contexts/Enclosures.scala
index 5e931817b5..0b4aad85a3 100644
--- a/src/compiler/scala/reflect/macros/contexts/Enclosures.scala
+++ b/src/compiler/scala/reflect/macros/contexts/Enclosures.scala
@@ -18,6 +18,7 @@ trait Enclosures {
// vals are eager to simplify debugging
// after all we wouldn't save that much time by making them lazy
val macroApplication: Tree = expandee
+ val enclosingOwner = site.owner
def enclosingPackage: PackageDef = strictEnclosure[PackageDef]
val enclosingClass: Tree = lenientEnclosure[ImplDef]
def enclosingImpl: ImplDef = strictEnclosure[ImplDef]
diff --git a/src/reflect/scala/reflect/macros/Enclosures.scala b/src/reflect/scala/reflect/macros/Enclosures.scala
index 1ced2e54c6..7c186139cf 100644
--- a/src/reflect/scala/reflect/macros/Enclosures.scala
+++ b/src/reflect/scala/reflect/macros/Enclosures.scala
@@ -20,7 +20,8 @@ import scala.language.existentials // SI-6541
* This is somewhat aligned with the overall evolution of macros during the 2.11 development cycle, where we played with
* `c.introduceTopLevel` and `c.introduceMember`, but at the end of the day decided to reject them.
*
- * If you're relying on the now deprecated APIs, consider reformulating your macros in terms of completely local expansion
+ * If you're relying on the now deprecated APIs, consider using the new [[c.enclosingOwner]] method that can be used to obtain
+ * the names of enclosing definitions. Alternatively try reformulating your macros in terms of completely local expansion
* and/or joining a discussion of a somewhat related potential language feature at [[https://groups.google.com/forum/#!topic/scala-debate/f4CLmYShX6Q]].
* We also welcome questions and suggestions on our mailing lists, where we would be happy to further discuss this matter.
*/
@@ -51,6 +52,11 @@ trait Enclosures {
*/
def enclosingPosition: Position
+ /** Symbol associated with the innermost enclosing lexical context.
+ * Walking the owner chain of this symbol will reveal information about more and more enclosing contexts.
+ */
+ def enclosingOwner: Symbol
+
/** Tree that corresponds to the enclosing method, or EmptyTree if not applicable.
* @see [[scala.reflect.macros.Enclosures]]
*/
diff --git a/test/files/run/macro-enclosures.check b/test/files/run/macro-enclosures.check
index 36bb67e194..b6fe7a4a91 100644
--- a/test/files/run/macro-enclosures.check
+++ b/test/files/run/macro-enclosures.check
@@ -30,3 +30,5 @@ enclosingTemplate = scala.AnyRef {
}
enclosingMethod = def test = Macros.foo
enclosingDef = def test = Macros.foo
+enclosingOwner = method test
+enclosingOwnerChain = List(method test, object Test, package test, package <root>)
diff --git a/test/files/run/macro-enclosures/Impls_Macros_1.scala b/test/files/run/macro-enclosures/Impls_Macros_1.scala
index 5b04cf29e9..a0f66a6b98 100644
--- a/test/files/run/macro-enclosures/Impls_Macros_1.scala
+++ b/test/files/run/macro-enclosures/Impls_Macros_1.scala
@@ -3,15 +3,21 @@ import scala.reflect.macros.blackbox.Context
object Macros {
def impl(c: Context) = {
import c.universe._
- reify {
- println("enclosingPackage = " + c.Expr[String](Literal(Constant(c.enclosingPackage.toString))).splice)
- println("enclosingClass = " + c.Expr[String](Literal(Constant(c.enclosingClass.toString))).splice)
- println("enclosingImpl = " + c.Expr[String](Literal(Constant(c.enclosingImpl.toString))).splice)
- println("enclosingTemplate = " + c.Expr[String](Literal(Constant(c.enclosingTemplate.toString))).splice)
- println("enclosingMethod = " + c.Expr[String](Literal(Constant(c.enclosingMethod.toString))).splice)
- println("enclosingDef = " + c.Expr[String](Literal(Constant(c.enclosingDef.toString))).splice)
+ def chain(sym: Symbol): List[Symbol] = sym.owner match {
+ case NoSymbol => sym :: Nil
+ case owner => sym :: chain(owner)
}
+ q"""
+ println("enclosingPackage = " + ${c.enclosingPackage.toString})
+ println("enclosingClass = " + ${c.enclosingClass.toString})
+ println("enclosingImpl = " + ${c.enclosingImpl.toString})
+ println("enclosingTemplate = " + ${c.enclosingTemplate.toString})
+ println("enclosingMethod = " + ${c.enclosingMethod.toString})
+ println("enclosingDef = " + ${c.enclosingDef.toString})
+ println("enclosingOwner = " + ${c.enclosingOwner.toString})
+ println("enclosingOwnerChain = " + ${chain(c.enclosingOwner).toString})
+ """
}
- def foo = macro impl
+ def foo: Any = macro impl
} \ No newline at end of file