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 ++++++++++++++++++---- 2 files changed, 50 insertions(+), 13 deletions(-) (limited to 'src') 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 -- cgit v1.2.3