Skip to content

Commit 483bd3c

Browse files
committed
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.
1 parent d7dd68f commit 483bd3c

File tree

4 files changed

+24
-9
lines changed

4 files changed

+24
-9
lines changed

src/compiler/scala/reflect/macros/contexts/Enclosures.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ trait Enclosures {
1818
// vals are eager to simplify debugging
1919
// after all we wouldn't save that much time by making them lazy
2020
val macroApplication: Tree = expandee
21+
val enclosingOwner = site.owner
2122
def enclosingPackage: PackageDef = strictEnclosure[PackageDef]
2223
val enclosingClass: Tree = lenientEnclosure[ImplDef]
2324
def enclosingImpl: ImplDef = strictEnclosure[ImplDef]

src/reflect/scala/reflect/macros/Enclosures.scala

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ import scala.language.existentials // SI-6541
2020
* This is somewhat aligned with the overall evolution of macros during the 2.11 development cycle, where we played with
2121
* `c.introduceTopLevel` and `c.introduceMember`, but at the end of the day decided to reject them.
2222
*
23-
* If you're relying on the now deprecated APIs, consider reformulating your macros in terms of completely local expansion
23+
* If you're relying on the now deprecated APIs, consider using the new [[c.enclosingOwner]] method that can be used to obtain
24+
* the names of enclosing definitions. Alternatively try reformulating your macros in terms of completely local expansion
2425
* and/or joining a discussion of a somewhat related potential language feature at [[https://groups.google.com/forum/#!topic/scala-debate/f4CLmYShX6Q]].
2526
* We also welcome questions and suggestions on our mailing lists, where we would be happy to further discuss this matter.
2627
*/
@@ -51,6 +52,11 @@ trait Enclosures {
5152
*/
5253
def enclosingPosition: Position
5354

55+
/** Symbol associated with the innermost enclosing lexical context.
56+
* Walking the owner chain of this symbol will reveal information about more and more enclosing contexts.
57+
*/
58+
def enclosingOwner: Symbol
59+
5460
/** Tree that corresponds to the enclosing method, or EmptyTree if not applicable.
5561
* @see [[scala.reflect.macros.Enclosures]]
5662
*/

test/files/run/macro-enclosures.check

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,5 @@ enclosingTemplate = scala.AnyRef {
3030
}
3131
enclosingMethod = def test = Macros.foo
3232
enclosingDef = def test = Macros.foo
33+
enclosingOwner = method test
34+
enclosingOwnerChain = List(method test, object Test, package test, package <root>)

test/files/run/macro-enclosures/Impls_Macros_1.scala

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,21 @@ import scala.reflect.macros.blackbox.Context
33
object Macros {
44
def impl(c: Context) = {
55
import c.universe._
6-
reify {
7-
println("enclosingPackage = " + c.Expr[String](Literal(Constant(c.enclosingPackage.toString))).splice)
8-
println("enclosingClass = " + c.Expr[String](Literal(Constant(c.enclosingClass.toString))).splice)
9-
println("enclosingImpl = " + c.Expr[String](Literal(Constant(c.enclosingImpl.toString))).splice)
10-
println("enclosingTemplate = " + c.Expr[String](Literal(Constant(c.enclosingTemplate.toString))).splice)
11-
println("enclosingMethod = " + c.Expr[String](Literal(Constant(c.enclosingMethod.toString))).splice)
12-
println("enclosingDef = " + c.Expr[String](Literal(Constant(c.enclosingDef.toString))).splice)
6+
def chain(sym: Symbol): List[Symbol] = sym.owner match {
7+
case NoSymbol => sym :: Nil
8+
case owner => sym :: chain(owner)
139
}
10+
q"""
11+
println("enclosingPackage = " + ${c.enclosingPackage.toString})
12+
println("enclosingClass = " + ${c.enclosingClass.toString})
13+
println("enclosingImpl = " + ${c.enclosingImpl.toString})
14+
println("enclosingTemplate = " + ${c.enclosingTemplate.toString})
15+
println("enclosingMethod = " + ${c.enclosingMethod.toString})
16+
println("enclosingDef = " + ${c.enclosingDef.toString})
17+
println("enclosingOwner = " + ${c.enclosingOwner.toString})
18+
println("enclosingOwnerChain = " + ${chain(c.enclosingOwner).toString})
19+
"""
1420
}
1521

16-
def foo = macro impl
22+
def foo: Any = macro impl
1723
}

0 commit comments

Comments
 (0)