summaryrefslogtreecommitdiff
path: root/src/reflect
diff options
context:
space:
mode:
authorEugene Burmako <xeno.by@gmail.com>2014-01-31 16:07:46 +0100
committerEugene Burmako <xeno.by@gmail.com>2014-02-14 23:51:23 +0100
commit63462f3d5f032639e80571176c91c34b91e65441 (patch)
tree6f5e5d1d1e28bb9a9dd8c9b0a2eb8076b26c76df /src/reflect
parent483bd3cacb34df3b3c2cc205338cb8e12cb89838 (diff)
downloadscala-63462f3d5f032639e80571176c91c34b91e65441.tar.gz
scala-63462f3d5f032639e80571176c91c34b91e65441.tar.bz2
scala-63462f3d5f032639e80571176c91c34b91e65441.zip
adds internal.changeOwner
As per Jason’s and Mark’s request, this commit introduces `changeOwner`, a facility to fixup symbol owner chains to prevent owner chain corruption in macro expansions leading to crashes in LambdaLift and GenICode. This is quite a low-level API that should only be used by expert users to get their job done. In the meanwhile we’ll be working on fixing the macro engine to automatically prevent owner chain corruption in the first place: https://groups.google.com/forum/#!topic/scala-internals/TtCTPlj_qcQ.
Diffstat (limited to 'src/reflect')
-rw-r--r--src/reflect/scala/reflect/internal/Internals.scala14
-rw-r--r--src/reflect/scala/reflect/macros/Universe.scala16
2 files changed, 30 insertions, 0 deletions
diff --git a/src/reflect/scala/reflect/internal/Internals.scala b/src/reflect/scala/reflect/internal/Internals.scala
index 9f503f66c3..cd2017e693 100644
--- a/src/reflect/scala/reflect/internal/Internals.scala
+++ b/src/reflect/scala/reflect/internal/Internals.scala
@@ -58,6 +58,20 @@ trait Internals extends api.Internals {
def typeDef(sym: Symbol): TypeDef = self.TypeDef(sym)
def labelDef(sym: Symbol, params: List[Symbol], rhs: Tree): LabelDef = self.LabelDef(sym, params, rhs)
+ def changeOwner(tree: Tree, prev: Symbol, next: Symbol): tree.type = {
+ object changeOwnerAndModuleClassTraverser extends ChangeOwnerTraverser(prev, next) {
+ override def traverse(tree: Tree) {
+ tree match {
+ case _: DefTree => change(tree.symbol.moduleClass)
+ case _ => // do nothing
+ }
+ super.traverse(tree)
+ }
+ }
+ changeOwnerAndModuleClassTraverser.traverse(tree)
+ tree
+ }
+
lazy val gen = self.treeBuild
def isFreeTerm(symbol: Symbol): Boolean = symbol.isFreeTerm
diff --git a/src/reflect/scala/reflect/macros/Universe.scala b/src/reflect/scala/reflect/macros/Universe.scala
index 9840295c95..15fd6bad99 100644
--- a/src/reflect/scala/reflect/macros/Universe.scala
+++ b/src/reflect/scala/reflect/macros/Universe.scala
@@ -25,6 +25,22 @@ abstract class Universe extends scala.reflect.api.Universe {
/** @inheritdoc */
trait MacroInternalApi extends InternalApi {
+ /** Collects all the symbols defined by subtrees of `tree` that are owned by `prev`,
+ * and then changes their owner to point to `next`.
+ *
+ * This is an essential tool to battle owner chain corruption when moving trees
+ * from one lexical context to another. Whenever you take an attributed tree that
+ * has been typechecked under the Context owned by some symbol (let's call it `x`)
+ * and splice it elsewhere, into the Context owned by another symbol (let's call it `y`),
+ * it is imperative that you either call `untypecheck` or do `changeOwner(tree, x, y)`.
+ *
+ * Since at the moment `untypecheck` has fundamental problem that can sometimes lead to tree corruption,
+ * `changeOwner` becomes an indispensible tool in building 100% robust macros.
+ * Future versions of the reflection API might obviate the need in taking care of
+ * these low-level details, but at the moment this is what we've got.
+ */
+ def changeOwner(tree: Tree, prev: Symbol, next: Symbol): tree.type
+
/** Advanced tree factories */
val gen: TreeGen