diff options
Diffstat (limited to 'src/compiler/scala/reflect/reify/phases/Metalevels.scala')
-rw-r--r-- | src/compiler/scala/reflect/reify/phases/Metalevels.scala | 23 |
1 files changed, 12 insertions, 11 deletions
diff --git a/src/compiler/scala/reflect/reify/phases/Metalevels.scala b/src/compiler/scala/reflect/reify/phases/Metalevels.scala index fbbd12a42f..c69263399f 100644 --- a/src/compiler/scala/reflect/reify/phases/Metalevels.scala +++ b/src/compiler/scala/reflect/reify/phases/Metalevels.scala @@ -1,16 +1,17 @@ package scala.reflect.reify package phases +import scala.collection.{ mutable } + trait Metalevels { self: Reifier => import global._ - import definitions._ /** * Makes sense of cross-stage bindings. * - * ================ + * ---------------- * * Analysis of cross-stage bindings becomes convenient if we introduce the notion of metalevels. * Metalevel of a tree is a number that gets incremented every time you reify something and gets decremented when you splice something. @@ -32,27 +33,27 @@ trait Metalevels { * * 1) symbol.metalevel < curr_metalevel. In this case reifier will generate a free variable * that captures both the name of the symbol (to be compiled successfully) and its value (to be run successfully). - * For example, x in Example 1 will be reified as follows: Ident(newFreeVar("x", IntClass.tpe, x)) + * For example, x in Example 1 will be reified as follows: Ident(newFreeVar("x", IntTpe, x)) * * 2) symbol.metalevel > curr_metalevel. This leads to a metalevel breach that violates intuitive perception of splicing. * As defined in macro spec, splicing takes a tree and inserts it into another tree - as simple as that. * However, how exactly do we do that in the case of y.splice? In this very scenario we can use dataflow analysis and inline it, * but what if y were a var, and what if it were calculated randomly at runtime? * - * This question has a genuinely simple answer. Sure, we cannot resolve such splices statically (i.e. during macro expansion of ``reify''), + * This question has a genuinely simple answer. Sure, we cannot resolve such splices statically (i.e. during macro expansion of `reify`), * but now we have runtime toolboxes, so noone stops us from picking up that reified tree and evaluating it at runtime - * (in fact, this is something that ``Expr.splice'' does transparently). + * (in fact, this is something that `Expr.splice` does transparently). * * This is akin to early vs late binding dilemma. * The prior is faster, plus, the latter (implemented with reflection) might not work because of visibility issues or might be not available on all platforms. * But the latter still has its uses, so I'm allowing metalevel breaches, but introducing the -Xlog-runtime-evals to log them. * - * upd. We no longer do that. In case of a runaway ``splice'' inside a `reify`, one will get a static error. + * upd. We no longer do that. In case of a runaway `splice` inside a `reify`, one will get a static error. * Why? Unfortunately, the cute idea of transparently converting between static and dynamic splices has failed. * 1) Runtime eval that services dynamic splices requires scala-compiler.jar, which might not be on library classpath * 2) Runtime eval incurs a severe performance penalty, so it'd better to be explicit about it * - * ================ + * ---------------- * * As we can see, the only problem is the fact that lhs'es of `splice` can be code blocks that can capture variables from the outside. * Code inside the lhs of an `splice` is not reified, while the code from the enclosing reify is. @@ -71,7 +72,7 @@ trait Metalevels { * Since the result of the inner reify is wrapped in a splice, it won't be reified * together with the other parts of the outer reify, but will be inserted into that result verbatim. * - * The inner reify produces an Expr[Int] that wraps Ident(freeVar("x", IntClass.tpe, x)). + * The inner reify produces an Expr[Int] that wraps Ident(freeVar("x", IntTpe, x)). * However the freevar the reification points to will vanish when the compiler processes the outer reify. * That's why we need to replace that freevar with a regular symbol that will point to reified x. * @@ -102,7 +103,7 @@ trait Metalevels { */ val metalevels = new Transformer { var insideSplice = false - var inlineableBindings = scala.collection.mutable.Map[TermName, Tree]() + val inlineableBindings = mutable.Map[TermName, Tree]() def withinSplice[T](op: => T) = { val old = insideSplice @@ -124,7 +125,7 @@ trait Metalevels { withinSplice { super.transform(TreeSplice(ReifiedTree(universe, mirror, symtab1, rtree, tpe, rtpe, concrete))) } case TreeSplice(splicee) => if (reifyDebug) println("entering splice: " + splicee) - val breaches = splicee filter (sub => sub.hasSymbol && sub.symbol != NoSymbol && sub.symbol.metalevel > 0) + val breaches = splicee filter (sub => sub.hasSymbolField && sub.symbol != NoSymbol && sub.symbol.metalevel > 0) if (!insideSplice && breaches.nonEmpty) { // we used to convert dynamic splices into runtime evals transparently, but we no longer do that // why? see comments above @@ -135,7 +136,7 @@ trait Metalevels { } else { withinSplice { super.transform(tree) } } - // todo. also inline usages of ``inlineableBindings'' in the symtab itself + // todo. also inline usages of `inlineableBindings` in the symtab itself // e.g. a free$Foo can well use free$x, if Foo is path-dependent w.r.t x // FreeRef(_, _) check won't work, because metalevels of symbol table and body are different, hence, freerefs in symbol table look different from freerefs in body case FreeRef(_, name) if inlineableBindings contains name => |