From 2375e2d878e6c493d9ab3097ef1d13d8641a6209 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Tue, 25 Dec 2012 02:08:21 +0100 Subject: enclosures are now strongly typed and are no longer vals --- .../scala/reflect/macros/runtime/Enclosures.scala | 19 +++++++--- src/reflect/scala/reflect/macros/Enclosures.scala | 44 ++++++++++++++++++---- test/files/run/macro-enclosures.check | 32 ++++++++++++++++ test/files/run/macro-enclosures.flags | 1 + .../run/macro-enclosures/Impls_Macros_1.scala | 14 +++++++ test/files/run/macro-enclosures/Test_2.scala | 11 ++++++ test/files/run/t6394a/Macros_1.scala | 2 +- 7 files changed, 109 insertions(+), 14 deletions(-) create mode 100644 test/files/run/macro-enclosures.check create mode 100644 test/files/run/macro-enclosures.flags create mode 100644 test/files/run/macro-enclosures/Impls_Macros_1.scala create mode 100644 test/files/run/macro-enclosures/Test_2.scala 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 () = { + super.(); + () + }; + def test = Macros.foo + } +} +enclosingClass = object Test extends scala.AnyRef { + def () = { + super.(); + () + }; + def test = Macros.foo +} +enclosingImpl = object Test extends scala.AnyRef { + def () = { + super.(); + () + }; + def test = Macros.foo +} +enclosingTemplate = scala.AnyRef { + def () = { + super.(); + () + }; + 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) } -- cgit v1.2.3