summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugene Burmako <xeno.by@gmail.com>2012-12-25 02:08:21 +0100
committerEugene Burmako <xeno.by@gmail.com>2012-12-25 02:31:15 +0100
commit2375e2d878e6c493d9ab3097ef1d13d8641a6209 (patch)
treec0953cdb7e61a5e9940ee2d8c757b839a19f7028
parentd2a7aa4ba1c048e52affb0eb2b9167a18dc29c83 (diff)
downloadscala-2375e2d878e6c493d9ab3097ef1d13d8641a6209.tar.gz
scala-2375e2d878e6c493d9ab3097ef1d13d8641a6209.tar.bz2
scala-2375e2d878e6c493d9ab3097ef1d13d8641a6209.zip
enclosures are now strongly typed and are no longer vals
-rw-r--r--src/compiler/scala/reflect/macros/runtime/Enclosures.scala19
-rw-r--r--src/reflect/scala/reflect/macros/Enclosures.scala44
-rw-r--r--test/files/run/macro-enclosures.check32
-rw-r--r--test/files/run/macro-enclosures.flags1
-rw-r--r--test/files/run/macro-enclosures/Impls_Macros_1.scala14
-rw-r--r--test/files/run/macro-enclosures/Test_2.scala11
-rw-r--r--test/files/run/t6394a/Macros_1.scala2
7 files changed, 109 insertions, 14 deletions
diff --git a/src/compiler/scala/reflect/macros/runtime/Enclosures.scala b/src/compiler/scala/reflect/macros/runtime/Enclosures.scala
index d9f337b5ba..e8b2961611 100644
--- a/src/compiler/scala/reflect/macros/runtime/Enclosures.scala
+++ b/src/compiler/scala/reflect/macros/runtime/Enclosures.scala
@@ -1,22 +1,31 @@
package scala.reflect.macros
package runtime
+import scala.reflect.{ClassTag, classTag}
+
trait Enclosures {
self: Context =>
import universe._
- private def site = callsiteTyper.context
- private def enclTrees = site.enclosingContextChain map (_.tree)
- private def enclPoses = enclosingMacros map (_.macroApplication.pos) filterNot (_ eq NoPosition)
+ private lazy val site = callsiteTyper.context
+ private lazy val enclTrees = site.enclosingContextChain map (_.tree)
+ private lazy val enclPoses = enclosingMacros map (_.macroApplication.pos) filterNot (_ eq NoPosition)
+
+ private def lenientEnclosure[T <: Tree : ClassTag]: Tree = enclTrees collectFirst { case x: T => x } getOrElse EmptyTree
+ private def strictEnclosure[T <: Tree : ClassTag]: T = enclTrees collectFirst { case x: T => x } getOrElse (throw new EnclosureException(classTag[T].runtimeClass, enclTrees))
// vals are eager to simplify debugging
// after all we wouldn't save that much time by making them lazy
val macroApplication: Tree = expandee
- val enclosingClass: Tree = enclTrees collectFirst { case x: ImplDef => x } getOrElse EmptyTree
+ def enclosingPackage: PackageDef = strictEnclosure[PackageDef]
+ val enclosingClass: Tree = lenientEnclosure[ImplDef]
+ def enclosingImpl: ImplDef = strictEnclosure[ImplDef]
+ def enclosingTemplate: Template = strictEnclosure[Template]
val enclosingImplicits: List[(Type, Tree)] = site.openImplicits
val enclosingMacros: List[Context] = this :: universe.analyzer.openMacros // include self
- val enclosingMethod: Tree = site.enclMethod.tree
+ val enclosingMethod: Tree = lenientEnclosure[DefDef]
+ def enclosingDef: DefDef = strictEnclosure[DefDef]
val enclosingPosition: Position = if (enclPoses.isEmpty) NoPosition else enclPoses.head.pos
val enclosingUnit: CompilationUnit = universe.currentRun.currentUnit
val enclosingRun: Run = universe.currentRun
diff --git a/src/reflect/scala/reflect/macros/Enclosures.scala b/src/reflect/scala/reflect/macros/Enclosures.scala
index c48656b366..1e366ccbc3 100644
--- a/src/reflect/scala/reflect/macros/Enclosures.scala
+++ b/src/reflect/scala/reflect/macros/Enclosures.scala
@@ -15,7 +15,7 @@ trait Enclosures {
/** The tree that undergoes macro expansion.
* Can be useful to get an offset or a range position of the entire tree being processed.
*/
- val macroApplication: Tree
+ def macroApplication: Tree
/** Contexts that represent macros in-flight, including the current one. Very much like a stack trace, but for macros only.
* Can be useful for interoperating with other macros and for imposing compiler-friendly limits on macro expansion.
@@ -27,7 +27,7 @@ trait Enclosures {
* Unlike `openMacros`, this is a val, which means that it gets initialized when the context is created
* and always stays the same regardless of whatever happens during macro expansion.
*/
- val enclosingMacros: List[Context]
+ def enclosingMacros: List[Context]
/** Types along with corresponding trees for which implicit arguments are currently searched.
* Can be useful to get information about an application with an implicit parameter that is materialized during current macro expansion.
@@ -35,28 +35,56 @@ trait Enclosures {
* Unlike `openImplicits`, this is a val, which means that it gets initialized when the context is created
* and always stays the same regardless of whatever happens during macro expansion.
*/
- val enclosingImplicits: List[(Type, Tree)]
+ def enclosingImplicits: List[(Type, Tree)]
/** Tries to guess a position for the enclosing application.
* But that is simple, right? Just dereference ``pos'' of ``macroApplication''? Not really.
* If we're in a synthetic macro expansion (no positions), we must do our best to infer the position of something that triggerd this expansion.
* Surprisingly, quite often we can do this by navigation the ``enclosingMacros'' stack.
*/
- val enclosingPosition: Position
+ def enclosingPosition: Position
/** Tree that corresponds to the enclosing method, or EmptyTree if not applicable.
*/
- val enclosingMethod: Tree
+ @deprecated("Use enclosingDef instead, but be wary of changes in semantics", "2.10.1")
+ def enclosingMethod: Tree
/** Tree that corresponds to the enclosing class, or EmptyTree if not applicable.
*/
- val enclosingClass: Tree
+ @deprecated("Use enclosingImpl instead, but be wary of changes in semantics", "2.10.1")
+ def enclosingClass: Tree
+
+ /** Tree that corresponds to the enclosing DefDef tree.
+ * Throws `EnclosureException` if there's no such enclosing tree.
+ */
+ def enclosingDef: universe.DefDef
+
+ /** Tree that corresponds to the enclosing Template tree.
+ * Throws `EnclosureException` if there's no such enclosing tree.
+ */
+ def enclosingTemplate: universe.Template
+
+ /** Tree that corresponds to the enclosing ImplDef tree (i.e. either ClassDef or ModuleDef).
+ * Throws `EnclosureException` if there's no such enclosing tree.
+ */
+ def enclosingImpl: universe.ImplDef
+
+ /** Tree that corresponds to the enclosing PackageDef tree.
+ * Throws `EnclosureException` if there's no such enclosing tree.
+ */
+ def enclosingPackage: universe.PackageDef
/** Compilation unit that contains this macro application.
*/
- val enclosingUnit: CompilationUnit
+ def enclosingUnit: CompilationUnit
/** Compilation run that contains this macro application.
*/
- val enclosingRun: Run
+ def enclosingRun: Run
+
+ /** Indicates than one of the enclosure methods failed to find a tree
+ * of required type among enclosing trees.
+ */
+ case class EnclosureException(expected: Class[_], enclosingTrees: List[Tree])
+ extends Exception(s"Couldn't find a tree of type $expected among enclosing trees $enclosingTrees")
} \ No newline at end of file
diff --git a/test/files/run/macro-enclosures.check b/test/files/run/macro-enclosures.check
new file mode 100644
index 0000000000..36bb67e194
--- /dev/null
+++ b/test/files/run/macro-enclosures.check
@@ -0,0 +1,32 @@
+enclosingPackage = package test {
+ object Test extends scala.AnyRef {
+ def <init>() = {
+ super.<init>();
+ ()
+ };
+ def test = Macros.foo
+ }
+}
+enclosingClass = object Test extends scala.AnyRef {
+ def <init>() = {
+ super.<init>();
+ ()
+ };
+ def test = Macros.foo
+}
+enclosingImpl = object Test extends scala.AnyRef {
+ def <init>() = {
+ super.<init>();
+ ()
+ };
+ def test = Macros.foo
+}
+enclosingTemplate = scala.AnyRef {
+ def <init>() = {
+ super.<init>();
+ ()
+ };
+ def test = Macros.foo
+}
+enclosingMethod = def test = Macros.foo
+enclosingDef = def test = Macros.foo
diff --git a/test/files/run/macro-enclosures.flags b/test/files/run/macro-enclosures.flags
new file mode 100644
index 0000000000..cd66464f2f
--- /dev/null
+++ b/test/files/run/macro-enclosures.flags
@@ -0,0 +1 @@
+-language:experimental.macros \ No newline at end of file
diff --git a/test/files/run/macro-enclosures/Impls_Macros_1.scala b/test/files/run/macro-enclosures/Impls_Macros_1.scala
new file mode 100644
index 0000000000..cd54028676
--- /dev/null
+++ b/test/files/run/macro-enclosures/Impls_Macros_1.scala
@@ -0,0 +1,14 @@
+import scala.reflect.macros.Context
+
+object Macros {
+ def impl(c: Context) = c.universe.reify {
+ println("enclosingPackage = " + c.literal(c.enclosingPackage.toString).splice)
+ println("enclosingClass = " + c.literal(c.enclosingClass.toString).splice)
+ println("enclosingImpl = " + c.literal(c.enclosingImpl.toString).splice)
+ println("enclosingTemplate = " + c.literal(c.enclosingTemplate.toString).splice)
+ println("enclosingMethod = " + c.literal(c.enclosingMethod.toString).splice)
+ println("enclosingDef = " + c.literal(c.enclosingDef.toString).splice)
+ }
+
+ def foo = macro impl
+} \ No newline at end of file
diff --git a/test/files/run/macro-enclosures/Test_2.scala b/test/files/run/macro-enclosures/Test_2.scala
new file mode 100644
index 0000000000..779fe5211e
--- /dev/null
+++ b/test/files/run/macro-enclosures/Test_2.scala
@@ -0,0 +1,11 @@
+object Test extends App {
+ test.Test.test
+}
+
+package test {
+ object Test {
+ def test = {
+ Macros.foo
+ }
+ }
+} \ No newline at end of file
diff --git a/test/files/run/t6394a/Macros_1.scala b/test/files/run/t6394a/Macros_1.scala
index 3d39d3e40a..5aa07e7f41 100644
--- a/test/files/run/t6394a/Macros_1.scala
+++ b/test/files/run/t6394a/Macros_1.scala
@@ -4,7 +4,7 @@ object Macros {
def impl(c:Context): c.Expr[Any] = {
import c.universe._
- val selfTree = This(c.enclosingClass.symbol.asModule.moduleClass)
+ val selfTree = This(c.enclosingImpl.symbol.asModule.moduleClass)
c.Expr[AnyRef](selfTree)
}