summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugene Burmako <xeno.by@gmail.com>2012-06-06 14:29:05 +0200
committerEugene Burmako <xeno.by@gmail.com>2012-06-08 15:32:03 +0200
commit6355d1a0b825c99560d4ccec1a8769f7421b1a71 (patch)
tree80f448f0da11dcab9cee30f3d8fe867cd66313ed
parentce67870e64afabf75363679bcee597812ad223e9 (diff)
downloadscala-6355d1a0b825c99560d4ccec1a8769f7421b1a71.tar.gz
scala-6355d1a0b825c99560d4ccec1a8769f7421b1a71.tar.bz2
scala-6355d1a0b825c99560d4ccec1a8769f7421b1a71.zip
brings reification up to speed
Along with recovering from reflection refactoring, I implemented some new features (e.g. rollback of macro expansions), and did some stabilizing refactorings (e.g. moved mutable state into a ghetto). Also used the refactoring as a chance to fix free and aux symbols. Encapsulated this notion in a symbol table class, which allowed me to address outstanding issues with symbol table inheritance and inlining.
-rw-r--r--src/compiler/scala/reflect/internal/StdAttachments.scala6
-rw-r--r--src/compiler/scala/reflect/internal/StdNames.scala20
-rw-r--r--src/compiler/scala/reflect/internal/TreeInfo.scala173
-rw-r--r--src/compiler/scala/reflect/makro/runtime/ContextReifiers.scala26
-rw-r--r--src/compiler/scala/reflect/makro/runtime/Reifiers.scala55
-rw-r--r--src/compiler/scala/reflect/reify/Errors.scala19
-rw-r--r--src/compiler/scala/reflect/reify/NodePrinters.scala24
-rw-r--r--src/compiler/scala/reflect/reify/Phases.scala21
-rw-r--r--src/compiler/scala/reflect/reify/Reifier.scala112
-rw-r--r--src/compiler/scala/reflect/reify/States.scala65
-rw-r--r--src/compiler/scala/reflect/reify/Taggers.scala67
-rw-r--r--src/compiler/scala/reflect/reify/codegen/GenAnnotationInfos.scala (renamed from src/compiler/scala/reflect/reify/codegen/AnnotationInfos.scala)13
-rw-r--r--src/compiler/scala/reflect/reify/codegen/GenNames.scala (renamed from src/compiler/scala/reflect/reify/codegen/Names.scala)5
-rw-r--r--src/compiler/scala/reflect/reify/codegen/GenPositions.scala (renamed from src/compiler/scala/reflect/reify/codegen/Positions.scala)5
-rw-r--r--src/compiler/scala/reflect/reify/codegen/GenSymbols.scala109
-rw-r--r--src/compiler/scala/reflect/reify/codegen/GenTrees.scala (renamed from src/compiler/scala/reflect/reify/codegen/Trees.scala)139
-rw-r--r--src/compiler/scala/reflect/reify/codegen/GenTypes.scala203
-rw-r--r--src/compiler/scala/reflect/reify/codegen/GenUtils.scala (renamed from src/compiler/scala/reflect/reify/codegen/Util.scala)53
-rw-r--r--src/compiler/scala/reflect/reify/codegen/Symbols.scala184
-rw-r--r--src/compiler/scala/reflect/reify/codegen/Types.scala168
-rw-r--r--src/compiler/scala/reflect/reify/package.scala81
-rw-r--r--src/compiler/scala/reflect/reify/phases/Calculate.scala17
-rw-r--r--src/compiler/scala/reflect/reify/phases/Metalevels.scala82
-rw-r--r--src/compiler/scala/reflect/reify/phases/Reify.scala31
-rw-r--r--src/compiler/scala/reflect/reify/phases/Reshape.scala47
-rw-r--r--src/compiler/scala/reflect/reify/utils/Extractors.scala294
-rw-r--r--src/compiler/scala/reflect/reify/utils/NodePrinters.scala144
-rw-r--r--src/compiler/scala/reflect/reify/utils/StdAttachments.scala12
-rw-r--r--src/compiler/scala/reflect/reify/utils/SymbolTables.scala223
-rw-r--r--src/compiler/scala/reflect/reify/utils/Utils.scala21
-rw-r--r--src/compiler/scala/reflect/runtime/package.scala15
-rw-r--r--src/compiler/scala/tools/nsc/settings/ScalaSettings.scala1
-rw-r--r--src/compiler/scala/tools/nsc/transform/Erasure.scala2
-rw-r--r--src/compiler/scala/tools/nsc/transform/UnCurry.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Implicits.scala6
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Macros.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Taggings.scala71
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Tags.scala86
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala18
-rw-r--r--src/compiler/scala/tools/reflect/FastTrack.scala11
-rw-r--r--src/compiler/scala/tools/reflect/ToolBoxFactory.scala2
-rw-r--r--src/library/scala/reflect/api/StandardNames.scala15
-rw-r--r--src/library/scala/reflect/makro/Context.scala2
-rw-r--r--src/library/scala/reflect/makro/Reifiers.scala25
44 files changed, 1707 insertions, 970 deletions
diff --git a/src/compiler/scala/reflect/internal/StdAttachments.scala b/src/compiler/scala/reflect/internal/StdAttachments.scala
index 33e3eb03b7..df1a1267de 100644
--- a/src/compiler/scala/reflect/internal/StdAttachments.scala
+++ b/src/compiler/scala/reflect/internal/StdAttachments.scala
@@ -6,7 +6,9 @@ import scala.reflect.makro.runtime.{Context => MacroContext}
trait StdAttachments {
self: SymbolTable =>
- case class ReifyAttachment(original: Symbol)
-
case object BackquotedIdentifierAttachment
+
+ case class CompoundTypeTreeOriginalAttachment(parents: List[Tree], stats: List[Tree])
+
+ case class MacroExpansionAttachment(original: Tree)
} \ No newline at end of file
diff --git a/src/compiler/scala/reflect/internal/StdNames.scala b/src/compiler/scala/reflect/internal/StdNames.scala
index 07fbe6f049..0e5f3efb49 100644
--- a/src/compiler/scala/reflect/internal/StdNames.scala
+++ b/src/compiler/scala/reflect/internal/StdNames.scala
@@ -213,6 +213,8 @@ trait StdNames {
final val REFINE_CLASS_NAME: NameType = "<refinement>"
final val REPEATED_PARAM_CLASS_NAME: NameType = "<repeated>"
final val WILDCARD_STAR: NameType = "_*"
+ final val REIFY_TREECREATOR_PREFIX: NameType = "$treecreator"
+ final val REIFY_TYPECREATOR_PREFIX: NameType = "$typecreator"
final val Any: NameType = "Any"
final val AnyVal: NameType = "AnyVal"
@@ -299,12 +301,17 @@ trait StdNames {
val LAZY_LOCAL: NameType = "$lzy"
val LAZY_SLOW_SUFFIX: NameType = "$lzycompute"
val LOCAL_SUFFIX_STRING = " "
- val MIRROR_FREE_PREFIX: NameType = "free$"
- val MIRROR_FREE_THIS_SUFFIX: NameType = "$this"
- val MIRROR_FREE_VALUE_SUFFIX: NameType = "$value"
- val MIRROR_PREFIX: NameType = "$mr."
- val MIRROR_SHORT: NameType = "$mr"
- val MIRROR_SYMDEF_PREFIX: NameType = "symdef$"
+ val UNIVERSE_BUILD_PREFIX: NameType = "$u.build."
+ val UNIVERSE_BUILD: NameType = "$u.build"
+ val UNIVERSE_PREFIX: NameType = "$u."
+ val UNIVERSE_SHORT: NameType = "$u"
+ val MIRROR_PREFIX: NameType = "$m."
+ val MIRROR_SHORT: NameType = "$m"
+ val MIRROR_UNTYPED: NameType = "$m$untyped"
+ val REIFY_FREE_PREFIX: NameType = "free$"
+ val REIFY_FREE_THIS_SUFFIX: NameType = "$this"
+ val REIFY_FREE_VALUE_SUFFIX: NameType = "$value"
+ val REIFY_SYMDEF_PREFIX: NameType = "symdef$"
val MIXIN_CONSTRUCTOR: NameType = "$init$"
val MODULE_INSTANCE_FIELD: NameType = NameTransformer.MODULE_INSTANCE_NAME // "MODULE$"
val OUTER: NameType = "$outer"
@@ -747,7 +754,6 @@ trait StdNames {
val tail: NameType = "tail"
val `then` : NameType = "then"
val this_ : NameType = "this"
- val thisModuleType : NameType = "thisModuleType"
val thisPrefix : NameType = "thisPrefix"
val throw_ : NameType = "throw"
val toArray: NameType = "toArray"
diff --git a/src/compiler/scala/reflect/internal/TreeInfo.scala b/src/compiler/scala/reflect/internal/TreeInfo.scala
index fc6e31ce1b..4b2105876d 100644
--- a/src/compiler/scala/reflect/internal/TreeInfo.scala
+++ b/src/compiler/scala/reflect/internal/TreeInfo.scala
@@ -568,177 +568,4 @@ abstract class TreeInfo {
object DynamicUpdate extends DynamicApplicationExtractor(_ == nme.updateDynamic)
object DynamicApplication extends DynamicApplicationExtractor(isApplyDynamicName)
object DynamicApplicationNamed extends DynamicApplicationExtractor(_ == nme.applyDynamicNamed)
-
-
- // domain-specific extractors for reification
-
- import definitions._
-
- object TypedOrAnnotated {
- def unapply(tree: Tree): Option[Tree] = tree match {
- case ty @ Typed(_, _) =>
- Some(ty)
- case at @ Annotated(_, _) =>
- Some(at)
- case _ =>
- None
- }
- }
-
- object TreeSplice {
- def unapply(tree: Tree): Option[Tree] = tree match {
- case Select(splicee, _) if tree.symbol == ExprSplice =>
- Some(splicee)
- case _ =>
- None
- }
- }
-
- object Reified {
- def unapply(tree: Tree): Option[(Tree, List[Tree], Tree)] = tree match {
- case ReifiedTree(reifee, symbolTable, reified, _) =>
- Some(reifee, symbolTable, reified)
- case ReifiedType(reifee, symbolTable, reified) =>
- Some(reifee, symbolTable, reified)
- case _ =>
- None
- }
- }
-
- object ReifiedTree {
- def unapply(tree: Tree): Option[(Tree, List[Tree], Tree, Tree)] = tree match {
- case reifee @ Block((mrDef @ ValDef(_, _, _, _)) :: symbolTable, Apply(Apply(_, List(tree)), List(Apply(_, tpe :: _)))) if mrDef.name == nme.MIRROR_SHORT =>
- Some(reifee, symbolTable, tree, tpe)
- case _ =>
- None
- }
- }
-
- object InlineableTreeSplice {
- def unapply(tree: Tree): Option[(Tree, List[Tree], Tree, Tree, Symbol)] = tree match {
- case select @ Select(ReifiedTree(splicee, symbolTable, tree, tpe), _) if select.symbol == ExprSplice =>
- Some(splicee, symbolTable, tree, tpe, select.symbol)
- case _ =>
- None
- }
- }
-
- object InlinedTreeSplice {
- def unapply(tree: Tree): Option[(Tree, List[Tree], Tree, Tree)] = tree match {
- case Select(ReifiedTree(splicee, symbolTable, tree, tpe), name) if name == nme.tree =>
- Some(splicee, symbolTable, tree, tpe)
- case _ =>
- None
- }
- }
-
- object ReifiedType {
- def unapply(tree: Tree): Option[(Tree, List[Tree], Tree)] = tree match {
- case reifee @ Block((mrDef @ ValDef(_, _, _, _)) :: symbolTable, Apply(_, tpe :: _)) if mrDef.name == nme.MIRROR_SHORT =>
- Some(reifee, symbolTable, tpe)
- case _ =>
- None
- }
- }
-
- object InlinedTypeSplice {
- def unapply(tree: Tree): Option[(Tree, List[Tree], Tree)] = tree match {
- case Select(ReifiedType(splicee, symbolTable, tpe), name) if name == nme.tpe =>
- Some(splicee, symbolTable, tpe)
- case _ =>
- None
- }
- }
-
- object FreeDef {
- def unapply(tree: Tree): Option[(Tree, TermName, Tree, Long, String)] = tree match {
- case FreeTermDef(mrRef, name, binding, flags, origin) =>
- Some(mrRef, name, binding, flags, origin)
- case FreeTypeDef(mrRef, name, binding, flags, origin) =>
- Some(mrRef, name, binding, flags, origin)
- case _ =>
- None
- }
- }
-
- object FreeTermDef {
- def unapply(tree: Tree): Option[(Tree, TermName, Tree, Long, String)] = tree match {
- case ValDef(_, name, _, Apply(Select(mrRef @ Ident(_), newFreeTerm), List(_, _, binding, Literal(Constant(flags: Long)), Literal(Constant(origin: String)))))
- if mrRef.name == nme.MIRROR_SHORT && newFreeTerm == nme.newFreeTerm =>
- Some(mrRef, name, binding, flags, origin)
- case _ =>
- None
- }
- }
-
- object FreeTypeDef {
- def unapply(tree: Tree): Option[(Tree, TermName, Tree, Long, String)] = tree match {
- case ValDef(_, name, _, Apply(Select(mrRef1 @ Ident(_), newFreeType), List(_, _, value, Literal(Constant(flags: Long)), Literal(Constant(origin: String)))))
- if mrRef1.name == nme.MIRROR_SHORT && (newFreeType == nme.newFreeType || newFreeType == nme.newFreeExistential) =>
- value match {
- case Apply(TypeApply(Select(Select(mrRef2 @ Ident(_), typeTag), apply), List(binding)), List(Literal(Constant(null)), _))
- if mrRef2.name == nme.MIRROR_SHORT && typeTag == nme.TypeTag && apply == nme.apply =>
- Some(mrRef1, name, binding, flags, origin)
- case Apply(TypeApply(Select(mrRef2 @ Ident(_), typeTag), List(binding)), List(Literal(Constant(null)), _))
- if mrRef2.name == nme.MIRROR_SHORT && typeTag == nme.TypeTag =>
- Some(mrRef1, name, binding, flags, origin)
- case _ =>
- throw new Error("unsupported free type def: %s%n%s".format(value, showRaw(value)))
- }
- case _ =>
- None
- }
- }
-
- object FreeRef {
- def unapply(tree: Tree): Option[(Tree, TermName)] = tree match {
- case Apply(Select(mrRef @ Ident(_), ident), List(Ident(name: TermName))) if ident == nme.Ident && name.startsWith(nme.MIRROR_FREE_PREFIX) =>
- Some(mrRef, name)
- case _ =>
- None
- }
- }
-
- object TypeRefToFreeType {
- def unapply(tree: Tree): Option[TermName] = tree match {
- case Apply(Select(Select(mrRef @ Ident(_), typeRef), apply), List(Select(_, noSymbol), Ident(freeType: TermName), nil))
- if (mrRef.name == nme.MIRROR_SHORT && typeRef == nme.TypeRef && noSymbol == nme.NoSymbol && freeType.startsWith(nme.MIRROR_FREE_PREFIX)) =>
- Some(freeType)
- case _ =>
- None
- }
- }
-
- object NestedExpr {
- def unapply(tree: Tree): Option[(Tree, Tree, Tree)] = tree match {
- case Apply(Apply(factory @ Select(expr, apply), List(tree)), List(typetag)) if expr.symbol == ExprModule && apply == nme.apply =>
- Some(factory, tree, typetag)
- case _ =>
- None
- }
- }
-
- object BoundTerm {
- def unapply(tree: Tree): Option[Tree] = tree match {
- case Ident(name) if name.isTermName =>
- Some(tree)
- case This(_) =>
- Some(tree)
- case _ =>
- None
- }
- }
-
- object BoundType {
- def unapply(tree: Tree): Option[Tree] = tree match {
- case Select(_, name) if name.isTypeName =>
- Some(tree)
- case SelectFromTypeTree(_, name) if name.isTypeName =>
- Some(tree)
- case Ident(name) if name.isTypeName =>
- Some(tree)
- case _ =>
- None
- }
- }
}
diff --git a/src/compiler/scala/reflect/makro/runtime/ContextReifiers.scala b/src/compiler/scala/reflect/makro/runtime/ContextReifiers.scala
new file mode 100644
index 0000000000..564148fe6c
--- /dev/null
+++ b/src/compiler/scala/reflect/makro/runtime/ContextReifiers.scala
@@ -0,0 +1,26 @@
+package scala.reflect.makro
+package runtime
+
+abstract class ContextReifiers { self =>
+ val c: Context
+
+ import c.universe._
+ import definitions._
+ import treeBuild._
+
+ import scala.reflect.reify.Taggers
+ import language.implicitConversions
+ private implicit def context2taggers(c0: Context) : Taggers { val c: c0.type } = new { val c: c0.type = c0 } with Taggers
+
+ private def forMacroContext[T](prefix: Tree)(op: (Tree, Tree) => T): T = {
+ val universe = gen.mkAttributedSelect(prefix.duplicate, MacroContextUniverse) setType SingleType(prefix.tpe, MacroContextUniverse)
+ val mirror = TypeApply(Select(Select(prefix.duplicate, nme.mirror), nme.asInstanceOf_), List(Select(Ident(nme.UNIVERSE_SHORT), tpnme.Mirror)))
+ op(universe, mirror)
+ }
+
+ def materializeExprForMacroContext(prefix: Tree, expr: Tree): Tree =
+ forMacroContext(prefix)((universe, mirror) => c.materializeExpr(universe, mirror, expr))
+
+ def materializeTypeTagForMacroContext(prefix: Tree, tpe: Type, concrete: Boolean): Tree =
+ forMacroContext(prefix)((universe, mirror) => c.materializeTypeTag(universe, mirror, tpe, concrete))
+} \ No newline at end of file
diff --git a/src/compiler/scala/reflect/makro/runtime/Reifiers.scala b/src/compiler/scala/reflect/makro/runtime/Reifiers.scala
index 7d404128fb..c578fceb2c 100644
--- a/src/compiler/scala/reflect/makro/runtime/Reifiers.scala
+++ b/src/compiler/scala/reflect/makro/runtime/Reifiers.scala
@@ -9,20 +9,59 @@ package runtime
trait Reifiers {
self: Context =>
+ val global: universe.type = universe
import universe._
import definitions._
- lazy val reflectMirrorPrefix: Tree = ???
+ lazy val basisUniverse: Tree = gen.mkBasisUniverseRef
- def reifyTree(prefix: Tree, tree: Tree): Tree =
- scala.reflect.reify.`package`.reifyTree(universe)(callsiteTyper, prefix, tree)
+ lazy val runtimeUniverse: Tree = gen.mkRuntimeUniverseRef
- def reifyType(prefix: Tree, tpe: Type, dontSpliceAtTopLevel: Boolean = false, concrete: Boolean = false): Tree =
- scala.reflect.reify.`package`.reifyType(universe)(callsiteTyper, prefix, tpe, dontSpliceAtTopLevel, concrete)
+ def reifyTree(universe: Tree, mirror: Tree, tree: Tree): Tree = {
+ val result = scala.reflect.reify.`package`.reifyTree(self.universe)(callsiteTyper, universe, mirror, tree)
+ logFreeVars(enclosingPosition, result)
+ result
+ }
+
+ def reifyType(universe: Tree, mirror: Tree, tpe: Type, concrete: Boolean = false): Tree = {
+ val result = scala.reflect.reify.`package`.reifyType(self.universe)(callsiteTyper, universe, mirror, tpe, concrete)
+ logFreeVars(enclosingPosition, result)
+ result
+ }
def reifyRuntimeClass(tpe: Type, concrete: Boolean = true): Tree =
- scala.reflect.reify.`package`.reifyRuntimeClass(universe)(callsiteTyper, tpe, concrete)
+ scala.reflect.reify.`package`.reifyRuntimeClass(universe)(callsiteTyper, tpe, concrete = concrete)
+
+ def reifyEnclosingRuntimeClass: Tree =
+ scala.reflect.reify.`package`.reifyEnclosingRuntimeClass(universe)(callsiteTyper)
+
+ def unreifyTree(tree: Tree): Tree = {
+ assert(ExprSplice != NoSymbol)
+ Select(tree, ExprSplice)
+ }
+
+ object utils extends {
+ val global: self.global.type = self.global
+ val typer: global.analyzer.Typer = self.callsiteTyper
+ } with scala.reflect.reify.utils.Utils
+ import utils._
+
+ private def logFreeVars(position: Position, reification: Tree): Unit = {
+ def logFreeVars(symtab: SymbolTable): Unit =
+ // logging free vars only when they are untyped prevents avalanches of duplicate messages
+ symtab.syms map (sym => symtab.symDef(sym)) foreach {
+ case FreeTermDef(_, _, binding, _, origin) if universe.settings.logFreeTerms.value && binding.tpe == null =>
+ reporter.echo(position, "free term: %s %s".format(showRaw(binding), origin))
+ case FreeTypeDef(_, _, binding, _, origin) if universe.settings.logFreeTypes.value && binding.tpe == null =>
+ reporter.echo(position, "free type: %s %s".format(showRaw(binding), origin))
+ case _ =>
+ // do nothing
+ }
- def unreifyTree(tree: Tree): Tree =
- Select(tree, definitions.ExprSplice)
+ if (universe.settings.logFreeTerms.value || universe.settings.logFreeTypes.value)
+ reification match {
+ case ReifiedTree(_, _, symtab, _, _, _, _) => logFreeVars(symtab)
+ case ReifiedType(_, _, symtab, _, _, _) => logFreeVars(symtab)
+ }
+ }
}
diff --git a/src/compiler/scala/reflect/reify/Errors.scala b/src/compiler/scala/reflect/reify/Errors.scala
index 6edadf3a47..824f237948 100644
--- a/src/compiler/scala/reflect/reify/Errors.scala
+++ b/src/compiler/scala/reflect/reify/Errors.scala
@@ -7,7 +7,7 @@ import scala.reflect.makro.UnexpectedReificationError
trait Errors {
self: Reifier =>
- import mirror._
+ import global._
import definitions._
def defaultErrorPosition = {
@@ -38,6 +38,23 @@ trait Errors {
throw new ReificationError(defaultErrorPosition, msg)
}
+ def CannotConvertManifestToTagWithoutScalaReflect(tpe: Type, manifestInScope: Tree) = {
+ val msg = s"""
+ |to create a type tag here, it is necessary to interoperate with the manifest `$manifestInScope` in scope.
+ |however manifest -> typetag conversion requires Scala reflection, which is not present on the classpath.
+ |to proceed put scala-reflect.jar on your compilation classpath and recompile.""".trim.stripMargin
+ throw new ReificationError(defaultErrorPosition, msg)
+ }
+
+ def CannotReifyRuntimeSplice(tree: Tree) = {
+ val msg = """
+ |the splice cannot be resolved statically, which means there is a cross-stage evaluation involved.
+ |cross-stage evaluations need to be invoked explicitly, so we're showing you this error.
+ |if you're sure this is not an oversight, add scala-compiler.jar to the classpath,
+ |import `scala.tools.reflect.Eval` and call `<your expr>.eval` instead.""".trim.stripMargin
+ throw new ReificationError(tree.pos, msg)
+ }
+
// unexpected errors: these can never happen under normal conditions unless there's a bug in the compiler (or in a compiler plugin or in a macro)
// hence, we fail fast and loudly and don't care about being nice - in this situation noone will appreciate our quiet nicety
diff --git a/src/compiler/scala/reflect/reify/NodePrinters.scala b/src/compiler/scala/reflect/reify/NodePrinters.scala
deleted file mode 100644
index f0d0d0f5d4..0000000000
--- a/src/compiler/scala/reflect/reify/NodePrinters.scala
+++ /dev/null
@@ -1,24 +0,0 @@
-/* NSC -- new Scala compiler
- * Copyright 2005-2011 LAMP/EPFL
- * @author Martin Odersky
- */
-
-package scala.reflect
-package reify
-
-import scala.Array.canBuildFrom
-import scala.compat.Platform.EOL
-import scala.tools.nsc.symtab.Flags
-import scala.tools.nsc.Global
-
-trait NodePrinters { self: scala.tools.nsc.ast.NodePrinters =>
-
- val global: Global
- import global._
-
- object reifiedNodeToString extends Function2[Tree, Tree, String] {
- def apply(prefix: Tree, tree: Tree): String = {
- "temporarily disabled until reification is repaired"
- }
- }
-} \ No newline at end of file
diff --git a/src/compiler/scala/reflect/reify/Phases.scala b/src/compiler/scala/reflect/reify/Phases.scala
index 49d5a45e8e..54336ee708 100644
--- a/src/compiler/scala/reflect/reify/Phases.scala
+++ b/src/compiler/scala/reflect/reify/Phases.scala
@@ -1,16 +1,16 @@
package scala.reflect
package reify
-import scala.reflect.reify.phases._
+import phases._
-trait Phases extends Calculate
- with Reshape
+trait Phases extends Reshape
+ with Calculate
with Metalevels
with Reify {
self: Reifier =>
- import mirror._
+ import global._
import definitions._
private var alreadyRun = false
@@ -26,16 +26,19 @@ trait Phases extends Calculate
if (reifyDebug) println("[reshape phase]")
tree = reshape.transform(tree)
+ if (reifyDebug) println("[interlude]")
+ if (reifyDebug) println("reifee = " + (if (opt.showTrees) "\n" + nodePrinters.nodeToString(tree).trim else tree.toString))
+
+ if (reifyDebug) println("[calculate phase]")
+ calculate.traverse(tree)
if (reifyDebug) println("[metalevels phase]")
tree = metalevels.transform(tree)
-
if (reifyDebug) println("[interlude]")
- if (reifyDebug) println("symbol table = " + (if (symbolTable.length == 0) "<empty>" else ""))
- if (reifyDebug) symbolTable foreach (println(_))
- if (reifyDebug) println("reifee = " + (if (opt.showTrees) "\n" + nodePrinters.nodeToString(tree).trim else tree.toString))
+ if (reifyDebug) println(symtab.debugString)
+
if (reifyDebug) println("[reify phase]")
- var result = reify(tree)
+ val result = reify(tree)
result
}
diff --git a/src/compiler/scala/reflect/reify/Reifier.scala b/src/compiler/scala/reflect/reify/Reifier.scala
index 41b45741ba..a5b2fef18c 100644
--- a/src/compiler/scala/reflect/reify/Reifier.scala
+++ b/src/compiler/scala/reflect/reify/Reifier.scala
@@ -4,6 +4,7 @@ package reify
import scala.tools.nsc.Global
import scala.reflect.makro.ReificationError
import scala.reflect.makro.UnexpectedReificationError
+import scala.reflect.reify.utils.Utils
/** Given a tree or a type, generate a tree that when executed at runtime produces the original tree or type.
* See more info in the comments to ``reify'' in scala.reflect.api.Universe.
@@ -11,51 +12,59 @@ import scala.reflect.makro.UnexpectedReificationError
* @author Martin Odersky
* @version 2.10
*/
-abstract class Reifier extends Phases
- with Errors {
+abstract class Reifier extends States
+ with Phases
+ with Errors
+ with Utils {
- val mirror: Global
- import mirror._
+ val global: Global
+ import global._
import definitions._
- import treeInfo._
- val typer: mirror.analyzer.Typer
- val prefix: Tree
+ val typer: global.analyzer.Typer
+ val universe: Tree
+ val mirror: Tree
val reifee: Any
- val dontSpliceAtTopLevel: Boolean
val concrete: Boolean
+ // needed to seamlessly integrate with standalone utils
+ override def getReifier: Reifier { val global: Reifier.this.global.type } =
+ this.asInstanceOf[Reifier { val global: Reifier.this.global.type }]
+ override def hasReifier = true
+
/**
* For ``reifee'' and other reification parameters, generate a tree of the form
*
* {
- * val $mr = <[ prefix ]>
- * $mr.Expr[T](rtree) // if data is a Tree
- * $mr.TypeTag[T](rtree) // if data is a Type
+ * val $u: universe.type = <[ universe ]>
+ * val $m: $u.Mirror = <[ mirror ]>
+ * $u.Expr[T](rtree) // if data is a Tree
+ * $u.TypeTag[T](rtree) // if data is a Type
* }
*
* where
*
- * - `prefix` is the tree that represents the universe
- * the result will be bound to
+ * - `universe` is the tree that represents the universe the result will be bound to
+ * - `mirror` is the tree that represents the mirror the result will be initially bound to
* - `rtree` is code that generates `reifee` at runtime.
* - `T` is the type that corresponds to `data`.
*
* This is not a method, but a value to indicate the fact that Reifier instances are a one-off.
*/
- lazy val reified: Tree = {
+ lazy val reification: Tree = {
try {
// [Eugene] conventional way of doing this?
- if (prefix exists (_.isErroneous)) CannotReifyErroneousPrefix(prefix)
- if (prefix.tpe == null) CannotReifyUntypedPrefix(prefix)
+ if (universe exists (_.isErroneous)) CannotReifyErroneousPrefix(universe)
+ if (universe.tpe == null) CannotReifyUntypedPrefix(universe)
- val rtree = reifee match {
+ val result = reifee match {
case tree: Tree =>
reifyTrace("reifying = ")(if (opt.showTrees) "\n" + nodePrinters.nodeToString(tree).trim else tree.toString)
reifyTrace("reifee is located at: ")(tree.pos)
- reifyTrace("prefix = ")(prefix)
+ reifyTrace("universe = ")(universe)
+ reifyTrace("mirror = ")(mirror)
// [Eugene] conventional way of doing this?
- if (tree exists (_.isErroneous)) CannotReifyErroneousReifee(prefix)
+ if (tree exists (_.isErroneous)) CannotReifyErroneousReifee(tree)
if (tree.tpe == null) CannotReifyUntypedReifee(tree)
val pipeline = mkReificationPipeline
val rtree = pipeline(tree)
@@ -74,31 +83,23 @@ abstract class Reifier extends Phases
if (tree.tpe exists (sub => sub.typeSymbol.isLocalToReifee))
CannotReifyReifeeThatHasTypeLocalToReifee(tree)
- val taggedType = typer.packedType(tree, NoSymbol)
- val tagModule = if (reificationIsConcrete) ConcreteTypeTagModule else TypeTagModule
- val tagCtor = TypeApply(Select(Ident(nme.MIRROR_SHORT), tagModule.name), List(TypeTree(taggedType)))
- val exprCtor = TypeApply(Select(Ident(nme.MIRROR_SHORT), ExprModule.name), List(TypeTree(taggedType)))
- val tagArgs = List(reify(taggedType), reifyRuntimeClass(mirror)(typer, taggedType, concrete = false))
- Apply(Apply(exprCtor, List(rtree)), List(Apply(tagCtor, tagArgs)))
+ val tpe = typer.packedType(tree, NoSymbol)
+ val ReifiedType(_, _, tpeSymtab, _, rtpe, tpeReificationIsConcrete) = `package`.reifyType(global)(typer, universe, mirror, tpe, concrete = false)
+ state.reificationIsConcrete &= tpeReificationIsConcrete
+ state.symtab ++= tpeSymtab
+ ReifiedTree(universe, mirror, symtab, rtree, tpe, rtpe, reificationIsConcrete)
case tpe: Type =>
reifyTrace("reifying = ")(tpe.toString)
- reifyTrace("prefix = ")(prefix)
+ reifyTrace("universe = ")(universe)
+ reifyTrace("mirror = ")(mirror)
val rtree = reify(tpe)
-
- val taggedType = tpe
- val tagModule = if (reificationIsConcrete) ConcreteTypeTagModule else TypeTagModule
- val ctor = TypeApply(Select(Ident(nme.MIRROR_SHORT), tagModule.name), List(TypeTree(taggedType)))
- val args = List(rtree, reifyRuntimeClass(mirror)(typer, taggedType, concrete = false))
- Apply(ctor, args)
+ ReifiedType(universe, mirror, symtab, tpe, rtree, reificationIsConcrete)
case _ =>
throw new Error("reifee %s of type %s is not supported".format(reifee, if (reifee == null) "null" else reifee.getClass.toString))
}
- val mirrorAlias = ValDef(NoMods, nme.MIRROR_SHORT, SingletonTypeTree(prefix), prefix)
- val wrapped = Block(mirrorAlias :: symbolTable, rtree)
-
// todo. why do we resetAllAttrs?
//
// typically we do some preprocessing before reification and
@@ -107,14 +108,14 @@ abstract class Reifier extends Phases
//
// ===example 1===
// we move a freevar from a nested symbol table to a top-level symbol table,
- // and then the reference to mr$ becomes screwed up, because nested symbol tables are already typechecked,
- // so we have an mr$ symbol that points to the nested mr$ rather than to the top-level one.
+ // and then the reference to $u becomes screwed up, because nested symbol tables are already typechecked,
+ // so we have an $u symbol that points to the nested $u rather than to the top-level one.
//
// ===example 2===
- // we inline a freevar by replacing a reference to it, e.g. $mr.Apply($mr.Select($mr.Ident($mr.newTermName("$mr")), $mr.newTermName("Ident")), List($mr.Ident($mr.newTermName("free$x"))))
- // with its original binding (e.g. $mr.Ident("x"))
- // we'd love to typecheck the result, but we cannot do this easily, because $mr is external to this tree
- // what's even worse, sometimes $mr can point to the top-level symbol table's $mr, which doesn't have any symbol/type yet -
+ // we inline a freevar by replacing a reference to it, e.g. $u.Apply($u.Select($u.Ident($u.newTermName("$u")), $u.newTermName("Ident")), List($u.Ident($u.newTermName("free$x"))))
+ // with its original binding (e.g. $u.Ident("x"))
+ // we'd love to typecheck the result, but we cannot do this easily, because $u is external to this tree
+ // what's even worse, sometimes $u can point to the top-level symbol table's $u, which doesn't have any symbol/type yet -
// it's just a ValDef that will be emitted only after the reification is completed
//
// hence, the simplest solution is to erase all attrs so that invalid (as well as non-existent) bindings get rebound correctly
@@ -124,31 +125,30 @@ abstract class Reifier extends Phases
// needs to be solved some day
//
// list of non-hygienic transformations:
- // 1) local freetype inlining in Nested
- // 2) external freevar moving in Nested
- // 3) local freeterm inlining in Metalevels
- // 4) trivial tree splice inlining in Reify (Trees.scala)
- // 5) trivial type splice inlining in Reify (Types.scala)
- val freevarBindings = symbolTable collect { case entry @ FreeDef(_, _, binding, _, _) => binding.symbol } toSet
- // [Eugene] yeah, ugly and extremely brittle, but we do need to do resetAttrs. will be fixed later
- var importantSymbols = Set[Symbol](PredefModule, ScalaRunTimeModule)
+ // todo. to be updated
+ // [Eugene++] yeah, ugly and extremely brittle, but we do need to do resetAttrs. will be fixed later
+ // todo. maybe try `resetLocalAttrs` once the dust settles
+ var importantSymbols = Set[Symbol](
+ NothingClass, AnyClass, SingletonClass, PredefModule, ScalaRunTimeModule, TypeCreatorClass, TreeCreatorClass, MirrorOfClass,
+ BaseUniverseClass, ApiUniverseClass, JavaUniverseClass, ReflectRuntimePackage, ReflectRuntimeCurrentMirror)
importantSymbols ++= importantSymbols map (_.companionSymbol)
importantSymbols ++= importantSymbols map (_.moduleClass)
importantSymbols ++= importantSymbols map (_.linkedClassOfClass)
- def importantSymbol(sym: Symbol): Boolean = sym != null && sym != NoSymbol && importantSymbols(sym)
- val untyped = resetAllAttrs(wrapped, leaveAlone = {
- case ValDef(_, mr, _, _) if mr == nme.MIRROR_SHORT => true
- case tree if freevarBindings contains tree.symbol => true
- case tree if importantSymbol(tree.symbol) => true
+ def isImportantSymbol(sym: Symbol): Boolean = sym != null && sym != NoSymbol && importantSymbols(sym)
+ val untyped = resetAllAttrs(result, leaveAlone = {
+ case ValDef(_, u, _, _) if u == nme.UNIVERSE_SHORT => true
+ case ValDef(_, m, _, _) if m == nme.MIRROR_SHORT => true
+ case tree if symtab.syms contains tree.symbol => true
+ case tree if isImportantSymbol(tree.symbol) => true
case _ => false
})
if (reifyCopypaste) {
if (reifyDebug) println("=============================")
- println(reifiedNodeToString(prefix, untyped))
+ println(reifiedNodeToString(untyped))
if (reifyDebug) println("=============================")
} else {
- reifyTrace("reified = ")(untyped)
+ reifyTrace("reification = ")(untyped)
}
untyped
diff --git a/src/compiler/scala/reflect/reify/States.scala b/src/compiler/scala/reflect/reify/States.scala
new file mode 100644
index 0000000000..97b703d32b
--- /dev/null
+++ b/src/compiler/scala/reflect/reify/States.scala
@@ -0,0 +1,65 @@
+package scala.reflect.reify
+
+trait States {
+ self: Reifier =>
+
+ import global._
+ import definitions._
+
+ /** Encapsulates reifier state
+ *
+ * When untangling reifier symbol tables from the reifier itself,
+ * I discovered that encoding of a symbol table (e.g. producing corresponding reificode)
+ * might cause subsequent reification (e.g. when filling in signatures and annotations for syms).
+ *
+ * This is a mess in the face of nested reifications, splices and inlining of thereof,
+ * so I made `SymbolTable` immutable, which brought a significant amount of sanity.
+ *
+ * However that wasn't enough. Sure, symbol table became immutable, but the reifier still needed
+ * to mutate its `symtab` field during reification. This caused nasty desyncs between the table being encoded
+ * and the table of the underlying reifier, so I decided to encapsulate the entire state here,
+ * so that encoding can backup the state before it starts and restore it after it completes.
+ */
+ val state = new State
+
+ // todo. rewrite the reifier so that we don't need mutable state anymore
+ // to aid you with that I've already removed all the setters from the reifier
+ // so all the places that involve mutations are forced to do that by explicitly mentioning `state`
+ class State {
+ var symtab = SymbolTable()
+ var reifyTreeSymbols = false
+ var reifyTreeTypes = false
+ private var _reificationIsConcrete = true
+ def reificationIsConcrete: Boolean = _reificationIsConcrete
+ def reificationIsConcrete_=(value: Boolean): Unit = {
+ _reificationIsConcrete = value
+ if (!value && concrete) {
+ assert(current.isInstanceOf[Type], current)
+ val offender = current.asInstanceOf[Type]
+ CannotReifyConcreteTypeTagHavingUnresolvedTypeParameters(offender)
+ }
+ }
+ var reifyStack = reifee :: Nil
+ var localSymbols = Map[Symbol, Int]()
+
+ def backup: State = {
+ val backup = new State
+ backup.symtab = this.symtab
+ backup.reifyTreeSymbols = this.reifyTreeSymbols
+ backup.reifyTreeTypes = this.reifyTreeTypes
+ backup._reificationIsConcrete = this._reificationIsConcrete
+ backup.reifyStack = this.reifyStack
+ backup.localSymbols = this.localSymbols
+ backup
+ }
+
+ def restore(backup: State): Unit = {
+ this.symtab = backup.symtab
+ this.reifyTreeSymbols = backup.reifyTreeSymbols
+ this.reifyTreeTypes = backup.reifyTreeTypes
+ this._reificationIsConcrete = backup._reificationIsConcrete
+ this.reifyStack = backup.reifyStack
+ this.localSymbols = backup.localSymbols
+ }
+ }
+}
diff --git a/src/compiler/scala/reflect/reify/Taggers.scala b/src/compiler/scala/reflect/reify/Taggers.scala
index d8da7e74ff..cf0a749e41 100644
--- a/src/compiler/scala/reflect/reify/Taggers.scala
+++ b/src/compiler/scala/reflect/reify/Taggers.scala
@@ -8,38 +8,57 @@ abstract class Taggers {
import c.universe._
import definitions._
+ import treeBuild._
val coreTags = Map(
- ByteClass.asType -> newTermName("Byte"),
- ShortClass.asType -> newTermName("Short"),
- CharClass.asType -> newTermName("Char"),
- IntClass.asType -> newTermName("Int"),
- LongClass.asType -> newTermName("Long"),
- FloatClass.asType -> newTermName("Float"),
- DoubleClass.asType -> newTermName("Double"),
- BooleanClass.asType -> newTermName("Boolean"),
- UnitClass.asType -> newTermName("Unit"),
- AnyClass.asType -> newTermName("Any"),
- ObjectClass.asType -> newTermName("Object"),
- NothingClass.asType -> newTermName("Nothing"),
- NullClass.asType -> newTermName("Null"),
- StringClass.asType -> newTermName("String"))
+ ByteClass.asType -> nme.Byte,
+ ShortClass.asType -> nme.Short,
+ CharClass.asType -> nme.Char,
+ IntClass.asType -> nme.Int,
+ LongClass.asType -> nme.Long,
+ FloatClass.asType -> nme.Float,
+ DoubleClass.asType -> nme.Double,
+ BooleanClass.asType -> nme.Boolean,
+ UnitClass.asType -> nme.Unit,
+ AnyClass.asType -> nme.Any,
+ ObjectClass.asType -> nme.Object,
+ NothingClass.asType -> nme.Nothing,
+ NullClass.asType -> nme.Null,
+ StringClass.asType -> nme.String)
// todo. the following two methods won't be necessary once we implement implicit macro generators for tags
def materializeArrayTag(prefix: Tree, tpe: Type): Tree =
materializeClassTag(prefix, tpe)
- def materializeClassTag(prefix: Tree, tpe: Type): Tree =
- materializeTag(prefix, tpe, ClassTagModule, {
- val runtimeClass = c.reifyRuntimeClass(tpe, concrete = true)
- val factory = TypeApply(Select(Ident(ClassTagModule), "apply"), List(TypeTree(tpe)))
- Apply(factory, List(runtimeClass))
+ def materializeClassTag(prefix: Tree, tpe: Type): Tree = {
+ val tagModule = ClassTagModule
+ materializeTag(prefix, tpe, tagModule, {
+ val erasure = c.reifyRuntimeClass(tpe, concrete = true)
+ val factory = TypeApply(Select(Ident(tagModule), nme.apply), List(TypeTree(tpe)))
+ Apply(factory, List(erasure))
})
+ }
- def materializeTypeTag(prefix: Tree, tpe: Type, concrete: Boolean): Tree = {
- val tagModule = if (concrete) ConcreteTypeTagModule else TypeTagModule
- materializeTag(prefix, tpe, tagModule, c.reifyType(prefix, tpe, dontSpliceAtTopLevel = true, concrete = concrete))
+ def materializeTypeTag(universe: Tree, mirror: Tree, tpe: Type, concrete: Boolean): Tree = {
+ if (universe.symbol == MacroContextUniverse && mirror == EmptyTree) {
+ import scala.reflect.makro.runtime.ContextReifiers
+ import language.implicitConversions
+ implicit def context2contextreifiers(c0: Context) : ContextReifiers { val c: c0.type } = new { val c: c0.type = c0 } with ContextReifiers
+ val Select(prefix, _) = universe
+ c.materializeTypeTagForMacroContext(prefix, tpe, concrete)
+ } else {
+ val tagType = if (concrete) ConcreteTypeTagClass else TypeTagClass
+ val unaffiliatedTagTpe = TypeRef(BaseUniverseClass.asTypeConstructor, tagType, List(tpe))
+ val unaffiliatedTag = c.inferImplicitValue(unaffiliatedTagTpe, silent = true, withMacrosDisabled = true)
+ unaffiliatedTag match {
+ case success if !success.isEmpty =>
+ Apply(Select(success, nme.in), List(mirror orElse mkDefaultMirrorRef(c.universe)(universe, c.callsiteTyper)))
+ case _ =>
+ val tagModule = if (concrete) ConcreteTypeTagModule else TypeTagModule
+ materializeTag(universe, tpe, tagModule, c.reifyType(universe, mirror, tpe, concrete = concrete))
+ }
+ }
}
private def materializeTag(prefix: Tree, tpe: Type, tagModule: Symbol, materializer: => Tree): Tree = {
@@ -55,8 +74,8 @@ abstract class Taggers {
catch { case terr @ c.TypeError(pos, msg) => failTag(result, terr) }
}
- def materializeExpr(prefix: Tree, expr: Tree): Tree = {
- val result = translatingReificationErrors(c.reifyTree(prefix, expr))
+ def materializeExpr(universe: Tree, mirror: Tree, expr: Tree): Tree = {
+ val result = translatingReificationErrors(c.reifyTree(universe, mirror, expr))
try c.typeCheck(result)
catch { case terr @ c.TypeError(pos, msg) => failExpr(result, terr) }
}
diff --git a/src/compiler/scala/reflect/reify/codegen/AnnotationInfos.scala b/src/compiler/scala/reflect/reify/codegen/GenAnnotationInfos.scala
index 1d218317dc..5f4296f54f 100644
--- a/src/compiler/scala/reflect/reify/codegen/AnnotationInfos.scala
+++ b/src/compiler/scala/reflect/reify/codegen/GenAnnotationInfos.scala
@@ -1,12 +1,11 @@
package scala.reflect.reify
package codegen
-trait AnnotationInfos {
+trait GenAnnotationInfos {
self: Reifier =>
- import mirror._
+ import global._
import definitions._
- import treeInfo._
// usually annotations are reified as their originals from Modifiers
// however, when reifying free and tough types, we're forced to reify annotation infos as is
@@ -26,8 +25,8 @@ trait AnnotationInfos {
// reflective typechecker will fill in missing symbols and types, right?
// A: actually, no. annotation ASTs live inside AnnotatedTypes,
// and insides of the types is the place where typechecker doesn't look.
- reifyTreeSymbols = true
- reifyTreeTypes = true
+ state.reifyTreeSymbols = true
+ state.reifyTreeTypes = true
// todo. every AnnotationInfo is an island, entire of itself
// no regular Traverser or Transformer can reach it
@@ -35,8 +34,8 @@ trait AnnotationInfos {
// e.g. to apply reshaping or to check metalevels
reify(arg)
} finally {
- reifyTreeSymbols = saved1
- reifyTreeTypes = saved2
+ state.reifyTreeSymbols = saved1
+ state.reifyTreeTypes = saved2
}
}
diff --git a/src/compiler/scala/reflect/reify/codegen/Names.scala b/src/compiler/scala/reflect/reify/codegen/GenNames.scala
index 589f6355d0..4abf88f475 100644
--- a/src/compiler/scala/reflect/reify/codegen/Names.scala
+++ b/src/compiler/scala/reflect/reify/codegen/GenNames.scala
@@ -1,12 +1,11 @@
package scala.reflect.reify
package codegen
-trait Names {
+trait GenNames {
self: Reifier =>
- import mirror._
+ import global._
import definitions._
- import treeInfo._
def reifyName(name: Name) = {
val factory = if (name.isTypeName) nme.nmeNewTypeName else nme.nmeNewTermName
diff --git a/src/compiler/scala/reflect/reify/codegen/Positions.scala b/src/compiler/scala/reflect/reify/codegen/GenPositions.scala
index ac9195ef31..8c5db04454 100644
--- a/src/compiler/scala/reflect/reify/codegen/Positions.scala
+++ b/src/compiler/scala/reflect/reify/codegen/GenPositions.scala
@@ -1,12 +1,11 @@
package scala.reflect.reify
package codegen
-trait Positions {
+trait GenPositions {
self: Reifier =>
- import mirror._
+ import global._
import definitions._
- import treeInfo._
// we do not reify positions because this inflates resulting trees, but doesn't buy as anything
// where would one use positions? right, in error messages
diff --git a/src/compiler/scala/reflect/reify/codegen/GenSymbols.scala b/src/compiler/scala/reflect/reify/codegen/GenSymbols.scala
new file mode 100644
index 0000000000..3a98d308a7
--- /dev/null
+++ b/src/compiler/scala/reflect/reify/codegen/GenSymbols.scala
@@ -0,0 +1,109 @@
+package scala.reflect.reify
+package codegen
+
+trait GenSymbols {
+ self: Reifier =>
+
+ import global._
+ import definitions._
+
+ /** Symbol table of the reifee.
+ *
+ * Keeps track of auxiliary symbols that are necessary for this reification session.
+ * These include:
+ * 1) Free vars (terms, types and existentials),
+ * 2) Non-locatable symbols (sometimes, e.g. for RefinedTypes, we need to reify these; to do that we create their local copies in the reificode)
+ * 3) Non-locatable symbols that are referred by #1, #2 and #3
+ *
+ * Exposes three main methods:
+ * 1) `syms` that lists symbols belonging to the table,
+ * 2) `symXXX` family of methods that provide information about the symbols in the table,
+ * 3) `encode` that renders the table into a list of trees (recursively populating #3 and setting up initialization code for #1, #2 and #3)
+ */
+ def symtab: SymbolTable = state.symtab
+
+ /** Reify a reference to a symbol */
+ def reifySymRef(sym0: Symbol): Tree = {
+ assert(sym0 != null, "sym is null")
+ val sym = sym0.dealias
+
+ if (sym == NoSymbol)
+ mirrorSelect(nme.NoSymbol)
+ else if (sym.isRootPackage)
+ mirrorMirrorSelect(nme.RootPackage)
+ else if (sym.isRoot)
+ mirrorMirrorSelect(nme.RootClass)
+ else if (sym.isEmptyPackage)
+ mirrorMirrorSelect(nme.EmptyPackage)
+ else if (sym.isEmptyPackageClass)
+ mirrorMirrorSelect(nme.EmptyPackageClass)
+ else if (sym.isModuleClass)
+ Select(Select(reify(sym.sourceModule), nme.asModuleSymbol), nme.moduleClass)
+ else if (sym.isLocatable) {
+ // [Eugene] am I doing this right?
+// if (sym.isStaticOwner) { // no good for us, because it returns false for packages
+ if (sym.isStatic && (sym.isClass || sym.isModule)) {
+ val resolver = if (sym.isType) nme.staticClass else nme.staticModule
+ mirrorMirrorCall(resolver, reify(sym.fullName))
+ } else {
+ if (reifyDebug) println("Locatable: %s (%s) owned by %s (%s) at %s".format(sym, sym.accurateKindString, sym.owner, sym.owner.accurateKindString, sym.owner.fullNameString))
+ val rowner = reify(sym.owner)
+ val rname = reify(sym.name.toString)
+ if (sym.isType)
+ mirrorBuildCall(nme.selectType, rowner, rname)
+ else if (sym.isMethod && sym.owner.isClass && sym.owner.info.decl(sym.name).isOverloaded) {
+ val index = sym.owner.info.decl(sym.name).alternatives indexOf sym
+ assert(index >= 0, sym)
+ mirrorBuildCall(nme.selectOverloadedMethod, rowner, rname, reify(index))
+ } else
+ mirrorBuildCall(nme.selectTerm, rowner, rname)
+ }
+ } else {
+ // todo. make sure that free methods and free local defs work correctly
+ if (sym.isTerm) reifyFreeTerm(sym, Ident(sym))
+ else reifyFreeType(sym, Ident(sym))
+ }
+ }
+
+ def reifyFreeTerm(sym: Symbol, value: Tree): Tree =
+ reifyIntoSymtab(sym) {
+ if (reifyDebug) println("Free term" + (if (sym.isCapturedVariable) " (captured)" else "") + ": " + sym + "(" + sym.accurateKindString + ")")
+ var name = newTermName(nme.REIFY_FREE_PREFIX + sym.name)
+ if (sym.isType) name = name.append(nme.REIFY_FREE_THIS_SUFFIX)
+ if (sym.isCapturedVariable) {
+ assert(value.isInstanceOf[Ident], showRaw(value))
+ val capturedTpe = capturedVariableType(sym)
+ val capturedValue = referenceCapturedVariable(sym)
+ (name, mirrorBuildCall(nme.newFreeTerm, reify(sym.name.toString), reify(capturedTpe), capturedValue, mirrorBuildCall(nme.flagsFromBits, reify(sym.flags)), reify(origin(sym))))
+ } else {
+ (name, mirrorBuildCall(nme.newFreeTerm, reify(sym.name.toString), reify(sym.tpe), value, mirrorBuildCall(nme.flagsFromBits, reify(sym.flags)), reify(origin(sym))))
+ }
+ }
+
+ def reifyFreeType(sym: Symbol, value: Tree): Tree =
+ reifyIntoSymtab(sym) {
+ if (reifyDebug) println("Free type: %s (%s)".format(sym, sym.accurateKindString))
+ var name = newTermName(nme.REIFY_FREE_PREFIX + sym.name)
+ val phantomTypeTag = Apply(TypeApply(Select(Ident(nme.UNIVERSE_SHORT), nme.TypeTag), List(value)), List(Literal(Constant(null)), Literal(Constant(null))))
+ val flavor = if (sym.isExistential) nme.newFreeExistential else nme.newFreeType
+ (name, mirrorBuildCall(flavor, reify(sym.name.toString), reify(sym.info), phantomTypeTag, mirrorBuildCall(nme.flagsFromBits, reify(sym.flags)), reify(origin(sym))))
+ }
+
+ def reifySymDef(sym: Symbol): Tree =
+ reifyIntoSymtab(sym) {
+ if (reifyDebug) println("Sym def: %s (%s)".format(sym, sym.accurateKindString))
+ assert(!sym.isLocatable, sym) // if this assertion fires, then tough type reification needs to be rethought
+ sym.owner.ownersIterator find (!_.isLocatable) foreach reifySymDef
+ var name = newTermName(nme.REIFY_SYMDEF_PREFIX + sym.name)
+ (name, mirrorBuildCall(nme.newNestedSymbol, reify(sym.owner), reify(sym.name), reify(sym.pos), mirrorBuildCall(nme.flagsFromBits, reify(sym.flags)), reify(sym.isClass)))
+ }
+
+ private def reifyIntoSymtab(sym: Symbol)(reificode: => (TermName, Tree)): Tree ={
+ def fromSymtab = symtab symRef sym
+ if (fromSymtab == EmptyTree) {
+ val reification = reificode
+ state.symtab += (sym, reification._1, reification._2)
+ }
+ fromSymtab
+ }
+}
diff --git a/src/compiler/scala/reflect/reify/codegen/Trees.scala b/src/compiler/scala/reflect/reify/codegen/GenTrees.scala
index a4543d84c1..b97bf6b0cd 100644
--- a/src/compiler/scala/reflect/reify/codegen/Trees.scala
+++ b/src/compiler/scala/reflect/reify/codegen/GenTrees.scala
@@ -1,17 +1,17 @@
package scala.reflect.reify
package codegen
-trait Trees {
+trait GenTrees {
self: Reifier =>
- import mirror._
+ import global._
import definitions._
- import treeInfo._
// unfortunately, these are necessary to reify AnnotatedTypes
- // I'd gladly got rid of them, but I don't fancy making a metaprogramming API that doesn't work with annotated types
- var reifyTreeSymbols = false
- var reifyTreeTypes = false
+ // I'd gladly get rid of them, but I don't fancy making a metaprogramming API that doesn't work with annotated types
+ // luckily for our sanity, these vars are mutated only within a very restricted code execution path
+ def reifyTreeSymbols: Boolean = state.reifyTreeSymbols
+ def reifyTreeTypes: Boolean = state.reifyTreeTypes
/**
* Reify a tree.
@@ -42,10 +42,10 @@ trait Trees {
// the second prototype reified external types, but avoided reifying local ones => this created an ugly irregularity
// current approach is uniform and compact
var rtree = tree match {
- case mirror.EmptyTree =>
+ case global.EmptyTree =>
reifyMirrorObject(EmptyTree)
- case mirror.emptyValDef =>
- mirrorSelect(nme.emptyValDef)
+ case global.emptyValDef =>
+ mirrorBuildSelect(nme.emptyValDef)
case FreeDef(_, _, _, _, _) =>
reifyNestedFreeDef(tree)
case FreeRef(_, _) =>
@@ -54,31 +54,7 @@ trait Trees {
reifyBoundTerm(tree)
case BoundType(tree) =>
reifyBoundType(tree)
- case NestedExpr(_, _, _) =>
- reifyNestedExpr(tree)
case Literal(const @ Constant(_)) =>
- // [Eugene] was necessary when we reified erasures as normalized tycons
- // now, when we do existentialAbstraction on normalizations, everything works great
- // todo. find an explanation
-// if (const.tag == ClazzTag) {
-//// def preprocess(tpe: Type): Type = tpe.typeSymbol match {
-//// case ArrayClass => appliedType(ArrayClass, preprocess(tpe.typeArgs.head))
-//// case _ => tpe.typeConstructor
-//// }
-//// val tpe = preprocess(const.typeValue)
-// val tpe = const.typeValue
-// var reified = reify(tpe)
-// reified = mirrorCall(nme.Literal, mirrorCall(nme.Constant, reified))
-//// val skolems = ClassClass.typeParams map (_ => newTypeName(typer.context.unit.fresh.newName("_$")))
-//// var existential = mirrorCall(nme.AppliedTypeTree, mirrorCall(nme.TypeTree, reify(ClassClass.typeConstructor)), mkList(skolems map (skolem => mirrorCall(nme.Ident, reify(skolem)))))
-//// existential = mirrorCall(nme.ExistentialTypeTree, existential, reify(skolems map (skolem => TypeDef(Modifiers(Set(Modifier.deferred: Modifier)), skolem, Nil, TypeBoundsTree(Ident(NothingClass) setType NothingClass.tpe, Ident(AnyClass) setType AnyClass.tpe)))))
-//// reified = mirrorCall(nme.TypeApply, mirrorCall(nme.Select, reified, reify(nme.asInstanceOf_)), mkList(List(existential)))
-// // why is this required??
-//// reified = mirrorCall(nme.TypeApply, mirrorCall(nme.Select, reified, reify(nme.asInstanceOf_)), mkList(List(mirrorCall(nme.TypeTree, reify(appliedType(ClassClass.tpe, List(AnyClass.tpe)))))))
-// reified
-// } else {
-// mirrorCall(nme.Literal, reifyProduct(const))
-// }
mirrorCall(nme.Literal, reifyProduct(const))
case Import(expr, selectors) =>
mirrorCall(nme.Import, reify(expr), mkList(selectors map reifyProduct))
@@ -90,51 +66,47 @@ trait Trees {
// however, reification of AnnotatedTypes is special. see ``reifyType'' to find out why.
if (reifyTreeSymbols && tree.hasSymbol) {
if (reifyDebug) println("reifying symbol %s for tree %s".format(tree.symbol, tree))
- rtree = Apply(Select(rtree, nme.setSymbol), List(reify(tree.symbol)))
+ rtree = mirrorBuildCall(nme.setSymbol, rtree, reify(tree.symbol))
}
if (reifyTreeTypes && tree.tpe != null) {
if (reifyDebug) println("reifying type %s for tree %s".format(tree.tpe, tree))
- rtree = Apply(Select(rtree, nme.setType), List(reify(tree.tpe)))
+ rtree = mirrorBuildCall(nme.setType, rtree, reify(tree.tpe))
}
rtree
}
- def reifyModifiers(m: mirror.Modifiers) =
- mirrorCall("modifiersFromInternalFlags", reify(m.flags), reify(m.privateWithin), reify(m.annotations))
+ def reifyModifiers(m: global.Modifiers) =
+ mirrorFactoryCall(nme.Modifiers, mirrorBuildCall(nme.flagsFromBits, reify(m.flags)), reify(m.privateWithin), reify(m.annotations))
private def spliceTree(tree: Tree): Tree = {
tree match {
case TreeSplice(splicee) =>
- if (reifyDebug) println("splicing eval " + tree)
+ if (reifyDebug) println("splicing " + tree)
// see ``Metalevels'' for more info about metalevel breaches
// and about how we deal with splices that contain them
- if (splicee exists (sub => sub.hasSymbol && sub.symbol != NoSymbol && sub.symbol.metalevel > 0)) {
- if (reifyDebug) println("splicing has failed: cannot splice when facing a metalevel breach")
- EmptyTree
+ val isMetalevelBreach = splicee exists (sub => sub.hasSymbol && sub.symbol != NoSymbol && sub.symbol.metalevel > 0)
+ val isRuntimeEval = splicee exists (sub => sub.hasSymbol && sub.symbol == ExprSplice)
+ if (isMetalevelBreach || isRuntimeEval) {
+ // we used to convert dynamic splices into runtime evals transparently, but we no longer do that
+ // why? see comments in ``Metalevels''
+ // if (reifyDebug) println("splicing has failed: cannot splice when facing a metalevel breach")
+ // EmptyTree
+ CannotReifyRuntimeSplice(tree)
} else {
if (reifyDebug) println("splicing has succeeded")
- var splice = Select(splicee, nme.tree)
- splice match {
- case InlinedTreeSplice(_, inlinedSymbolTable, tree, _) =>
+ splicee match {
+ // we intentionally don't care about the prefix (the first underscore in the `RefiedTree` pattern match)
+ case ReifiedTree(_, _, inlinedSymtab, rtree, _, _, _) =>
if (reifyDebug) println("inlining the splicee")
// all free vars local to the enclosing reifee should've already been inlined by ``Metalevels''
- inlinedSymbolTable collect { case freedef @ FreeDef(_, _, binding, _, _) if binding.symbol.isLocalToReifee => assert(false, freedef) }
- symbolTable ++= inlinedSymbolTable
- tree
+ inlinedSymtab.syms foreach (sym => if (sym.isLocalToReifee) assert(false, inlinedSymtab.symDef(sym)))
+ state.symtab ++= inlinedSymtab
+ rtree
case tree =>
- // we need to preserve types of exprs, because oftentimes they cannot be inferred later
- // this circumvents regular reification scheme, therefore we go the extra mile here
- new Transformer {
- override def transform(tree: Tree) = super.transform(tree match {
- case NestedExpr(factory, tree, typetag) =>
- val typedFactory = TypeApply(factory, List(TypeTree(typetag.tpe.typeArgs(0))))
- Apply(Apply(typedFactory, List(tree)), List(typetag))
- case _ =>
- tree
- })
- }.transform(tree)
+ val migrated = Apply(Select(splicee, nme.in), List(Ident(nme.MIRROR_SHORT)))
+ Select(migrated, nme.tree)
}
}
case _ =>
@@ -142,6 +114,9 @@ trait Trees {
}
}
+ // unlike in `reifyBoundType` we can skip checking for `tpe` being local or not local w.r.t the reifee
+ // a single check for a symbol of the bound term should be enough
+ // that's because only Idents and Thises can be bound terms, and they cannot host complex types
private def reifyBoundTerm(tree: Tree): Tree = tree match {
case tree @ This(_) if tree.symbol == NoSymbol =>
throw new Error("unexpected: bound term that doesn't have a symbol: " + showRaw(tree))
@@ -149,10 +124,10 @@ trait Trees {
val sym = tree.symbol
if (reifyDebug) println("This for %s, reified as freeVar".format(sym))
if (reifyDebug) println("Free: " + sym)
- mirrorCall(nme.Ident, reifyFreeTerm(sym, This(sym)))
+ mirrorBuildCall(nme.Ident, reifyFreeTerm(sym, This(sym)))
case tree @ This(_) if !tree.symbol.isLocalToReifee =>
if (reifyDebug) println("This for %s, reified as This".format(tree.symbol))
- mirrorCall(nme.This, reify(tree.symbol))
+ mirrorBuildCall(nme.This, reify(tree.symbol))
case tree @ This(_) if tree.symbol.isLocalToReifee =>
mirrorCall(nme.This, reify(tree.qual))
case tree @ Ident(_) if tree.symbol == NoSymbol =>
@@ -163,9 +138,9 @@ trait Trees {
case tree @ Ident(_) if !tree.symbol.isLocalToReifee =>
if (tree.symbol.isVariable && tree.symbol.owner.isTerm) {
captureVariable(tree.symbol) // Note order dependency: captureVariable needs to come before reification here.
- mirrorCall(nme.Select, mirrorCall(nme.Ident, reify(tree.symbol)), reify(nme.elem))
+ mirrorCall(nme.Select, mirrorBuildCall(nme.Ident, reify(tree.symbol)), reify(nme.elem))
} else {
- mirrorCall(nme.Ident, reify(tree.symbol))
+ mirrorBuildCall(nme.Ident, reify(tree.symbol))
}
case tree @ Ident(_) if tree.symbol.isLocalToReifee =>
mirrorCall(nme.Ident, reify(tree.name))
@@ -178,7 +153,12 @@ trait Trees {
if (tree.tpe == null)
throw new Error("unexpected: bound type that doesn't have a tpe: " + showRaw(tree))
- if (tree.symbol.isLocalToReifee)
+ // if a symbol or a type of the scrutinee are local to reifee
+ // (e.g. point to a locally declared class or to a path-dependent thingie that depends on a local variable)
+ // then we can reify the scrutinee as a symless AST and that will definitely be hygienic
+ // why? because then typechecking of a scrutinee doesn't depend on the environment external to the quasiquote
+ // otherwise we need to reify the corresponding type
+ if (tree.symbol.isLocalToReifee || tree.tpe.isLocalToReifee)
reifyProduct(tree)
else {
val sym0 = tree.symbol
@@ -191,7 +171,7 @@ trait Trees {
val spliced = spliceType(tpe)
if (spliced == EmptyTree) {
if (reifyDebug) println("splicing failed: reify as is")
- mirrorCall(nme.TypeTree, reify(tpe))
+ mirrorBuildCall(nme.TypeTree, reify(tpe))
} else {
spliced match {
case TypeRefToFreeType(freeType) =>
@@ -199,16 +179,16 @@ trait Trees {
Ident(freeType)
case _ =>
if (reifyDebug) println("splicing succeeded: " + spliced)
- mirrorCall(nme.TypeTree, spliced)
+ mirrorBuildCall(nme.TypeTree, spliced)
}
}
} else {
if (sym.isLocatable) {
if (reifyDebug) println("tpe is locatable: reify as Ident(%s)".format(sym))
- mirrorCall(nme.Ident, reify(sym))
+ mirrorBuildCall(nme.Ident, reify(sym))
} else {
if (reifyDebug) println("tpe is an alias, but not a locatable: reify as TypeTree(%s)".format(tpe))
- mirrorCall(nme.TypeTree, reify(tpe))
+ mirrorBuildCall(nme.TypeTree, reify(tpe))
}
}
}
@@ -231,25 +211,8 @@ trait Trees {
reifyProduct(tree)
}
- private def reifyNestedFreeRef(tree: Tree): Tree = tree match {
- case Apply(Select(mrRef @ Ident(_), ident), List(Ident(name: TermName))) if ident == nme.Ident && name.startsWith(nme.MIRROR_FREE_PREFIX) =>
- if (reifyDebug) println("nested free ref: %s".format(showRaw(tree)))
- reifyProduct(tree)
- case _ =>
- throw new Error("internal error: %s (%s, %s) is not supported".format(tree, tree.productPrefix, tree.getClass))
- }
-
- private def reifyNestedExpr(tree: Tree): Tree = tree match {
- case NestedExpr(factory, tree, typetag) =>
- // we need to preserve types of exprs, because oftentimes they cannot be inferred later
- // this circumvents regular reification scheme, therefore we go through this crazy dance
- if (reifyDebug) println("nested expr: %s".format(showRaw(tree)))
- val rtype = mirrorCall(nme.TypeTree, reify(typetag.tpe.typeArgs(0)))
- val rfactory = mirrorCall(nme.TypeApply, reify(factory), mkList(List(rtype)))
- val rexpr = mirrorCall(nme.Apply, rfactory, reify(List(tree)))
- val rwrapped = mirrorCall(nme.Apply, rexpr, reify(List(typetag)))
- rwrapped
- case _ =>
- throw new Error("internal error: %s (%s, %s) is not supported".format(tree, tree.productPrefix, tree.getClass))
+ private def reifyNestedFreeRef(tree: Tree): Tree = {
+ if (reifyDebug) println("nested free ref: %s".format(showRaw(tree)))
+ reifyProduct(tree)
}
-} \ No newline at end of file
+}
diff --git a/src/compiler/scala/reflect/reify/codegen/GenTypes.scala b/src/compiler/scala/reflect/reify/codegen/GenTypes.scala
new file mode 100644
index 0000000000..25928651c8
--- /dev/null
+++ b/src/compiler/scala/reflect/reify/codegen/GenTypes.scala
@@ -0,0 +1,203 @@
+package scala.reflect.reify
+package codegen
+
+trait GenTypes {
+ self: Reifier =>
+
+ import global._
+ import definitions._
+
+ /**
+ * Reify a type.
+ * For internal use only, use ``reified'' instead.
+ */
+ def reifyType(tpe0: Type): Tree = {
+ assert(tpe0 != null, "tpe is null")
+ val tpe = tpe0.dealias
+
+ if (tpe.isErroneous)
+ CannotReifyErroneousReifee(tpe)
+ if (tpe.isLocalToReifee)
+ CannotReifyType(tpe)
+
+ // this is a very special case. see the comments below for more info.
+ if (isSemiConcreteTypeMember(tpe))
+ return reifySemiConcreteTypeMember(tpe)
+
+ // [Eugene] how do I check that the substitution is legal w.r.t tpe.info?
+ val spliced = spliceType(tpe)
+ if (spliced != EmptyTree)
+ return spliced
+
+ val tsym = tpe.typeSymbol
+ if (tsym.isClass && tpe == tsym.typeConstructor && tsym.isStatic)
+ Select(Select(reify(tpe.typeSymbol), nme.asTypeSymbol), nme.asTypeConstructor)
+ else tpe match {
+ case tpe @ NoType =>
+ reifyMirrorObject(tpe)
+ case tpe @ NoPrefix =>
+ reifyMirrorObject(tpe)
+ case tpe @ ThisType(root) if root.isRoot =>
+ mirrorBuildCall(nme.thisPrefix, mirrorMirrorSelect(nme.RootClass))
+ case tpe @ ThisType(empty) if empty.isEmptyPackageClass =>
+ mirrorBuildCall(nme.thisPrefix, mirrorMirrorSelect(nme.EmptyPackageClass))
+ case tpe @ ThisType(clazz) if clazz.isModuleClass && clazz.isStatic =>
+ // [Eugene++ to Martin] makes sense?
+ val module = mirrorMirrorCall(nme.staticModule, reify(clazz.fullName))
+ val moduleClass = Select(Select(module, nme.asModuleSymbol), nme.moduleClass)
+ mirrorFactoryCall(nme.ThisType, moduleClass)
+ case tpe @ ThisType(_) =>
+ reifyProduct(tpe)
+ case tpe @ SuperType(thistpe, supertpe) =>
+ reifyProduct(tpe)
+ case tpe @ SingleType(pre, sym) =>
+ reifyProduct(tpe)
+ case tpe @ ConstantType(value) =>
+ mirrorFactoryCall(nme.ConstantType, reifyProduct(value))
+ case tpe @ TypeRef(pre, sym, args) =>
+ reifyProduct(tpe)
+ case tpe @ TypeBounds(lo, hi) =>
+ reifyProduct(tpe)
+ case tpe @ NullaryMethodType(restpe) =>
+ reifyProduct(tpe)
+ case tpe @ AnnotatedType(anns, underlying, selfsym) =>
+ reifyAnnotatedType(tpe)
+ case _ =>
+ reifyToughType(tpe)
+ }
+ }
+
+ /** Keeps track of whether this reification contains abstract type parameters */
+ def reificationIsConcrete: Boolean = state.reificationIsConcrete
+
+ def spliceType(tpe: Type): Tree = {
+ // [Eugene] it seems that depending on the context the very same symbol can be either a spliceable tparam or a quantified existential. very weird!
+ val quantified = currentQuantified
+ if (tpe.isSpliceable && !(quantified contains tpe.typeSymbol)) {
+ if (reifyDebug) println("splicing " + tpe)
+
+ val tagFlavor = if (concrete) tpnme.ConcreteTypeTag.toString else tpnme.TypeTag.toString
+ val key = (tagFlavor, tpe.typeSymbol)
+ // if this fails, it might produce the dreaded "erroneous or inaccessible type" error
+ // to find out the whereabouts of the error run scalac with -Ydebug
+ if (reifyDebug) println("launching implicit search for %s.%s[%s]".format(universe, tagFlavor, tpe))
+ val result =
+ typer.resolveTypeTag(defaultErrorPosition, universe.tpe, tpe, concrete = concrete, allowMaterialization = false) match {
+ case failure if failure.isEmpty =>
+ if (reifyDebug) println("implicit search was fruitless")
+ if (reifyDebug) println("trying to splice as manifest")
+ val splicedAsManifest = spliceAsManifest(tpe)
+ if (splicedAsManifest.isEmpty) {
+ if (reifyDebug) println("no manifest in scope")
+ EmptyTree
+ } else {
+ if (reifyDebug) println("successfully spliced as manifest: " + splicedAsManifest)
+ splicedAsManifest
+ }
+ case success =>
+ if (reifyDebug) println("implicit search has produced a result: " + success)
+ state.reificationIsConcrete &= concrete || success.tpe <:< ConcreteTypeTagClass.asTypeConstructor
+ Select(Apply(Select(success, nme.in), List(Ident(nme.MIRROR_SHORT))), nme.tpe)
+ }
+ if (result != EmptyTree) return result
+ state.reificationIsConcrete = false
+ }
+
+ EmptyTree
+ }
+
+ private def spliceAsManifest(tpe: Type): Tree = {
+ val ManifestClass = rootMirror.staticClass("scala.reflect.Manifest")
+ val ManifestModule = rootMirror.staticModule("scala.reflect.Manifest")
+ def isSynthetic(manifest: Tree) = manifest exists (sub => sub.symbol != null && (sub.symbol == ManifestModule || sub.symbol.owner == ManifestModule))
+ def searchForManifest(typer: analyzer.Typer): Tree =
+ analyzer.inferImplicit(
+ EmptyTree,
+ appliedType(ManifestClass.asTypeConstructor, List(tpe)),
+ reportAmbiguous = false,
+ isView = false,
+ context = typer.context,
+ saveAmbiguousDivergent = false,
+ pos = defaultErrorPosition) match {
+ case success if !success.tree.isEmpty && !isSynthetic(success.tree) =>
+ val manifestInScope = success.tree
+ // todo. write a test for this
+ if (ReflectRuntimeUniverse == NoSymbol) CannotConvertManifestToTagWithoutScalaReflect(tpe, manifestInScope)
+ val cm = typer.typed(Ident(ReflectRuntimeCurrentMirror))
+ val tagTree = gen.mkMethodCall(ReflectRuntimeUniverse, nme.manifestToConcreteTypeTag, List(tpe), List(cm, manifestInScope))
+ Select(Apply(Select(tagTree, nme.in), List(Ident(nme.MIRROR_SHORT))), nme.tpe)
+ case _ =>
+ EmptyTree
+ }
+ val result = typer.silent(silentTyper => silentTyper.context.withMacrosDisabled(searchForManifest(silentTyper)))
+ result match {
+ case analyzer.SilentResultValue(result) => result
+ case analyzer.SilentTypeError(_) => EmptyTree
+ }
+ }
+
+ /** Reify a semi-concrete type member.
+ *
+ * This is a VERY special case to deal with stuff like `typeOf[ru.Type]`.
+ * In that case `Type`, which is an abstract type member of scala.reflect.api.Universe, is not a free type.
+ * Why? Because we know its prefix, and it unambiguously determines the type.
+ *
+ * Here is a different view on this question that supports this suggestion.
+ * Say, you reify a tree. Iff it doesn't contain free types, it can be successfully compiled and run.
+ * For example, if you reify `tpe.asInstanceOf[T]` taken from `def foo[T]`, then you won't be able to compile the result.
+ * Fair enough, you don't know the `T`, so the compiler will choke.
+ * This fact is captured by reification result having a free type T (this can be inspected by calling `tree.freeTypes`).
+ * Now imagine you reify the following tree: `tpe.asInstanceOf[ru.Type]`.
+ * To the contrast with the previous example, that's totally not a problem.
+ *
+ * Okay, so we figured out that `ru.Type` is not a free type.
+ * However, in our reification framework, this type would be treated a free type.
+ * Why? Because `tpe.isSpliceable` will return true.
+ * Hence we intervene and handle this situation in a special way.
+ *
+ * By the way, we cannot change the definition of `isSpliceable`, because class tags also depend on it.
+ * And, you know, class tags don't care whether we select a type member from a concrete instance or get it from scope (as with type parameters).
+ * The type itself still remains not concrete, in the sense that we don't know its erasure.
+ * I.e. we can compile the code that involves `ru.Type`, but we cannot serialize an instance of `ru.Type`.
+ */
+ private def reifySemiConcreteTypeMember(tpe: Type): Tree = tpe match {
+ case tpe @ TypeRef(pre @ SingleType(prepre, presym), sym, args) if sym.isAbstractType && !sym.isExistential =>
+ return mirrorFactoryCall(nme.TypeRef, reify(pre), mirrorBuildCall(nme.selectType, reify(sym.owner), reify(sym.name.toString)), reify(args))
+ }
+
+ /** Reify an annotated type, i.e. the one that makes us deal with AnnotationInfos */
+ private def reifyAnnotatedType(tpe: AnnotatedType): Tree = {
+ val AnnotatedType(anns, underlying, selfsym) = tpe
+ mirrorFactoryCall(nme.AnnotatedType, mkList(anns map reifyAnnotationInfo), reify(underlying), reify(selfsym))
+ }
+
+ /** Reify a tough type, i.e. the one that leads to creation of auxiliary symbols */
+ private def reifyToughType(tpe: Type): Tree = {
+ if (reifyDebug) println("tough type: %s (%s)".format(tpe, tpe.kind))
+
+ def reifyScope(scope: Scope): Tree = {
+ scope foreach reifySymDef
+ mirrorCall(nme.newScopeWith, scope.toList map reify: _*)
+ }
+
+ tpe match {
+ case tpe @ RefinedType(parents, decls) =>
+ reifySymDef(tpe.typeSymbol)
+ mirrorFactoryCall(tpe, reify(parents), reifyScope(decls), reify(tpe.typeSymbol))
+ case tpe @ ExistentialType(tparams, underlying) =>
+ tparams foreach reifySymDef
+ mirrorFactoryCall(tpe, reify(tparams), reify(underlying))
+ case tpe @ ClassInfoType(parents, decls, clazz) =>
+ reifySymDef(clazz)
+ mirrorFactoryCall(tpe, reify(parents), reifyScope(decls), reify(tpe.typeSymbol))
+ case tpe @ MethodType(params, restpe) =>
+ params foreach reifySymDef
+ mirrorFactoryCall(tpe, reify(params), reify(restpe))
+ case tpe @ PolyType(tparams, underlying) =>
+ tparams foreach reifySymDef
+ mirrorFactoryCall(tpe, reify(tparams), reify(underlying))
+ case _ =>
+ throw new Error("internal error: %s (%s) is not supported".format(tpe, tpe.kind))
+ }
+ }
+}
diff --git a/src/compiler/scala/reflect/reify/codegen/Util.scala b/src/compiler/scala/reflect/reify/codegen/GenUtils.scala
index bb369a1adb..e7fa858346 100644
--- a/src/compiler/scala/reflect/reify/codegen/Util.scala
+++ b/src/compiler/scala/reflect/reify/codegen/GenUtils.scala
@@ -1,18 +1,11 @@
package scala.reflect.reify
package codegen
-trait Util {
+trait GenUtils {
self: Reifier =>
- import mirror._
+ import global._
import definitions._
- import treeInfo._
-
- val reifyDebug = settings.Yreifydebug.value
- val reifyCopypaste = settings.Yreifycopypaste.value
- val reifyTrace = scala.tools.nsc.util.trace when reifyDebug
- object reifiedNodePrinters extends { val global: mirror.type = mirror } with tools.nsc.ast.NodePrinters with NodePrinters
- val reifiedNodeToString = reifiedNodePrinters.reifiedNodeToString
def reifyList(xs: List[Any]): Tree =
mkList(xs map reify)
@@ -39,12 +32,30 @@ trait Util {
Apply(termPath(fname), args.toList)
def mirrorSelect(name: String): Tree =
+ termPath(nme.UNIVERSE_PREFIX + name)
+
+ def mirrorBuildSelect(name: String): Tree =
+ termPath(nme.UNIVERSE_BUILD_PREFIX + name)
+
+ def mirrorMirrorSelect(name: String): Tree =
termPath(nme.MIRROR_PREFIX + name)
def mirrorCall(name: TermName, args: Tree*): Tree =
- call("" + (nme.MIRROR_PREFIX append name), args: _*)
+ call("" + (nme.UNIVERSE_PREFIX append name), args: _*)
def mirrorCall(name: String, args: Tree*): Tree =
+ call(nme.UNIVERSE_PREFIX + name, args: _*)
+
+ def mirrorBuildCall(name: TermName, args: Tree*): Tree =
+ call("" + (nme.UNIVERSE_BUILD_PREFIX append name), args: _*)
+
+ def mirrorBuildCall(name: String, args: Tree*): Tree =
+ call(nme.UNIVERSE_BUILD_PREFIX + name, args: _*)
+
+ def mirrorMirrorCall(name: TermName, args: Tree*): Tree =
+ call("" + (nme.MIRROR_PREFIX append name), args: _*)
+
+ def mirrorMirrorCall(name: String, args: Tree*): Tree =
call(nme.MIRROR_PREFIX + name, args: _*)
def mirrorFactoryCall(value: Product, args: Tree*): Tree =
@@ -93,6 +104,17 @@ trait Util {
tpe != null && (tpe exists isTough)
}
+ object TypedOrAnnotated {
+ def unapply(tree: Tree): Option[Tree] = tree match {
+ case ty @ Typed(_, _) =>
+ Some(ty)
+ case at @ Annotated(_, _) =>
+ Some(at)
+ case _ =>
+ None
+ }
+ }
+
def isAnnotated(tpe: Type) = {
def isAnnotated(tpe: Type) = tpe match {
case _: AnnotatedType => true
@@ -102,6 +124,17 @@ trait Util {
tpe != null && (tpe exists isAnnotated)
}
+ def isSemiConcreteTypeMember(tpe: Type) = tpe match {
+ case TypeRef(SingleType(_, _), sym, _) if sym.isAbstractType && !sym.isExistential => true
+ case _ => false
+ }
+
+ def isCrossStageTypeBearer(tree: Tree): Boolean = tree match {
+ case TypeApply(hk, _) => isCrossStageTypeBearer(hk)
+ case Select(sym @ Select(_, ctor), nme.apply) if ctor == nme.TypeTag || ctor == nme.ConcreteTypeTag || ctor == nme.Expr => true
+ case _ => false
+ }
+
def origin(sym: Symbol) = {
var origin = ""
if (sym.owner != NoSymbol) origin += "defined by %s".format(sym.owner.name)
diff --git a/src/compiler/scala/reflect/reify/codegen/Symbols.scala b/src/compiler/scala/reflect/reify/codegen/Symbols.scala
deleted file mode 100644
index 5ab8a11efe..0000000000
--- a/src/compiler/scala/reflect/reify/codegen/Symbols.scala
+++ /dev/null
@@ -1,184 +0,0 @@
-package scala.reflect.reify
-package codegen
-
-trait Symbols {
- self: Reifier =>
-
- import mirror._
- import definitions._
- import treeInfo._
-
- /** Reify a reference to a symbol */
- def reifySymRef(sym0: Symbol): Tree = {
- assert(sym0 != null, "sym is null")
- val sym = sym0.dealias
-
- if (sym == NoSymbol)
- mirrorSelect(nme.NoSymbol)
- else if (sym == rootMirror.RootPackage)
- Select(mirrorSelect(nme.definitions), nme.RootPackage)
- else if (sym == rootMirror.RootClass)
- Select(mirrorSelect(nme.definitions), nme.RootClass)
- else if (sym == rootMirror.EmptyPackage)
- Select(mirrorSelect(nme.definitions), nme.EmptyPackage)
- else if (sym == rootMirror.EmptyPackageClass)
- Select(mirrorSelect(nme.definitions), nme.EmptyPackageClass)
- else if (sym.isModuleClass)
- Select(reify(sym.sourceModule), nme.moduleClass)
- else if (sym.isLocatable) {
- // [Eugene] am I doing this right?
-// if (sym.isStaticOwner) { // no good for us, because it returns false for packages
- if (sym.isStatic && (sym.isClass || sym.isModule)) {
- val resolver = if (sym.isType) nme.staticClass else nme.staticModule
- mirrorCall(resolver, reify(sym.fullName))
- } else {
- if (reifyDebug) println("Locatable: %s (%s) owned by %s (%s) at %s".format(sym, sym.accurateKindString, sym.owner, sym.owner.accurateKindString, sym.owner.fullNameString))
- val rowner = reify(sym.owner)
- val rname = reify(sym.name.toString)
- if (sym.isType)
- mirrorCall(nme.selectType, rowner, rname)
- else if (sym.isMethod && sym.owner.isClass && sym.owner.info.decl(sym.name).isOverloaded) {
- val index = sym.owner.info.decl(sym.name).alternatives indexOf sym
- assert(index >= 0, sym)
- mirrorCall(nme.selectOverloadedMethod, rowner, rname, reify(index))
- } else
- mirrorCall(nme.selectTerm, rowner, rname)
- }
- } else {
- // todo. make sure that free methods and free local defs work correctly
- if (sym.isTerm) reifyFreeTerm(sym, Ident(sym))
- else reifyFreeType(sym, Ident(sym))
- }
- }
-
- def reifyFreeTerm(sym: Symbol, value: Tree): Tree =
- locallyReified get sym match {
- case Some(reified) =>
- reified
- case None =>
- if (reifyDebug) println("Free term" + (if (sym.isCapturedVariable) " (captured)" else "") + ": " + sym + "(" + sym.accurateKindString + ")")
- var name = newTermName(nme.MIRROR_FREE_PREFIX + sym.name)
- if (sym.isType) name = name.append(nme.MIRROR_FREE_THIS_SUFFIX)
- if (sym.isCapturedVariable) {
- assert(value.isInstanceOf[Ident], showRaw(value))
- val capturedTpe = capturedVariableType(sym)
- val capturedValue = referenceCapturedVariable(sym)
- locallyReify(sym, name, mirrorCall(nme.newFreeTerm, reify(sym.name.toString), reify(capturedTpe), capturedValue, reify(sym.flags), reify(origin(sym))))
- } else {
- locallyReify(sym, name, mirrorCall(nme.newFreeTerm, reify(sym.name.toString), reify(sym.tpe), value, reify(sym.flags), reify(origin(sym))))
- }
- }
-
- def reifyFreeType(sym: Symbol, value: Tree): Tree =
- locallyReified get sym match {
- case Some(reified) =>
- reified
- case None =>
- if (reifyDebug) println("Free type: %s (%s)".format(sym, sym.accurateKindString))
- var name = newTermName(nme.MIRROR_FREE_PREFIX + sym.name)
- val phantomTypeTag = Apply(TypeApply(Select(Ident(nme.MIRROR_SHORT), nme.TypeTag), List(value)), List(Literal(Constant(null)), Literal(Constant(null))))
- val flavor = if (sym.isExistential) nme.newFreeExistential else nme.newFreeType
- locallyReify(sym, name, mirrorCall(flavor, reify(sym.name.toString), reify(sym.info), phantomTypeTag, reify(sym.flags), reify(origin(sym))))
- }
-
- def reifySymDef(sym: Symbol): Tree =
- locallyReified get sym match {
- case Some(reified) =>
- reified
- case None =>
- if (reifyDebug) println("Sym def: %s (%s)".format(sym, sym.accurateKindString))
- assert(!sym.isLocatable, sym) // if this assertion fires, then tough type reification needs to be rethought
- sym.owner.ownersIterator find (!_.isLocatable) foreach reifySymDef
- var name = newTermName(nme.MIRROR_SYMDEF_PREFIX + sym.name)
- locallyReify(sym, name, Apply(Select(reify(sym.owner), nme.newNestedSymbol), List(reify(sym.name), reify(sym.pos), reify(sym.flags), reify(sym.isClass))))
- }
-
- // todo. very brittle abstraction, needs encapsulation
- import scala.collection.mutable._
- private val localReifications = ArrayBuffer[Tree]()
- private val locallyReified = Map[Symbol, Tree]()
- private var filledIn = false
- def symbolTable: List[Tree] = { fillInSymbolTable(); localReifications.toList }
- def symbolTable_=(newSymbolTable: List[Tree]): Unit = {
- localReifications.clear()
- locallyReified.clear()
- filledIn = false
- newSymbolTable foreach {
- case entry =>
- val att = entry.attachments.get[ReifyAttachment]
- att match {
- case Some(ReifyAttachment(sym)) =>
- // don't duplicate reified symbols when merging inlined reifee
- if (!(locallyReified contains sym)) {
- val ValDef(_, name, _, _) = entry
- localReifications += entry
- locallyReified(sym) = Ident(name)
- }
- case other =>
- // do nothing => symbol table fill-ins will be repopulated later
- }
- }
- }
-
- private def localName(name0: TermName): TermName = {
- var name = name0.toString
- name = name.replace(".type", "$type")
- name = name.replace(" ", "$")
- val fresh = typer.context.unit.fresh
- newTermName(fresh.newName(name))
- }
-
- private def locallyReify(sym: Symbol, name0: TermName, reificode: => Tree): Tree = {
- val reified = reificode
- val name = localName(name0)
- // todo. tried to declare a private class here to carry an attachment, but it's path-dependent
- // so got troubles with exchanging free variables between nested and enclosing quasiquotes
- // attaching just Symbol isn't good either, so we need to think of a principled solution
- val local = ValDef(NoMods, name, TypeTree(), reified) addAttachment ReifyAttachment(sym)
- localReifications += local
- filledIn = false
- locallyReified(sym) = Ident(name)
- locallyReified(sym)
- }
-
- /** Sets type signatures and annotations for locally reified symbols */
- private def fillInSymbolTable() = {
- if (!filledIn) {
- val fillIns = new ArrayBuffer[Tree]
- var i = 0
- while (i < localReifications.length) {
- // fillInSymbol might create new locallyReified symbols, that's why this is done iteratively
- val reified = localReifications(i)
- val att = reified.attachments.get[ReifyAttachment]
- att match {
- case Some(ReifyAttachment(sym)) => fillIns += fillInSymbol(sym)
- case other => // do nothing
- }
- i += 1
- }
-
- filledIn = true
- localReifications ++= fillIns.toList
- }
- }
-
- /** Generate code to add type and annotation info to a reified symbol */
- private def fillInSymbol(sym: Symbol): Tree = {
- if (reifyDebug) println("Filling in: %s (%s)".format(sym, sym.accurateKindString))
- val isFree = locallyReified(sym) match { case Ident(name) => name startsWith nme.MIRROR_FREE_PREFIX }
- if (isFree) {
- if (sym.annotations.isEmpty) EmptyTree
- else Apply(Select(locallyReified(sym), nme.setAnnotations), List(reify(sym.annotations)))
- } else {
- import scala.reflect.internal.Flags._
- if (sym hasFlag LOCKED) {
- // [Eugene] better to have a symbol without a type signature, than to crash with a CyclicReference
- EmptyTree
- } else {
- val rset = Apply(Select(locallyReified(sym), nme.setTypeSignature), List(reify(sym.info)))
- if (sym.annotations.isEmpty) rset
- else Apply(Select(rset, nme.setAnnotations), List(reify(sym.annotations)))
- }
- }
- }
-} \ No newline at end of file
diff --git a/src/compiler/scala/reflect/reify/codegen/Types.scala b/src/compiler/scala/reflect/reify/codegen/Types.scala
deleted file mode 100644
index a2b074c6b2..0000000000
--- a/src/compiler/scala/reflect/reify/codegen/Types.scala
+++ /dev/null
@@ -1,168 +0,0 @@
-package scala.reflect.reify
-package codegen
-
-trait Types {
- self: Reifier =>
-
- import mirror._
- import definitions._
- import treeInfo._
-
- /**
- * Reify a type.
- * For internal use only, use ``reified'' instead.
- */
- def reifyType(tpe0: Type): Tree = {
- assert(tpe0 != null, "tpe is null")
- val tpe = tpe0.dealias
-
- if (tpe.isErroneous)
- CannotReifyErroneousReifee(tpe)
- if (tpe.isLocalToReifee)
- CannotReifyType(tpe)
-
- // [Eugene] how do I check that the substitution is legal w.r.t tpe.info?
- val spliced = spliceType(tpe)
- if (spliced != EmptyTree)
- return spliced
-
- val tsym = tpe.typeSymbol
- if (tsym.isClass && tpe == tsym.typeConstructor && tsym.isStatic)
- Select(reify(tpe.typeSymbol), nme.asTypeConstructor)
- else tpe match {
- case tpe @ NoType =>
- reifyMirrorObject(tpe)
- case tpe @ NoPrefix =>
- reifyMirrorObject(tpe)
- case tpe @ ThisType(root) if root == RootClass =>
- mirrorSelect("definitions.RootClass.thisPrefix")
- case tpe @ ThisType(empty) if empty == EmptyPackageClass =>
- mirrorSelect("definitions.EmptyPackageClass.thisPrefix")
- case tpe @ ThisType(clazz) if clazz.isModuleClass && clazz.isStatic =>
- mirrorCall(nme.thisModuleType, reify(clazz.fullName))
- case tpe @ ThisType(_) =>
- reifyProduct(tpe)
- case tpe @ SuperType(thistpe, supertpe) =>
- reifyProduct(tpe)
- case tpe @ SingleType(pre, sym) =>
- reifyProduct(tpe)
- case tpe @ ConstantType(value) =>
- mirrorFactoryCall(nme.ConstantType, reifyProduct(value))
- case tpe @ TypeRef(pre, sym, args) =>
- reifyProduct(tpe)
- case tpe @ TypeBounds(lo, hi) =>
- reifyProduct(tpe)
- case tpe @ NullaryMethodType(restpe) =>
- reifyProduct(tpe)
- case tpe @ AnnotatedType(anns, underlying, selfsym) =>
- reifyAnnotatedType(tpe)
- case _ =>
- reifyToughType(tpe)
- }
- }
-
- /** An obscure flag necessary for implicit TypeTag generation */
- private var spliceTypesEnabled = !dontSpliceAtTopLevel
-
- /** Keeps track of whether this reification contains abstract type parameters */
- private var _reificationIsConcrete = true
- def reificationIsConcrete = _reificationIsConcrete
- def reificationIsConcrete_=(value: Boolean) {
- _reificationIsConcrete = value
- if (!value && concrete) {
- assert(current.isInstanceOf[Type], current)
- val offender = current.asInstanceOf[Type]
- CannotReifyConcreteTypeTagHavingUnresolvedTypeParameters(offender)
- }
- }
-
- private type SpliceCacheKey = (Symbol, Symbol)
- private lazy val spliceCache: collection.mutable.Map[SpliceCacheKey, Tree] = {
- val cache = analyzer.perRunMacroCache.getOrElseUpdate(MacroContextReify, collection.mutable.Map[Any, Any]())
- cache.getOrElseUpdate("spliceCache", collection.mutable.Map[SpliceCacheKey, Tree]()).asInstanceOf[collection.mutable.Map[SpliceCacheKey, Tree]]
- }
-
- def spliceType(tpe: Type): Tree = {
- // [Eugene] it seems that depending on the context the very same symbol can be either a spliceable tparam or a quantified existential. very weird!
- val quantified = currentQuantified
- if (tpe.isSpliceable && !(quantified contains tpe.typeSymbol)) {
- if (reifyDebug) println("splicing " + tpe)
-
- if (spliceTypesEnabled) {
- var tagClass = if (concrete) ConcreteTypeTagClass else TypeTagClass
- val tagTpe = singleType(prefix.tpe, prefix.tpe member tagClass.name)
-
- // [Eugene] this should be enough for an abstract type, right?
- val key = (tagClass, tpe.typeSymbol)
- if (reifyDebug && spliceCache.contains(key)) println("cache hit: " + spliceCache(key))
- val result = spliceCache.getOrElseUpdate(key, {
- // if this fails, it might produce the dreaded "erroneous or inaccessible type" error
- // to find out the whereabouts of the error run scalac with -Ydebug
- if (reifyDebug) println("launching implicit search for %s.%s[%s]".format(prefix, tagClass.name, tpe))
- typer.resolveTypeTag(prefix.tpe, tpe, defaultErrorPosition, concrete) match {
- case failure if failure.isEmpty =>
- if (reifyDebug) println("implicit search was fruitless")
- EmptyTree
- case success =>
- if (reifyDebug) println("implicit search has produced a result: " + success)
- reificationIsConcrete &= concrete
- var splice = Select(success, nme.tpe)
- splice match {
- case InlinedTypeSplice(_, inlinedSymbolTable, tpe) =>
- // all free vars local to the enclosing reifee should've already been inlined by ``Metalevels''
- inlinedSymbolTable collect { case freedef @ FreeDef(_, _, binding, _, _) if binding.symbol.isLocalToReifee => assert(false, freedef) }
- symbolTable ++= inlinedSymbolTable
- reifyTrace("inlined the splicee: ")(tpe)
- case tpe =>
- tpe
- }
- }
- })
- if (result != EmptyTree) return result.duplicate
- } else {
- if (reifyDebug) println("splicing has been cancelled: spliceTypesEnabled = false")
- }
-
- reificationIsConcrete = false
- }
-
- spliceTypesEnabled = true
- EmptyTree
- }
-
- /** Reify an annotated type, i.e. the one that makes us deal with AnnotationInfos */
- private def reifyAnnotatedType(tpe: AnnotatedType): Tree = {
- val AnnotatedType(anns, underlying, selfsym) = tpe
- mirrorFactoryCall(nme.AnnotatedType, mkList(anns map reifyAnnotationInfo), reify(underlying), reify(selfsym))
- }
-
- /** Reify a tough type, i.e. the one that leads to creation of auxiliary symbols */
- private def reifyToughType(tpe: Type): Tree = {
- if (reifyDebug) println("tough type: %s (%s)".format(tpe, tpe.kind))
-
- def reifyScope(scope: Scope): Tree = {
- scope foreach reifySymDef
- mirrorCall(nme.newScopeWith, scope.toList map reify: _*)
- }
-
- tpe match {
- case tpe @ RefinedType(parents, decls) =>
- reifySymDef(tpe.typeSymbol)
- mirrorFactoryCall(tpe, reify(parents), reifyScope(decls), reify(tpe.typeSymbol))
- case tpe @ ExistentialType(tparams, underlying) =>
- tparams foreach reifySymDef
- mirrorFactoryCall(tpe, reify(tparams), reify(underlying))
- case tpe @ ClassInfoType(parents, decls, clazz) =>
- reifySymDef(clazz)
- mirrorFactoryCall(tpe, reify(parents), reifyScope(decls), reify(tpe.typeSymbol))
- case tpe @ MethodType(params, restpe) =>
- params foreach reifySymDef
- mirrorFactoryCall(tpe, reify(params), reify(restpe))
- case tpe @ PolyType(tparams, underlying) =>
- tparams foreach reifySymDef
- mirrorFactoryCall(tpe, reify(tparams), reify(underlying))
- case _ =>
- throw new Error("internal error: %s (%s) is not supported".format(tpe, tpe.kind))
- }
- }
-} \ No newline at end of file
diff --git a/src/compiler/scala/reflect/reify/package.scala b/src/compiler/scala/reflect/reify/package.scala
index 35b3d9bf38..342b49dee7 100644
--- a/src/compiler/scala/reflect/reify/package.scala
+++ b/src/compiler/scala/reflect/reify/package.scala
@@ -1,59 +1,78 @@
package scala.reflect
+import language.implicitConversions
+import language.experimental.macros
+import scala.reflect.base.{Universe => BaseUniverse}
+import scala.reflect.makro.{Context, ReificationError, UnexpectedReificationError}
import scala.tools.nsc.Global
-import scala.reflect.makro.ReificationError
-import scala.reflect.makro.UnexpectedReificationError
package object reify {
- private def mkReifier(global: Global)(typer: global.analyzer.Typer, prefix: global.Tree, reifee: Any, dontSpliceAtTopLevel: Boolean = false, concrete: Boolean = false): Reifier { val mirror: global.type } = {
+ private def mkReifier(global1: Global)(typer: global1.analyzer.Typer, universe: global1.Tree, mirror: global1.Tree, reifee: Any, concrete: Boolean = false): Reifier { val global: global1.type } = {
val typer1: typer.type = typer
- val prefix1: prefix.type = prefix
+ val universe1: universe.type = universe
+ val mirror1: mirror.type = mirror
val reifee1 = reifee
- val dontSpliceAtTopLevel1 = dontSpliceAtTopLevel
val concrete1 = concrete
new {
- val mirror: global.type = global
+ val global: global1.type = global1
val typer = typer1
- val prefix = prefix1
+ val universe = universe1
+ val mirror = mirror1
val reifee = reifee1
- val dontSpliceAtTopLevel = dontSpliceAtTopLevel1
val concrete = concrete1
} with Reifier
}
- def reifyTree(global: Global)(typer: global.analyzer.Typer, prefix: global.Tree, tree: global.Tree): global.Tree =
- mkReifier(global)(typer, prefix, tree, false, false).reified.asInstanceOf[global.Tree]
+ private[reify] def mkDefaultMirrorRef(global: Global)(universe: global.Tree, typer0: global.analyzer.Typer): global.Tree = {
+ import global._
+ import definitions._
+ val enclosingErasure = reifyEnclosingRuntimeClass(global)(typer0)
+ // JavaUniverse is defined in scala-reflect.jar, so we must be very careful in case someone reifies stuff having only scala-library.jar on the classpath
+ val isJavaUniverse = JavaUniverseClass != NoSymbol && universe.tpe <:< JavaUniverseClass.asTypeConstructor
+ if (isJavaUniverse && !enclosingErasure.isEmpty) Apply(Select(universe, nme.runtimeMirror), List(Select(enclosingErasure, sn.GetClassLoader)))
+ else Select(universe, nme.rootMirror)
+ }
- def reifyType(global: Global)(typer: global.analyzer.Typer, prefix: global.Tree, tpe: global.Type, dontSpliceAtTopLevel: Boolean = false, concrete: Boolean = false): global.Tree =
- mkReifier(global)(typer, prefix, tpe, dontSpliceAtTopLevel, concrete).reified.asInstanceOf[global.Tree]
+ def reifyTree(global: Global)(typer: global.analyzer.Typer, universe: global.Tree, mirror: global.Tree, tree: global.Tree): global.Tree =
+ mkReifier(global)(typer, universe, mirror, tree, concrete = false).reification.asInstanceOf[global.Tree]
+
+ def reifyType(global: Global)(typer: global.analyzer.Typer,universe: global.Tree, mirror: global.Tree, tpe: global.Type, concrete: Boolean = false): global.Tree =
+ mkReifier(global)(typer, universe, mirror, tpe, concrete = concrete).reification.asInstanceOf[global.Tree]
def reifyRuntimeClass(global: Global)(typer0: global.analyzer.Typer, tpe: global.Type, concrete: Boolean = true): global.Tree = {
import global._
import definitions._
import analyzer.enclosingMacroPosition
- def erasureTagInScope = typer0.context.withMacrosDisabled(typer0.resolveErasureTag(tpe, enclosingMacroPosition, concrete = concrete))
- def arrayTagInScope = typer0.context.withMacrosDisabled(typer0.resolveArrayTag(tpe, enclosingMacroPosition))
- val inScope = (erasureTagInScope, arrayTagInScope)
+ if (tpe.isSpliceable) {
+ val classTagInScope = typer0.resolveClassTag(enclosingMacroPosition, tpe, allowMaterialization = false)
+ if (!classTagInScope.isEmpty) return Select(classTagInScope, nme.runtimeClass)
+ val arrayTagInScope = typer0.resolveArrayTag(enclosingMacroPosition, tpe, allowMaterialization = false)
+ if (!arrayTagInScope.isEmpty) return gen.mkMethodCall(arrayElementClassMethod, List(arrayTagInScope))
+ if (concrete) throw new ReificationError(enclosingMacroPosition, "tpe %s is an unresolved spliceable type".format(tpe))
+ }
- inScope match {
- case (success, _) if !success.isEmpty =>
- Select(success, nme.runtimeClass)
- case (_, success) if !success.isEmpty =>
- gen.mkMethodCall(arrayElementClassMethod, List(success))
+ tpe.normalize match {
+ case TypeRef(_, ArrayClass, componentTpe :: Nil) =>
+ val componentErasure = reifyRuntimeClass(global)(typer0, componentTpe, concrete)
+ gen.mkMethodCall(arrayClassMethod, List(componentErasure))
case _ =>
- tpe.normalize match {
- case TypeRef(_, ArrayClass, componentTpe :: Nil) =>
- val componentRuntimeClass = reifyRuntimeClass(global)(typer0, componentTpe, concrete)
- gen.mkMethodCall(arrayClassMethod, List(componentRuntimeClass))
- case _ =>
- if (tpe.isSpliceable && concrete)
- throw new ReificationError(enclosingMacroPosition, "tpe %s is an unresolved spliceable type".format(tpe))
- var erasure = tpe.erasure
- if (tpe.typeSymbol.isDerivedValueClass && global.phase.id < global.currentRun.erasurePhase.id) erasure = tpe
- gen.mkNullaryCall(Predef_classOf, List(erasure))
- }
+ var erasure = tpe.erasure
+ if (tpe.typeSymbol.isDerivedValueClass && global.phase.id < global.currentRun.erasurePhase.id) erasure = tpe
+ gen.mkNullaryCall(Predef_classOf, List(erasure))
}
}
+
+ def reifyEnclosingRuntimeClass(global: Global)(typer0: global.analyzer.Typer): global.Tree = {
+ import global._
+ import definitions._
+ def isThisInScope = typer0.context.enclosingContextChain exists (_.tree.isInstanceOf[Template])
+ if (isThisInScope) {
+ val enclosingClasses = typer0.context.enclosingContextChain map (_.tree) collect { case classDef: ClassDef => classDef }
+ val classInScope = enclosingClasses.headOption getOrElse EmptyTree
+ if (!classInScope.isEmpty) reifyRuntimeClass(global)(typer0, classInScope.symbol.asTypeConstructor, concrete = true)
+ else Select(This(tpnme.EMPTY), sn.GetClass)
+ } else EmptyTree
+ }
}
diff --git a/src/compiler/scala/reflect/reify/phases/Calculate.scala b/src/compiler/scala/reflect/reify/phases/Calculate.scala
index 93ef46472e..41cf6c066a 100644
--- a/src/compiler/scala/reflect/reify/phases/Calculate.scala
+++ b/src/compiler/scala/reflect/reify/phases/Calculate.scala
@@ -4,25 +4,26 @@ package phases
trait Calculate {
self: Reifier =>
- import mirror._
+ import global._
import definitions._
- import treeInfo._
- implicit class RichSymbol(sym: Symbol) {
- def metalevel: Int = { assert(sym != NoSymbol); localSymbols.getOrElse(sym, 0) }
+ implicit class RichCalculateSymbol(sym: Symbol) {
+ def metalevel: Int = { assert(sym != null && sym != NoSymbol); localSymbols.getOrElse(sym, 0) }
def isLocalToReifee = (localSymbols contains sym) // [Eugene] how do I account for local skolems?
}
- implicit class RichType(tpe: Type) {
+ implicit class RichCalculateType(tpe: Type) {
def isLocalToReifee = tpe != null && (tpe exists (tp => (localSymbols contains tp.typeSymbol) || (localSymbols contains tp.termSymbol)))
}
- private var localSymbols = collection.mutable.Map[Symbol, Int]() // set of all symbols that are local to the tree to be reified
+ private def localSymbols: Map[Symbol, Int] = state.localSymbols // set of all symbols that are local to the tree to be reified
+ private def localSymbols_=(value: Map[Symbol, Int]): Unit = state.localSymbols = value
private def registerLocalSymbol(sym: Symbol, metalevel: Int): Unit =
if (sym != null && sym != NoSymbol) {
if (localSymbols contains sym)
assert(localSymbols(sym) == metalevel, "metalevel mismatch: expected %s, actual %s".format(localSymbols(sym), metalevel))
- localSymbols(sym) = metalevel
+ else
+ localSymbols += (sym -> metalevel)
}
/**
@@ -38,7 +39,7 @@ trait Calculate {
try super.traverse(tree)
finally currMetalevel += 1
case tree if tree.isDef =>
- if (reifyDebug) println("boundSym: %s of type %s".format(tree.symbol, (tree.productIterator.toList collect { case tt: TypeTree => tt } headOption).getOrElse(TypeTree(tree.tpe))))
+ if (reifyDebug) println("boundSym: %s of type %s".format(tree.symbol, (tree.productIterator.toList collect { case tt: TypeTree => tt }).headOption.getOrElse(TypeTree(tree.tpe))))
registerLocalSymbol(tree.symbol, currMetalevel)
bindRelatedSymbol(tree.symbol.sourceModule, "sourceModule")
diff --git a/src/compiler/scala/reflect/reify/phases/Metalevels.scala b/src/compiler/scala/reflect/reify/phases/Metalevels.scala
index 206f3b1118..1624bbe951 100644
--- a/src/compiler/scala/reflect/reify/phases/Metalevels.scala
+++ b/src/compiler/scala/reflect/reify/phases/Metalevels.scala
@@ -4,9 +4,8 @@ package phases
trait Metalevels {
self: Reifier =>
- import mirror._
+ import global._
import definitions._
- import treeInfo._
/**
* Makes sense of cross-stage bindings.
@@ -23,7 +22,7 @@ trait Metalevels {
* val x = 2 // metalevel of symbol x is 1, because it's declared inside reify
* val y = reify{x} // metalevel of symbol y is 1, because it's declared inside reify
* // metalevel of Ident(x) is 2, because it's inside two reifies
- * y.eval // metalevel of Ident(y) is 0, because it's inside a designator of a splice
+ * y.splice // metalevel of Ident(y) is 0, because it's inside a designator of a splice
* }
*
* Cross-stage bindings are introduced when symbol.metalevel != curr_metalevel.
@@ -37,21 +36,26 @@ trait Metalevels {
*
* 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.eval? In this very scenario we can use dataflow analysis and inline it,
+ * 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''),
* 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.eval'' and ``Expr.value'' do 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.
+ * 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 eval can be code blocks that can capture variables from the outside.
- * Code inside the lhs of an eval is not reified, while the code from the enclosing reify is.
+ * 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.
*
* Hence some bindings become cross-stage, which is not bad per se (in fact, some cross-stage bindings have sane semantics, as in the example above).
* However this affects freevars, since they are delicate inter-dimensional beings that refer to both current and next planes of existence.
@@ -61,10 +65,10 @@ trait Metalevels {
*
* reify {
* val x = 2
- * reify{x}.eval
+ * reify{x}.splice
* }
*
- * Since the result of the inner reify is wrapped in an eval, it won't be reified
+ * 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)).
@@ -76,10 +80,10 @@ trait Metalevels {
* reify {
* val x = 2
* val y = reify{x}
- * y.eval
+ * y.splice
* }
*
- * In this case the inner reify doesn't appear next to eval, so it will be reified together with x.
+ * In this case the inner reify doesn't appear next to splice, so it will be reified together with x.
* This means that no special processing is needed here.
*
* Example 4. Consider the following fragment:
@@ -89,16 +93,16 @@ trait Metalevels {
* {
* val y = 2
* val z = reify{reify{x + y}}
- * z.eval
- * }.eval
+ * z.splice
+ * }.splice
* }
*
* The reasoning from Example 2 still holds here - we do need to inline the freevar that refers to x.
- * However, we must not touch anything inside the eval'd block, because it's not getting reified.
+ * However, we must not touch anything inside the splice'd block, because it's not getting reified.
*/
- var metalevels = new Transformer {
+ val metalevels = new Transformer {
var insideSplice = false
- var freedefsToInline = collection.mutable.Map[String, ValDef]()
+ var inlineableBindings = collection.mutable.Map[TermName, Tree]()
def withinSplice[T](op: => T) = {
val old = insideSplice
@@ -107,40 +111,36 @@ trait Metalevels {
finally insideSplice = old
}
- // Q: here we deal with all sorts of reified trees. what about ReifiedType(_, _, _, _)?
+ // Q: here we deal with all sorts of reified trees. what about ReifiedType(_, _, _, _, _, _)?
// A: nothing. reified trees give us problems because they sometimes create dimensional rifts as described above
// to the contrast, reified types (i.e. synthetic typetags materialized by Implicits.scala) always stay on the same metalevel as their enclosing code
override def transform(tree: Tree): Tree = tree match {
- case InlineableTreeSplice(splicee, inlinedSymbolTable, _, _, flavor) =>
- if (reifyDebug) println("entering inlineable splice: " + splicee)
- val Block(mrDef :: symbolTable, expr) = splicee
- // [Eugene] how to express the fact that a scrutinee is both of some type and matches an extractor?
- val freedefsToInline = symbolTable collect { case freedef @ FreeTermDef(_, _, binding, _, _) if binding.symbol.isLocalToReifee => freedef.asInstanceOf[ValDef] }
- freedefsToInline foreach (vdef => this.freedefsToInline(vdef.name) = vdef)
- val symbolTable1 = symbolTable diff freedefsToInline
- val tree1 = Select(Block(mrDef :: symbolTable1, expr), flavor)
- if (reifyDebug) println("trimmed %s inlineable free defs from its symbol table: %s".format(freedefsToInline.length, freedefsToInline map (_.name) mkString(", ")))
- withinSplice { super.transform(tree1) }
+ case TreeSplice(ReifiedTree(universe, mirror, symtab, rtree, tpe, rtpe, concrete)) =>
+ if (reifyDebug) println("entering inlineable splice: " + tree)
+ val inlinees = symtab.syms filter (_.isLocalToReifee)
+ inlinees foreach (inlinee => symtab.symAliases(inlinee) foreach (alias => inlineableBindings(alias) = symtab.symBinding(inlinee)))
+ val symtab1 = symtab -- inlinees
+ if (reifyDebug) println("trimmed %s inlineable free defs from its symbol table: %s".format(inlinees.length, inlinees map (inlinee => symtab.symName(inlinee)) mkString(", ")))
+ withinSplice { super.transform(TreeSplice(ReifiedTree(universe, mirror, symtab1, rtree, tpe, rtpe, concrete))) }
case TreeSplice(splicee) =>
if (reifyDebug) println("entering splice: " + splicee)
- val hasBreaches = splicee exists (_.symbol.metalevel > 0)
- if (!insideSplice && hasBreaches) {
- if (settings.logRuntimeSplices.value) reporter.echo(tree.pos, "this splice cannot be resolved statically")
- if (reifyDebug) println("metalevel breach in %s: %s".format(tree, (splicee filter (_.symbol.metalevel > 0) map (_.symbol) distinct) mkString ", "))
+ val breaches = splicee filter (sub => sub.hasSymbol && 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
+ // if (settings.logRuntimeSplices.value) reporter.echo(tree.pos, "this splice cannot be resolved statically")
+ // withinSplice { super.transform(tree) }
+ if (reifyDebug) println("metalevel breach in %s: %s".format(tree, (breaches map (_.symbol)).distinct mkString ", "))
+ CannotReifyRuntimeSplice(tree)
+ } else {
+ withinSplice { super.transform(tree) }
}
- withinSplice { super.transform(tree) }
- // todo. also inline usages of ``freedefsToInline'' in the symbolTable 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
- // todo. also perform garbage collection on local symbols
- // so that local symbols used only in type signatures of free vars get removed
- // todo. same goes for auxiliary symbol defs reified to support tough types
- // some of them need to be rebuilt, some of them need to be removed, because they're no longer necessary
- case FreeRef(mr, name) if freedefsToInline contains name =>
+ case FreeRef(_, name) if inlineableBindings contains name =>
if (reifyDebug) println("inlineable free ref: %s in %s".format(name, showRaw(tree)))
- val freedef @ FreeDef(_, _, binding, _, _) = freedefsToInline(name)
- if (reifyDebug) println("related definition: %s".format(showRaw(freedef)))
- val inlined = reify(binding)
+ val inlined = reify(inlineableBindings(name))
if (reifyDebug) println("verdict: inlined as %s".format(showRaw(inlined)))
inlined
case _ =>
diff --git a/src/compiler/scala/reflect/reify/phases/Reify.scala b/src/compiler/scala/reflect/reify/phases/Reify.scala
index 0e0ce17bd0..dc0028be38 100644
--- a/src/compiler/scala/reflect/reify/phases/Reify.scala
+++ b/src/compiler/scala/reflect/reify/phases/Reify.scala
@@ -5,29 +5,22 @@ import scala.runtime.ScalaRunTime.isAnyVal
import scala.runtime.ScalaRunTime.isTuple
import scala.reflect.reify.codegen._
-trait Reify extends Symbols
- with Types
- with Names
- with Trees
- with AnnotationInfos
- with Positions
- with Util {
+trait Reify extends GenSymbols
+ with GenTypes
+ with GenNames
+ with GenTrees
+ with GenAnnotationInfos
+ with GenPositions
+ with GenUtils {
self: Reifier =>
- import mirror._
+ import global._
import definitions._
- import treeInfo._
- // `reify` looked so nice, I wanted to push the last bit of orthogonal
- // logic out of it so you can see the improvement. There is no cost to
- // wrapper methods of this form because the inliner will eliminate them,
- // but they are very good at separating concerns like pushing/popping
- // a stack, and they are great for composition and reuse.
- //
- // Also, please avoid public vars whenever possible.
private object reifyStack {
- var currents: List[Any] = reifee :: Nil
+ def currents: List[Any] = state.reifyStack
+ def currents_=(value: List[Any]): Unit = state.reifyStack = value
@inline final def push[T](reifee: Any)(body: => T): T = {
currents ::= reifee
@@ -53,9 +46,9 @@ trait Reify extends Symbols
case tree: Tree => reifyTree(tree)
// disabled because this is a very special case that I plan to remove later
// why do I dislike annotations? see comments to `reifyAnnotationInfo`
-// case ann: AnnotationInfo => reifyAnnotationInfo(ann)
+ // case ann: AnnotationInfo => reifyAnnotationInfo(ann)
case pos: Position => reifyPosition(pos)
- case mods: mirror.Modifiers => reifyModifiers(mods)
+ case mods: global.Modifiers => reifyModifiers(mods)
case xs: List[_] => reifyList(xs)
case s: String => Literal(Constant(s))
case v if isAnyVal(v) => Literal(Constant(v))
diff --git a/src/compiler/scala/reflect/reify/phases/Reshape.scala b/src/compiler/scala/reflect/reify/phases/Reshape.scala
index 4ab306a13f..2a562d81e2 100644
--- a/src/compiler/scala/reflect/reify/phases/Reshape.scala
+++ b/src/compiler/scala/reflect/reify/phases/Reshape.scala
@@ -6,15 +6,16 @@ import scala.tools.nsc.symtab.Flags._
trait Reshape {
self: Reifier =>
- import mirror._
+ import global._
import definitions._
- import treeInfo._
/**
* Rolls back certain changes that were introduced during typechecking of the reifee.
*
* These include:
+ * * Undoing macro expansions
* * Replacing type trees with TypeTree(tpe)
+ * * Reassembling CompoundTypeTrees into reifiable form
* * Transforming Modifiers.annotations into Symbol.annotations
* * Transforming Annotated annotations into AnnotatedType annotations
* * Transforming Annotated(annot, expr) into Typed(expr, TypeTree(Annotated(annot, _))
@@ -23,7 +24,8 @@ trait Reshape {
val reshape = new Transformer {
var currentSymbol: Symbol = NoSymbol
- override def transform(tree: Tree) = {
+ override def transform(tree0: Tree) = {
+ val tree = undoMacroExpansion(tree0)
currentSymbol = tree.symbol
val preTyper = tree match {
@@ -31,8 +33,13 @@ trait Reshape {
tree
case tt @ TypeTree() =>
toPreTyperTypeTree(tt)
+ case ctt @ CompoundTypeTree(_) =>
+ toPreTyperCompoundTypeTree(ctt)
case toa @ TypedOrAnnotated(_) =>
toPreTyperTypedOrAnnotated(toa)
+ case ta @ TypeApply(_, _) if isCrossStageTypeBearer(ta) =>
+ if (reifyDebug) println("cross-stage type bearer, retaining: " + tree)
+ ta
case ta @ TypeApply(hk, ts) =>
val discard = ts collect { case tt: TypeTree => tt } exists isDiscarded
if (reifyDebug && discard) println("discarding TypeApply: " + tree)
@@ -85,6 +92,29 @@ trait Reshape {
super.transform(preTyper)
}
+ private def undoMacroExpansion(tree: Tree): Tree =
+ tree.attachments.get[MacroExpansionAttachment] match {
+ case Some(MacroExpansionAttachment(original)) =>
+ original match {
+ // this hack is necessary until I fix implicit macros
+ // so far tag materialization is implemented by sneaky macros hidden in scala-compiler.jar
+ // hence we cannot reify references to them, because noone will be able to see them later
+ // when implicit macros are fixed, these sneaky macros will move to corresponding companion objects
+ // of, say, ClassTag or TypeTag
+ case Apply(TypeApply(_, List(tt)), _) if original.symbol == MacroInternal_materializeArrayTag =>
+ gen.mkNullaryCall(Predef_implicitly, List(appliedType(ArrayTagClass, tt.tpe)))
+ case Apply(TypeApply(_, List(tt)), _) if original.symbol == MacroInternal_materializeClassTag =>
+ gen.mkNullaryCall(Predef_implicitly, List(appliedType(ClassTagClass, tt.tpe)))
+ case Apply(TypeApply(_, List(tt)), List(pre)) if original.symbol == MacroInternal_materializeTypeTag =>
+ gen.mkNullaryCall(Predef_implicitly, List(typeRef(pre.tpe, TypeTagClass, List(tt.tpe))))
+ case Apply(TypeApply(_, List(tt)), List(pre)) if original.symbol == MacroInternal_materializeConcreteTypeTag =>
+ gen.mkNullaryCall(Predef_implicitly, List(typeRef(pre.tpe, ConcreteTypeTagClass, List(tt.tpe))))
+ case _ =>
+ original
+ }
+ case _ => tree
+ }
+
override def transformModifiers(mods: Modifiers) = {
val mods1 = toPreTyperModifiers(mods, currentSymbol)
super.transformModifiers(mods1)
@@ -130,6 +160,7 @@ trait Reshape {
* Suddenly I found out that in certain contexts original trees do not contain symbols, but are just parser trees.
* To the moment I know only one such situation: typedAnnotations does not typecheck the annotation in-place, but rather creates new trees and typechecks them, so the original remains symless.
* Thus we apply a workaround for that in typedAnnotated. I hope this will be the only workaround in this department.
+ * upd. There are also problems with CompoundTypeTrees. I had to use attachments to retain necessary information.
*
* upd. Recently I went ahead and started using original for all TypeTrees, regardless of whether they refer to local symbols or not.
* As a result, ``reifyType'' is never called directly by tree reification (and, wow, it seems to work great!).
@@ -137,7 +168,7 @@ trait Reshape {
*/
private def isDiscarded(tt: TypeTree) = tt.original == null
private def toPreTyperTypeTree(tt: TypeTree): Tree = {
- if (tt.original != null) {
+ if (!isDiscarded(tt)) {
// here we rely on the fact that the originals that reach this point
// have all necessary symbols attached to them (i.e. that they can be recompiled in any lexical context)
// if this assumption fails, please, don't be quick to add postprocessing here (like I did before)
@@ -154,6 +185,14 @@ trait Reshape {
}
}
+ private def toPreTyperCompoundTypeTree(ctt: CompoundTypeTree): Tree = {
+ val CompoundTypeTree(tmpl @ Template(parents, self, stats)) = ctt
+ assert(self eq emptyValDef, self)
+ val att = tmpl.attachments.get[CompoundTypeTreeOriginalAttachment]
+ val CompoundTypeTreeOriginalAttachment(parents1, stats1) = att.getOrElse(CompoundTypeTreeOriginalAttachment(parents, stats))
+ CompoundTypeTree(Template(parents1, self, stats1))
+ }
+
private def toPreTyperTypedOrAnnotated(tree: Tree): Tree = tree match {
case ty @ Typed(expr1, tt @ TypeTree()) =>
if (reifyDebug) println("reify typed: " + tree)
diff --git a/src/compiler/scala/reflect/reify/utils/Extractors.scala b/src/compiler/scala/reflect/reify/utils/Extractors.scala
new file mode 100644
index 0000000000..1fdc015325
--- /dev/null
+++ b/src/compiler/scala/reflect/reify/utils/Extractors.scala
@@ -0,0 +1,294 @@
+package scala.reflect.reify
+package utils
+
+trait Extractors {
+ self: Utils =>
+
+ import global._
+ import definitions._
+ import Flag._
+
+ // Example of a reified tree for `reify(List(1, 2))`:
+ // (also contains an example of a reified type as a third argument to the constructor of Expr)
+ // {
+ // val $u: reflect.runtime.universe.type = scala.reflect.runtime.`package`.universe;
+ // val $m: $u.Mirror = $u.runtimeMirror(Test.this.getClass().getClassLoader());
+ // $u.Expr[List[Int]]($m, {
+ // final class $treecreator1 extends scala.reflect.base.TreeCreator {
+ // def <init>(): $treecreator1 = {
+ // $treecreator1.super.<init>();
+ // ()
+ // };
+ // def apply[U >: Nothing <: scala.reflect.base.Universe with Singleton]($m$untyped: scala.reflect.base.MirrorOf[U]): U#Tree = {
+ // val $u: scala.reflect.api.Universe = $m$untyped.universe.asInstanceOf[scala.reflect.api.Universe];
+ // val $m: $u.Mirror = $m$untyped.asInstanceOf[$u.Mirror];
+ // applyImpl($m).asInstanceOf[U#Tree];
+ // }
+ // def applyImpl[U >: Nothing <: scala.reflect.api.Universe with Singleton]($m$untyped: scala.reflect.base.MirrorOf[U]): U#Tree = {
+ // val $u: U = $m$untyped.universe;
+ // val $m: $u.Mirror = $m$untyped.asInstanceOf[$u.Mirror];
+ // $u.Apply($u.Select($u.Select($u.build.This($m.staticModule("scala.collection.immutable").moduleClass), $u.newTermName("List")), $u.newTermName("apply")), List($u.Literal($u.Constant(1)), $u.Literal($u.Constant(2))))
+ // }
+ // };
+ // new $treecreator1()
+ // })($u.ConcreteTypeTag[List[Int]]($m, {
+ // final class $typecreator1 extends scala.reflect.base.TypeCreator {
+ // def <init>(): $typecreator1 = {
+ // $typecreator1.super.<init>();
+ // ()
+ // };
+ // def apply[U >: Nothing <: scala.reflect.base.Universe with Singleton]($m$untyped: scala.reflect.base.MirrorOf[U]): U#Type = {
+ // val $u: U = $m$untyped.universe;
+ // val $m: $u.Mirror = $m$untyped.asInstanceOf[$u.Mirror];
+ // $u.TypeRef($u.ThisType($m.staticModule("scala.collection.immutable").moduleClass), $m.staticClass("scala.collection.immutable.List"), List($m.staticClass("scala.Int").asTypeConstructor))
+ // }
+ // };
+ // new $typecreator1()
+ // }))
+ // }
+
+ private def mkCreator(flavor: TypeName, symtab: SymbolTable, rtree: Tree): Tree = {
+ val tparamu = newTypeName("U")
+ val (reifierBase, reifierName, reifierTpt, reifierUniverse) = flavor match {
+ case tpnme.REIFY_TYPECREATOR_PREFIX => (TypeCreatorClass, nme.apply, SelectFromTypeTree(Ident(tparamu), tpnme.Type), BaseUniverseClass)
+ case tpnme.REIFY_TREECREATOR_PREFIX => (TreeCreatorClass, nme.applyImpl, SelectFromTypeTree(Ident(BaseUniverseClass), tpnme.Tree), ApiUniverseClass)
+ case _ => throw new Error(s"unexpected flavor $flavor")
+ }
+ val reifierPreamble = flavor match {
+ case tpnme.REIFY_TYPECREATOR_PREFIX => Nil
+ case tpnme.REIFY_TREECREATOR_PREFIX => List[Tree](
+ DefDef(NoMods,
+ nme.apply,
+ List(TypeDef(Modifiers(PARAM), tparamu, List(), TypeBoundsTree(Ident(NothingClass), CompoundTypeTree(Template(List(Ident(BaseUniverseClass), Ident(SingletonClass)), emptyValDef, List()))))),
+ List(List(ValDef(Modifiers(PARAM), nme.MIRROR_UNTYPED, AppliedTypeTree(Ident(MirrorOfClass), List(Ident(tparamu))), EmptyTree))),
+ SelectFromTypeTree(Ident(tparamu), tpnme.Tree),
+ Block(
+ ValDef(NoMods, nme.UNIVERSE_SHORT, Ident(ApiUniverseClass), TypeApply(Select(Select(Ident(nme.MIRROR_UNTYPED), nme.universe), nme.asInstanceOf_), List(Ident(ApiUniverseClass)))),
+ ValDef(NoMods, nme.MIRROR_SHORT, Select(Ident(nme.UNIVERSE_SHORT), tpnme.Mirror), TypeApply(Select(Ident(nme.MIRROR_UNTYPED), nme.asInstanceOf_), List(Select(Ident(nme.UNIVERSE_SHORT), tpnme.Mirror)))),
+ TypeApply(Select(Apply(TypeApply(Ident(reifierName), List(SingletonTypeTree(Ident(nme.UNIVERSE_SHORT)))), List(Ident(nme.MIRROR_SHORT))), nme.asInstanceOf_), List(SelectFromTypeTree(Ident(tparamu), tpnme.Tree)))
+ ))
+ )
+ case _ => throw new Error(s"unexpected flavor $flavor")
+ }
+ val reifierBody = {
+ def gc(symtab: SymbolTable): SymbolTable = {
+ def loop(symtab: SymbolTable): SymbolTable = {
+ def extractNames(tree: Tree) = tree.collect{ case ref: RefTree => ref.name }.toSet
+ val usedNames = extractNames(rtree) ++ symtab.syms.flatMap(sym => extractNames(symtab.symDef(sym)))
+ symtab filterAliases { case (_, name) => usedNames(name) }
+ }
+ var prev = symtab
+ var next = loop(symtab)
+ while (next.syms.length < prev.syms.length) {
+ prev = next
+ next = loop(prev)
+ }
+ next
+ }
+
+ val universeAlias = ValDef(NoMods, nme.UNIVERSE_SHORT, Ident(tparamu), Select(Ident(nme.MIRROR_UNTYPED), nme.universe))
+ val mirrorAlias = ValDef(NoMods, nme.MIRROR_SHORT, Select(Ident(nme.UNIVERSE_SHORT), tpnme.Mirror), TypeApply(Select(Ident(nme.MIRROR_UNTYPED), nme.asInstanceOf_), List(Select(Ident(nme.UNIVERSE_SHORT), tpnme.Mirror))))
+ val trimmedSymtab = if (hasReifier) gc(symtab) else symtab
+ Block(universeAlias :: mirrorAlias :: trimmedSymtab.encode, rtree)
+ }
+ val tpec = ClassDef(
+ Modifiers(FINAL),
+ newTypeName(global.currentUnit.fresh.newName(flavor.toString)),
+ List(),
+ Template(List(Ident(reifierBase)),
+ emptyValDef,
+ List(
+ DefDef(NoMods, nme.CONSTRUCTOR, List(), List(List()), TypeTree(), Block(List(Apply(Select(Super(This(tpnme.EMPTY), tpnme.EMPTY), nme.CONSTRUCTOR), List())), Literal(Constant(()))))
+ ) ++ reifierPreamble ++ List(
+ DefDef(NoMods,
+ reifierName,
+ List(TypeDef(Modifiers(PARAM), tparamu, List(), TypeBoundsTree(Ident(NothingClass), CompoundTypeTree(Template(List(Ident(reifierUniverse), Ident(SingletonClass)), emptyValDef, List()))))),
+ List(List(ValDef(Modifiers(PARAM), nme.MIRROR_UNTYPED, AppliedTypeTree(Ident(MirrorOfClass), List(Ident(tparamu))), EmptyTree))),
+ reifierTpt, reifierBody))))
+ Block(tpec, ApplyConstructor(Ident(tpec.name), List()))
+ }
+
+ private def mkWrapper(universe: Tree, mirror: Tree, wrappee: Tree): Tree = {
+ val universeAlias = ValDef(NoMods, nme.UNIVERSE_SHORT, SingletonTypeTree(universe), universe)
+ val mirrorAlias = ValDef(NoMods, nme.MIRROR_SHORT, Select(Ident(nme.UNIVERSE_SHORT), tpnme.Mirror), mirror orElse mkDefaultMirrorRef(global)(universe, typer))
+ Block(List(universeAlias, mirrorAlias), wrappee)
+ }
+
+ object ReifiedTree {
+ def apply(universe: Tree, mirror: Tree, symtab: SymbolTable, rtree: Tree, tpe: Type, rtpe: Tree, concrete: Boolean): Tree = {
+ val tagFactory = if (concrete) nme.ConcreteTypeTag else nme.TypeTag
+ val tagCtor = TypeApply(Select(Select(Ident(nme.UNIVERSE_SHORT), tagFactory), nme.apply), List(TypeTree(tpe)))
+ val exprCtor = TypeApply(Select(Select(Ident(nme.UNIVERSE_SHORT), nme.Expr), nme.apply), List(TypeTree(tpe)))
+ val tagArgs = List(Ident(nme.MIRROR_SHORT), mkCreator(tpnme.REIFY_TYPECREATOR_PREFIX, symtab, rtpe))
+ val unwrapped = Apply(Apply(exprCtor, List(Ident(nme.MIRROR_SHORT), mkCreator(tpnme.REIFY_TREECREATOR_PREFIX, symtab, rtree))), List(Apply(tagCtor, tagArgs)))
+ mkWrapper(universe, mirror, unwrapped)
+ }
+
+ def unapply(tree: Tree): Option[(Tree, Tree, SymbolTable, Tree, Type, Tree, Boolean)] = tree match {
+ case Block(
+ List(udef @ ValDef(_, _, _, universe), mdef @ ValDef(_, _, _, mirror)),
+ Apply(
+ Apply(TypeApply(_, List(ttpe @ TypeTree())), List(_, Block(List(ClassDef(_, _, _, Template(_, _, List(_, _, DefDef(_, _, _, _, _, Block(_ :: _ :: symbolTable1, rtree)))))), _))),
+ // todo. doesn't take into account optimizations such as $u.TypeTag.Int or the upcoming closure optimization
+ List(Apply(TypeApply(Select(_, tagFlavor), _), List(_, Block(List(ClassDef(_, _, _, Template(_, _, List(_, DefDef(_, _, _, _, _, Block(_ :: _ :: symbolTable2, rtpe)))))), _))))))
+ if udef.name == nme.UNIVERSE_SHORT && mdef.name == nme.MIRROR_SHORT =>
+ Some(universe, mirror, SymbolTable(symbolTable1 ++ symbolTable2), rtree, ttpe.tpe, rtpe, tagFlavor == nme.ConcreteTypeTag)
+ case _ =>
+ None
+ }
+ }
+
+ object ReifiedType {
+ def apply(universe: Tree, mirror: Tree, symtab: SymbolTable, tpe: Type, rtpe: Tree, concrete: Boolean) = {
+ val tagFactory = if (concrete) nme.ConcreteTypeTag else nme.TypeTag
+ val ctor = TypeApply(Select(Select(Ident(nme.UNIVERSE_SHORT), tagFactory), nme.apply), List(TypeTree(tpe)))
+ val args = List(Ident(nme.MIRROR_SHORT), mkCreator(tpnme.REIFY_TYPECREATOR_PREFIX, symtab, rtpe))
+ val unwrapped = Apply(ctor, args)
+ mkWrapper(universe, mirror, unwrapped)
+ }
+
+ def unapply(tree: Tree): Option[(Tree, Tree, SymbolTable, Type, Tree, Boolean)] = tree match {
+ case Block(
+ List(udef @ ValDef(_, _, _, universe), mdef @ ValDef(_, _, _, mirror)),
+ // todo. doesn't take into account optimizations such as $u.TypeTag.Int or the upcoming closure optimization
+ Apply(TypeApply(Select(_, tagFlavor), List(ttpe @ TypeTree())), List(_, Block(List(ClassDef(_, _, _, Template(_, _, List(_, DefDef(_, _, _, _, _, Block(_ :: _ :: symtab, rtpe)))))), _))))
+ if udef.name == nme.UNIVERSE_SHORT && mdef.name == nme.MIRROR_SHORT =>
+ Some(universe, mirror, SymbolTable(symtab), ttpe.tpe, rtpe, tagFlavor == nme.ConcreteTypeTag)
+ case _ =>
+ None
+ }
+ }
+
+ object TreeSplice {
+ def apply(splicee: Tree): Tree =
+ Select(splicee, ExprSplice)
+
+ def unapply(tree: Tree): Option[Tree] = tree match {
+ case Select(splicee, _) if tree.symbol != NoSymbol && tree.symbol == ExprSplice =>
+ Some(splicee)
+ case _ =>
+ None
+ }
+ }
+
+ object FreeDef {
+ def unapply(tree: Tree): Option[(Tree, TermName, Tree, Long, String)] = tree match {
+ case FreeTermDef(uref, name, binding, flags, origin) =>
+ Some(uref, name, binding, flags, origin)
+ case FreeTypeDef(uref, name, binding, flags, origin) =>
+ Some(uref, name, binding, flags, origin)
+ case _ =>
+ None
+ }
+ }
+
+ object FreeTermDef {
+ def unapply(tree: Tree): Option[(Tree, TermName, Tree, Long, String)] = tree match {
+ case
+ ValDef(_, name, _, Apply(
+ Select(Select(uref1 @ Ident(_), build1), newFreeTerm),
+ List(
+ _,
+ _,
+ binding,
+ Apply(Select(Select(uref2 @ Ident(_), build2), flagsFromBits), List(Literal(Constant(flags: Long)))),
+ Literal(Constant(origin: String)))))
+ if uref1.name == nme.UNIVERSE_SHORT && build1 == nme.build && newFreeTerm == nme.newFreeTerm &&
+ uref2.name == nme.UNIVERSE_SHORT && build2 == nme.build && flagsFromBits == nme.flagsFromBits =>
+ Some(uref1, name, binding, flags, origin)
+ case _ =>
+ None
+ }
+ }
+
+ object FreeTypeDef {
+ def unapply(tree: Tree): Option[(Tree, TermName, Tree, Long, String)] = tree match {
+ case
+ ValDef(_, name, _, Apply(
+ Select(Select(uref1 @ Ident(_), build1), newFreeType),
+ List(
+ _,
+ _,
+ value,
+ Apply(Select(Select(uref2 @ Ident(_), build2), flagsFromBits), List(Literal(Constant(flags: Long)))),
+ Literal(Constant(origin: String)))))
+ if uref1.name == nme.UNIVERSE_SHORT && build1 == nme.build && (newFreeType == nme.newFreeType || newFreeType == nme.newFreeExistential) &&
+ uref2.name == nme.UNIVERSE_SHORT && build2 == nme.build && flagsFromBits == nme.flagsFromBits =>
+ value match {
+ case Apply(TypeApply(Select(Select(uref3 @ Ident(_), typeTag), apply), List(binding)), List(Literal(Constant(null)), _))
+ if uref3.name == nme.UNIVERSE_SHORT && typeTag == nme.TypeTag && apply == nme.apply =>
+ Some(uref1, name, binding, flags, origin)
+ case Apply(TypeApply(Select(uref3 @ Ident(_), typeTag), List(binding)), List(Literal(Constant(null)), _))
+ if uref3.name == nme.UNIVERSE_SHORT && typeTag == nme.TypeTag =>
+ Some(uref1, name, binding, flags, origin)
+ case _ =>
+ throw new Error("unsupported free type def: %s%n%s".format(value, showRaw(value)))
+ }
+ case _ =>
+ None
+ }
+ }
+
+ object FreeRef {
+ def unapply(tree: Tree): Option[(Tree, TermName)] = tree match {
+ case Apply(Select(Select(uref @ Ident(_), build), ident), List(Ident(name: TermName)))
+ if build == nme.build && ident == nme.Ident && name.startsWith(nme.REIFY_FREE_PREFIX) =>
+ Some(uref, name)
+ case _ =>
+ None
+ }
+ }
+
+ object SymDef {
+ def unapply(tree: Tree): Option[(Tree, TermName, Long, Boolean)] = tree match {
+ case
+ ValDef(_, name, _, Apply(
+ Select(Select(uref1 @ Ident(_), build1), newNestedSymbol),
+ List(
+ _,
+ _,
+ _,
+ Apply(Select(Select(uref2 @ Ident(_), build2), flagsFromBits), List(Literal(Constant(flags: Long)))),
+ Literal(Constant(isClass: Boolean)))))
+ if uref1.name == nme.UNIVERSE_SHORT && build1 == nme.build && newNestedSymbol == nme.newNestedSymbol &&
+ uref2.name == nme.UNIVERSE_SHORT && build2 == nme.build && flagsFromBits == nme.flagsFromBits =>
+ Some(uref1, name, flags, isClass)
+ case _ =>
+ None
+ }
+ }
+
+ object TypeRefToFreeType {
+ def unapply(tree: Tree): Option[TermName] = tree match {
+ case Apply(Select(Select(uref @ Ident(_), typeRef), apply), List(Select(_, noSymbol), Ident(freeType: TermName), nil))
+ if (uref.name == nme.UNIVERSE_SHORT && typeRef == nme.TypeRef && noSymbol == nme.NoSymbol && freeType.startsWith(nme.REIFY_FREE_PREFIX)) =>
+ Some(freeType)
+ case _ =>
+ None
+ }
+ }
+
+ object BoundTerm {
+ def unapply(tree: Tree): Option[Tree] = tree match {
+ case Ident(name) if name.isTermName =>
+ Some(tree)
+ case This(_) =>
+ Some(tree)
+ case _ =>
+ None
+ }
+ }
+
+ object BoundType {
+ def unapply(tree: Tree): Option[Tree] = tree match {
+ case Select(_, name) if name.isTypeName =>
+ Some(tree)
+ case SelectFromTypeTree(_, name) if name.isTypeName =>
+ Some(tree)
+ case Ident(name) if name.isTypeName =>
+ Some(tree)
+ case _ =>
+ None
+ }
+ }
+}
diff --git a/src/compiler/scala/reflect/reify/utils/NodePrinters.scala b/src/compiler/scala/reflect/reify/utils/NodePrinters.scala
new file mode 100644
index 0000000000..ce0ab2196a
--- /dev/null
+++ b/src/compiler/scala/reflect/reify/utils/NodePrinters.scala
@@ -0,0 +1,144 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ * @author Martin Odersky
+ */
+package scala.reflect.reify
+package utils
+
+import scala.compat.Platform.EOL
+
+trait NodePrinters {
+ self: Utils =>
+
+ import global._
+ import definitions._
+ import Flag._
+
+ object reifiedNodeToString extends (Tree => String) {
+ // [Eugene++ to Martin] can we do better?
+ // didn't want to invent anything myself in order not to interfere with your line of thought
+ def bitsToFlags(bits: String): String = {
+ val flags = bits.toLong
+ if (flags == NoFlags) nme.NoFlags.toString
+ else {
+ val s_flags = new collection.mutable.ListBuffer[String]
+ if (flags containsAll TRAIT) s_flags += "TRAIT"
+ if (flags containsAll MODULE) s_flags += "MODULE"
+ if (flags containsAll MUTABLE) s_flags += "MUTABLE"
+ if (flags containsAll PACKAGE) s_flags += "PACKAGE"
+ if (flags containsAll METHOD) s_flags += "METHOD"
+ if (flags containsAll DEFERRED) s_flags += "DEFERRED"
+ if (flags containsAll ABSTRACT) s_flags += "ABSTRACT"
+ if (flags containsAll FINAL) s_flags += "FINAL"
+ if (flags containsAll SEALED) s_flags += "SEALED"
+ if (flags containsAll IMPLICIT) s_flags += "IMPLICIT"
+ if (flags containsAll LAZY) s_flags += "LAZY"
+ if (flags containsAll OVERRIDE) s_flags += "OVERRIDE"
+ if (flags containsAll PRIVATE) s_flags += "PRIVATE"
+ if (flags containsAll PROTECTED) s_flags += "PROTECTED"
+ if (flags containsAll CASE) s_flags += "CASE"
+ if (flags containsAll ABSOVERRIDE) s_flags += "ABSOVERRIDE"
+ if (flags containsAll BYNAMEPARAM) s_flags += "BYNAMEPARAM"
+ if (flags containsAll PARAM) s_flags += "PARAM"
+ if (flags containsAll PARAMACCESSOR) s_flags += "PARAMACCESSOR"
+ if (flags containsAll CASEACCESSOR) s_flags += "CASEACCESSOR"
+ if (flags containsAll COVARIANT) s_flags += "COVARIANT"
+ if (flags containsAll CONTRAVARIANT) s_flags += "CONTRAVARIANT"
+ if (flags containsAll DEFAULTPARAM) s_flags += "DEFAULTPARAM"
+ if (flags containsAll INTERFACE) s_flags += "INTERFACE"
+ s_flags mkString " | "
+ }
+ }
+
+ def apply(tree: Tree): String = {
+ var mirrorIsUsed = false
+ var flagsAreUsed = false
+
+ // @PP: I fervently hope this is a test case or something, not anything being
+ // depended upon. Of more fragile code I cannot conceive.
+ // @Eugene: This stuff is only needed to debug-print out reifications in human-readable format
+ // Rolling a full-fledged, robust TreePrinter would be several times more code.
+ val lines = (tree.toString.split(EOL) drop 1 dropRight 1).toList splitAt 2
+ var (List(universe, mirror), reification) = lines
+ reification = (for (line <- reification) yield {
+ var s = line substring 2
+ s = s.replace(nme.UNIVERSE_PREFIX.toString, "")
+ s = s.replace(".apply", "")
+ s = "([^\"])scala\\.collection\\.immutable\\.".r.replaceAllIn(s, "$1")
+ s = "List\\[List\\[.*?\\].*?\\]".r.replaceAllIn(s, "List")
+ s = "List\\[.*?\\]".r.replaceAllIn(s, "List")
+ s = s.replace("immutable.this.Nil", "List()")
+ s = """build\.flagsFromBits\((\d+)[lL]\)""".r.replaceAllIn(s, m => {
+ flagsAreUsed = true
+ bitsToFlags(m.group(1))
+ })
+ s = s.replace("Modifiers(0L, newTypeName(\"\"), List())", "Modifiers()")
+ s = """Modifiers\((\d+)[lL], newTypeName\("(.*?)"\), List\((.*?)\)\)""".r.replaceAllIn(s, m => {
+ val buf = new collection.mutable.ListBuffer[String]
+
+ val annotations = m.group(3)
+ if (buf.nonEmpty || annotations.nonEmpty)
+ buf.append("List(" + annotations + ")")
+
+ val privateWithin = "" + m.group(2)
+ if (buf.nonEmpty || privateWithin != "")
+ buf.append("newTypeName(\"" + privateWithin + "\")")
+
+ val bits = m.group(1)
+ if (buf.nonEmpty || bits != "0L") {
+ flagsAreUsed = true
+ buf.append(bitsToFlags(bits))
+ }
+
+ val replacement = "Modifiers(" + buf.reverse.mkString(", ") + ")"
+ java.util.regex.Matcher.quoteReplacement(replacement)
+ })
+ s
+ })
+
+ val isExpr = reification.length > 0 && reification(0).trim.startsWith("Expr[")
+ var rtree = reification dropWhile (!_.trim.startsWith(s"val ${nme.UNIVERSE_SHORT}: U = ${nme.MIRROR_UNTYPED}.universe;"))
+ rtree = rtree drop 2
+ rtree = rtree takeWhile (_ != " }")
+ rtree = rtree map (s0 => {
+ var s = s0
+ mirrorIsUsed |= s contains nme.MIRROR_PREFIX.toString
+ s = s.replace(nme.MIRROR_PREFIX.toString, "")
+ s.trim
+ })
+
+ val printout = collection.mutable.ListBuffer[String]();
+ printout += universe.trim
+ if (mirrorIsUsed) printout += mirror.replace("MirrorOf[", "scala.reflect.base.MirrorOf[").trim
+ val imports = collection.mutable.ListBuffer[String]();
+ imports += nme.UNIVERSE_SHORT
+ // if (buildIsUsed) imports += nme.build
+ if (mirrorIsUsed) imports += nme.MIRROR_SHORT
+ if (flagsAreUsed) imports += nme.Flag
+ printout += s"""import ${imports map (_ + "._") mkString ", "}"""
+
+ val name = if (isExpr) "tree" else "tpe"
+ if (rtree(0) startsWith "val") {
+ printout += s"val $name = {"
+ printout ++= (rtree map (" " + _))
+ printout += "}"
+ } else {
+ printout += s"val $name = " + rtree(0)
+ }
+ if (isExpr) {
+ if (mirror contains ".getClassLoader") {
+ printout += "import scala.tools.reflect.ToolBox"
+ printout += s"println(${nme.MIRROR_SHORT}.mkToolBox().runExpr(tree))"
+ } else {
+ printout += "println(tree)"
+ }
+ } else {
+ printout += "println(tpe)"
+ }
+
+ // printout mkString EOL
+ val prefix = "// produced from " + reifier.defaultErrorPosition
+ (prefix +: "object Test extends App {" +: (printout map (" " + _)) :+ "}") mkString EOL
+ }
+ }
+}
diff --git a/src/compiler/scala/reflect/reify/utils/StdAttachments.scala b/src/compiler/scala/reflect/reify/utils/StdAttachments.scala
new file mode 100644
index 0000000000..abbed814e0
--- /dev/null
+++ b/src/compiler/scala/reflect/reify/utils/StdAttachments.scala
@@ -0,0 +1,12 @@
+package scala.reflect.reify
+package utils
+
+trait StdAttachments {
+ self: Utils =>
+
+ import global._
+
+ case class ReifyBindingAttachment(binding: Symbol)
+
+ case class ReifyAliasAttachment(binding: Symbol, alias: TermName)
+} \ No newline at end of file
diff --git a/src/compiler/scala/reflect/reify/utils/SymbolTables.scala b/src/compiler/scala/reflect/reify/utils/SymbolTables.scala
new file mode 100644
index 0000000000..a7ac299317
--- /dev/null
+++ b/src/compiler/scala/reflect/reify/utils/SymbolTables.scala
@@ -0,0 +1,223 @@
+package scala.reflect.reify
+package utils
+
+import scala.collection._
+import scala.compat.Platform.EOL
+
+trait SymbolTables {
+ self: Utils =>
+
+ import global._
+ import definitions._
+ import Flag._
+
+ class SymbolTable private[SymbolTable] (
+ private[SymbolTable] val symtab: immutable.ListMap[Symbol, Tree] = immutable.ListMap[Symbol, Tree](),
+ private[SymbolTable] val aliases: List[(Symbol, TermName)] = List[(Symbol, TermName)](),
+ private[SymbolTable] val original: Option[List[Tree]] = None) {
+
+ def syms: List[Symbol] = symtab.keys.toList
+
+// def aliases: Map[Symbol, List[TermName]] = aliases.distinct groupBy (_._1) mapValues (_ map (_._2))
+
+ def symDef(sym: Symbol): Tree =
+ symtab.getOrElse(sym, EmptyTree)
+
+ def symName(sym: Symbol): TermName =
+ symtab.get(sym) match {
+ case Some(FreeDef(_, name, _, _, _)) => name
+ case Some(SymDef(_, name, _, _)) => name
+ case None => EmptyTermName
+ }
+
+ def symAliases(sym: Symbol): List[TermName] =
+ symName(sym) match {
+ case name if name.isEmpty => Nil
+ case _ => (aliases.distinct groupBy (_._1) mapValues (_ map (_._2)))(sym)
+ }
+
+ def symBinding(sym: Symbol): Tree =
+ symtab.get(sym) match {
+ case Some(FreeDef(_, _, binding, _, _)) => binding
+ case Some(SymDef(_, _, _, _)) => throw new UnsupportedOperationException(s"${symtab(sym)} is a symdef, hence it doesn't have a binding")
+ case None => EmptyTree
+ }
+
+ def symRef(sym: Symbol): Tree =
+ symtab.get(sym) match {
+ case Some(FreeDef(_, name, _, _, _)) => Ident(name) addAttachment ReifyBindingAttachment(sym)
+ case Some(SymDef(_, name, _, _)) => Ident(name) addAttachment ReifyBindingAttachment(sym)
+ case None => EmptyTree
+ }
+
+ def +(sym: Symbol, name: TermName, reification: Tree): SymbolTable = add(sym, name, reification)
+ def +(sym: Symbol, name: TermName): SymbolTable = add(sym, name)
+ def +(symDef: Tree): SymbolTable = add(symDef)
+ def ++(symDefs: TraversableOnce[Tree]): SymbolTable = (this /: symDefs)((symtab, symDef) => symtab.add(symDef))
+ def ++(symtab: SymbolTable): SymbolTable = { val updated = this ++ symtab.symtab.values; new SymbolTable(updated.symtab, updated.aliases ++ symtab.aliases) }
+ def -(sym: Symbol): SymbolTable = remove(sym)
+ def -(name: TermName): SymbolTable = remove(name)
+ def -(symDef: Tree): SymbolTable = remove(binding(symDef))
+ def --(syms: GenTraversableOnce[Symbol]): SymbolTable = (this /: syms)((symtab, sym) => symtab.remove(sym))
+ def --(names: Iterable[TermName]): SymbolTable = (this /: names)((symtab, name) => symtab.remove(name))
+ def --(symDefs: TraversableOnce[Tree]): SymbolTable = this -- (symDefs map (binding(_)))
+ def --(symtab: SymbolTable): SymbolTable = { val updated = this -- symtab.symtab.values; new SymbolTable(updated.symtab, updated.aliases diff symtab.aliases) }
+ def filterSyms(p: Symbol => Boolean): SymbolTable = this -- (syms filterNot p)
+ def filterAliases(p: (Symbol, TermName) => Boolean): SymbolTable = this -- (aliases filterNot (tuple => p(tuple._1, tuple._2)) map (_._2))
+
+ private def add(symDef: Tree): SymbolTable = {
+ val sym = binding(symDef)
+ assert(sym != NoSymbol, showRaw(symDef))
+ val name = symDef match {
+ case FreeDef(_, name, _, _, _) => name
+ case SymDef(_, name, _, _) => name
+ }
+ val newSymtab = if (!(symtab contains sym)) symtab + (sym -> symDef) else symtab
+ val newAliases = aliases :+ (sym -> name)
+ new SymbolTable(newSymtab, newAliases)
+ }
+
+ private def add(sym: Symbol, name0: TermName, reification: Tree): SymbolTable = {
+ def freshName(name0: TermName): TermName = {
+ var name = name0.toString
+ name = name.replace(".type", "$type")
+ name = name.replace(" ", "$")
+ val fresh = typer.context.unit.fresh
+ newTermName(fresh.newName(name))
+ }
+ add(ValDef(NoMods, freshName(name0), TypeTree(), reification) addAttachment ReifyBindingAttachment(sym))
+ }
+
+ private def add(sym: Symbol, name: TermName): SymbolTable = {
+ if (!(syms contains sym)) error("cannot add an alias to a symbol not in the symbol table")
+ add(sym, name, EmptyTree)
+ }
+
+ private def remove(sym: Symbol): SymbolTable = {
+ val newSymtab = symtab - sym
+ val newAliases = aliases filter (_._1 != sym)
+ new SymbolTable(newSymtab, newAliases)
+ }
+
+ private def remove(name: TermName): SymbolTable = {
+ var newSymtab = symtab
+ val newAliases = aliases filter (_._2 != name)
+ newSymtab = newSymtab filter { case ((sym, _)) => newAliases exists (_._1 == sym) }
+ newSymtab = newSymtab map { case ((sym, tree)) =>
+ val ValDef(mods, primaryName, tpt, rhs) = tree
+ val tree1 =
+ if (!(newAliases contains (sym, primaryName))) {
+ val primaryName1 = newAliases.find(_._1 == sym).get._2
+ ValDef(mods, primaryName1, tpt, rhs).copyAttrs(tree)
+ } else tree
+ (sym, tree1)
+ }
+ new SymbolTable(newSymtab, newAliases)
+ }
+
+ private def binding(tree: Tree): Symbol =
+ tree.attachments.get[ReifyBindingAttachment] match {
+ case Some(ReifyBindingAttachment(binding)) => binding
+ case other => NoSymbol
+ }
+
+ private val cache = mutable.Map[SymbolTable, List[Tree]]()
+ def encode: List[Tree] = cache.getOrElseUpdate(this, SymbolTable.encode(this)) map (_.duplicate)
+
+ override def toString = {
+ val symtabString = symtab.keys.map(symName(_)).mkString(", ")
+ val trueAliases = aliases.distinct.filter(entry => symName(entry._1) != entry._2)
+ val aliasesString = trueAliases.map(entry => s"${symName(entry._1)} -> ${entry._2}").mkString(", ")
+ s"""symtab = [$symtabString], aliases = [$aliasesString]${if (original.isDefined) ", has original" else ""}"""
+ }
+
+ def debugString: String = {
+ val buf = new StringBuilder
+ buf.append("symbol table = " + (if (syms.length == 0) "<empty>" else "")).append(EOL)
+ syms foreach (sym => buf.append(symDef(sym)).append(EOL))
+ buf.delete(buf.length - EOL.length, buf.length)
+ buf.toString
+ }
+ }
+
+ object SymbolTable {
+ def apply(): SymbolTable =
+ new SymbolTable()
+
+ def apply(encoded: List[Tree]): SymbolTable = {
+ var result = new SymbolTable(original = Some(encoded))
+ encoded foreach (entry => (entry.attachments.get[ReifyBindingAttachment], entry.attachments.get[ReifyAliasAttachment]) match {
+ case (Some(ReifyBindingAttachment(sym)), _) => result += entry
+ case (_, Some(ReifyAliasAttachment(sym, alias))) => result = new SymbolTable(result.symtab, result.aliases :+ (sym, alias))
+ case _ => // do nothing, this is boilerplate that can easily be recreated by subsequent `result.encode`
+ })
+ result
+ }
+
+ private[SymbolTable] def encode(symtab0: SymbolTable): List[Tree] = {
+ if (symtab0.original.isDefined) return symtab0.original.get.map(_.duplicate)
+ else assert(hasReifier, "encoding a symbol table requires a reifier")
+ // during `encode` we might need to do some reifications
+ // these reifications might lead to changes in `reifier.symtab`
+ // reifier is mutable, symtab is immutable. this is a tough friendship
+ val backup = reifier.state.backup
+ reifier.state.symtab = symtab0.asInstanceOf[reifier.SymbolTable]
+ def currtab = reifier.symtab.asInstanceOf[SymbolTable]
+ try {
+ val cumulativeSymtab = mutable.ArrayBuffer[Tree](symtab0.symtab.values.toList: _*)
+ val cumulativeAliases = mutable.ArrayBuffer[(Symbol, TermName)](symtab0.aliases: _*)
+
+ def fillInSymbol(sym: Symbol): Tree = {
+ if (reifyDebug) println("Filling in: %s (%s)".format(sym, sym.accurateKindString))
+ val isFree = currtab.symName(sym) startsWith nme.REIFY_FREE_PREFIX
+ if (isFree) {
+ if (sym.annotations.isEmpty) EmptyTree
+ else Apply(Select(currtab.symRef(sym), nme.setAnnotations), List(reifier.reify(sym.annotations)))
+ } else {
+ import scala.reflect.internal.Flags._
+ if (sym hasFlag LOCKED) {
+ // [Eugene] better to have a symbol without a type signature, than to crash with a CyclicReference
+ EmptyTree
+ } else {
+ val rset = reifier.mirrorBuildCall(nme.setTypeSignature, currtab.symRef(sym), reifier.reify(sym.info))
+ if (sym.annotations.isEmpty) rset
+ else reifier.mirrorBuildCall(nme.setAnnotations, rset, reifier.mkList(sym.annotations map reifier.reifyAnnotationInfo))
+ }
+ }
+ }
+
+ // `fillInSymbol` might add symbols to `symtab`, that's why this is done iteratively
+ var progress = 0
+ while (progress < cumulativeSymtab.length) {
+ val sym = currtab.binding(cumulativeSymtab(progress))
+ if (sym != NoSymbol) {
+ val symtabProgress = currtab.symtab.size
+ val aliasesProgress = currtab.aliases.length
+ val fillIn = fillInSymbol(sym)
+ cumulativeSymtab ++= currtab.symtab.values drop symtabProgress
+ cumulativeAliases ++= currtab.aliases drop aliasesProgress
+ cumulativeSymtab += fillIn
+ }
+ progress += 1
+ }
+
+ val withAliases = cumulativeSymtab flatMap (entry => {
+ val result = mutable.ListBuffer[Tree]()
+ result += entry
+ val sym = currtab.binding(entry)
+ if (sym != NoSymbol)
+ result ++= cumulativeAliases.distinct filter (alias => alias._1 == sym && alias._2 != currtab.symName(sym)) map (alias => {
+ val canonicalName = currtab.symName(sym)
+ val aliasName = alias._2
+ ValDef(NoMods, aliasName, TypeTree(), Ident(canonicalName)) addAttachment ReifyAliasAttachment(sym, aliasName)
+ })
+ result.toList
+ })
+
+ withAliases.toList
+ } finally {
+ reifier.state.restore(backup)
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/src/compiler/scala/reflect/reify/utils/Utils.scala b/src/compiler/scala/reflect/reify/utils/Utils.scala
new file mode 100644
index 0000000000..e1213f932c
--- /dev/null
+++ b/src/compiler/scala/reflect/reify/utils/Utils.scala
@@ -0,0 +1,21 @@
+package scala.reflect.reify
+package utils
+
+import scala.tools.nsc.Global
+
+trait Utils extends NodePrinters
+ with Extractors
+ with SymbolTables
+ with StdAttachments {
+
+ val global: Global
+ val typer: global.analyzer.Typer
+
+ lazy val reifier: Reifier { val global: Utils.this.global.type } = getReifier
+ def getReifier: Reifier { val global: Utils.this.global.type } = ???
+ def hasReifier = false
+
+ val reifyDebug = global.settings.Yreifydebug.value
+ val reifyCopypaste = global.settings.Yreifycopypaste.value
+ val reifyTrace = scala.tools.nsc.util.trace when reifyDebug
+} \ No newline at end of file
diff --git a/src/compiler/scala/reflect/runtime/package.scala b/src/compiler/scala/reflect/runtime/package.scala
index 531873c661..a5809a2629 100644
--- a/src/compiler/scala/reflect/runtime/package.scala
+++ b/src/compiler/scala/reflect/runtime/package.scala
@@ -9,5 +9,18 @@ package object runtime {
// [Eugene++ to Martin] removed `mirrorOfLoader`, because one can use `universe.runtimeMirror` instead
- def currentMirror: universe.Mirror = ???
+ def currentMirror: universe.Mirror = macro Macros.currentMirror
+}
+
+package runtime {
+ object Macros {
+ def currentMirror(c: scala.reflect.makro.Context): c.Expr[universe.Mirror] = {
+ import c.universe._
+ val runtimeClass = c.reifyEnclosingRuntimeClass
+ if (runtimeClass.isEmpty) c.abort(c.enclosingPosition, "call site does not have an enclosing class")
+ val runtimeUniverse = Select(Select(Select(Ident(newTermName("scala")), newTermName("reflect")), newTermName("runtime")), newTermName("universe"))
+ val currentMirror = Apply(Select(runtimeUniverse, newTermName("runtimeMirror")), List(Select(runtimeClass, newTermName("getClassLoader"))))
+ c.Expr[Nothing](currentMirror)(c.TypeTag.Nothing)
+ }
+ }
}
diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
index cd1a808823..a16b42dc47 100644
--- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
+++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
@@ -82,7 +82,6 @@ trait ScalaSettings extends AbsScalaSettings
val XlogImplicits = BooleanSetting ("-Xlog-implicits", "Show more detail on why some implicits are not applicable.")
val logImplicitConv = BooleanSetting ("-Xlog-implicit-conversions", "Print a message whenever an implicit conversion is inserted.")
val logReflectiveCalls = BooleanSetting("-Xlog-reflective-calls", "Print a message when a reflective method call is generated")
- val logRuntimeSplices = BooleanSetting("-Xlog-runtime-splices", "Print a message when Expr.eval or Expr.value cannot be resolved statically.")
val logFreeTerms = BooleanSetting ("-Xlog-free-terms", "Print a message when reification creates a free term.")
val logFreeTypes = BooleanSetting ("-Xlog-free-types", "Print a message when reification resorts to generating a free type.")
val maxClassfileName = IntSetting ("-Xmax-classfile-name", "Maximum filename length for generated classes", 255, Some((72, 255)), _ => None)
diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala
index ea66dbedd6..fde27a650a 100644
--- a/src/compiler/scala/tools/nsc/transform/Erasure.scala
+++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala
@@ -967,7 +967,7 @@ abstract class Erasure extends AddInterfaces
}
// Rewrite 5.getClass to ScalaRunTime.anyValClass(5)
else if (isPrimitiveValueClass(qual.tpe.typeSymbol))
- global.typer.typed(gen.mkRuntimeCall(nme.anyValClass, List(qual, typer.resolveErasureTag(qual.tpe.widen, tree.pos, true))))
+ global.typer.typed(gen.mkRuntimeCall(nme.anyValClass, List(qual, typer.resolveClassTag(tree.pos, qual.tpe.widen))))
else
tree
diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
index 8af12f3f10..db3d8b2785 100644
--- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala
+++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
@@ -419,7 +419,7 @@ abstract class UnCurry extends InfoTransform
val toArraySym = tree.tpe member nme.toArray
assert(toArraySym != NoSymbol)
def getArrayTag(tp: Type): Tree = {
- val tag = localTyper.resolveArrayTag(tp, tree.pos)
+ val tag = localTyper.resolveArrayTag(tree.pos, tp)
// Don't want bottom types getting any further than this (SI-4024)
if (tp.typeSymbol.isBottomClass) getArrayTag(AnyClass.tpe)
else if (!tag.isEmpty) tag
diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
index f3afa2d33f..9855284348 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
@@ -1294,8 +1294,8 @@ trait Implicits {
}
val tagInScope =
- if (full) resolveTypeTag(NoType, tp, pos, concrete = true)
- else resolveArrayTag(tp, pos)
+ if (full) resolveTypeTag(pos, NoType, tp, concrete = true, allowMaterialization = false)
+ else resolveArrayTag(pos, tp, allowMaterialization = false)
if (tagInScope.isEmpty) mot(tp, Nil, Nil)
else {
if (full) {
@@ -1307,7 +1307,7 @@ trait Implicits {
|to proceed put scala-reflect.jar on your compilation classpath and recompile.""".trim.stripMargin)
return SearchFailure
}
- if (resolveErasureTag(tp, pos, concrete = true) == EmptyTree) {
+ if (resolveClassTag(pos, tp, allowMaterialization = true) == EmptyTree) {
context.error(pos, s"""
|to create a manifest here, it is necessary to interoperate with the type tag `$tagInScope` in scope.
|however typetag -> manifest conversion requires a class tag for the corresponding type to be present.
diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
index 96fcdd793e..93991fe7d5 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
@@ -982,7 +982,7 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces {
if (typer.context.hasErrors) fail("typecheck against expected type", expanded)
macroLogVerbose("typechecked2:%n%s%n%s".format(typechecked, showRaw(typechecked)))
- typechecked
+ typechecked addAttachment MacroExpansionAttachment(expandee)
} finally {
openMacros = openMacros.tail
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Taggings.scala b/src/compiler/scala/tools/nsc/typechecker/Taggings.scala
deleted file mode 100644
index bbcfa2920b..0000000000
--- a/src/compiler/scala/tools/nsc/typechecker/Taggings.scala
+++ /dev/null
@@ -1,71 +0,0 @@
-package scala.tools.nsc
-package typechecker
-
-trait Taggings {
- self: Analyzer =>
-
- import global._
- import definitions._
-
- trait Tagging {
- self: Typer =>
-
- private def resolveTag(taggedTp: Type, pos: Position) = beforeTyper {
- inferImplicit(
- EmptyTree,
- taggedTp,
- /*reportAmbiguous =*/ true,
- /*isView =*/ false,
- /*context =*/ context,
- /*saveAmbiguousDivergent =*/ true,
- /*pos =*/ pos
- ).tree
- }
-
- /** Finds in scope or materializes an ArrayTag.
- * Should be used instead of ClassTag or ClassManifest every time compiler needs to create an array.
- *
- * @param tp Type we're looking an ArrayTag for, e.g. resolveArrayTag(IntClass.tpe, pos) will look for ArrayTag[Int].
- * @param pos Position for error reporting. Please, provide meaningful value.
- *
- * @returns Tree that represents an `scala.reflect.ArrayTag` for `tp` if everything is okay.
- * EmptyTree if the result contains unresolved (i.e. not spliced) type parameters and abstract type members.
- */
- def resolveArrayTag(tp: Type, pos: Position): Tree = {
- val taggedTp = appliedType(ArrayTagClass.typeConstructor, List(tp))
- resolveTag(taggedTp, pos)
- }
-
- /** Finds in scope or materializes an ErasureTag (if `concrete` is false) or a ClassTag (if `concrete` is true).
- * Should be used instead of ClassTag or ClassManifest every time compiler needs to persist an erasure.
- *
- * @param tp Type we're looking an ErasureTag for, e.g. resolveErasureTag(IntClass.tpe, pos, true) will look for ClassTag[Int].
- * @param pos Position for error reporting. Please, provide meaningful value.
- * @param concrete If true then the result must not contain unresolved (i.e. not spliced) type parameters and abstract type members.
- * If false then the function will always succeed (abstract types will be erased to their upper bounds).
- *
- * @returns Tree that represents an `scala.reflect.ErasureTag` for `tp` if everything is okay.
- * EmptyTree if `concrete` is true and the result contains unresolved (i.e. not spliced) type parameters and abstract type members.
- */
- def resolveErasureTag(tp: Type, pos: Position, concrete: Boolean): Tree = {
- val taggedTp = appliedType(if (concrete) ClassTagClass.typeConstructor else ???, List(tp))
- resolveTag(taggedTp, pos)
- }
-
- /** Finds in scope or materializes a TypeTag (if `concrete` is false) or a ConcreteTypeTag (if `concrete` is true).
- *
- * @param pre Prefix that represents a universe this type tag will be bound to.
- * @param tp Type we're looking a TypeTag for, e.g. resolveTypeTag(reflectMirrorPrefix, IntClass.tpe, pos, false) will look for scala.reflect.mirror.TypeTag[Int].
- * @param pos Position for error reporting. Please, provide meaningful value.
- * @param concrete If true then the result must not contain unresolved (i.e. not spliced) type parameters and abstract type members.
- * If false then the function will always succeed (abstract types will be reified as free types).
- *
- * @returns Tree that represents a `scala.reflect.TypeTag` for `tp` if everything is okay.
- * EmptyTree if `concrete` is true and the result contains unresolved (i.e. not spliced) type parameters and abstract type members.
- */
- def resolveTypeTag(pre: Type, tp: Type, pos: Position, concrete: Boolean): Tree = {
- val taggedTp = appliedType(singleType(pre, pre member (if (concrete) ConcreteTypeTagClass else TypeTagClass).name), List(tp))
- resolveTag(taggedTp, pos)
- }
- }
-} \ No newline at end of file
diff --git a/src/compiler/scala/tools/nsc/typechecker/Tags.scala b/src/compiler/scala/tools/nsc/typechecker/Tags.scala
new file mode 100644
index 0000000000..d371f02d1d
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/typechecker/Tags.scala
@@ -0,0 +1,86 @@
+package scala.tools.nsc
+package typechecker
+
+trait Tags {
+ self: Analyzer =>
+
+ import global._
+ import definitions._
+
+ trait Tag {
+ self: Typer =>
+
+ private def resolveTag(pos: Position, taggedTp: Type, allowMaterialization: Boolean) = beforeTyper {
+ def wrapper (tree: => Tree): Tree = if (allowMaterialization) (context.withMacrosEnabled[Tree](tree)) else (context.withMacrosDisabled[Tree](tree))
+ wrapper(inferImplicit(
+ EmptyTree,
+ taggedTp,
+ /*reportAmbiguous =*/ true,
+ /*isView =*/ false,
+ /*context =*/ context,
+ /*saveAmbiguousDivergent =*/ true,
+ /*pos =*/ pos
+ ).tree)
+ }
+
+ /** Finds in scope or materializes an ArrayTag.
+ * Should be used instead of ClassTag or ClassManifest every time compiler needs to create an array.
+ *
+ * @param pos Position for error reporting. Please, provide meaningful value.
+ * @param tp Type we're looking an ArrayTag for, e.g. resolveArrayTag(pos, IntClass.tpe) will look for ArrayTag[Int].
+ * @param allowMaterialization If true (default) then the resolver is allowed to launch materialization macros when there's no array tag in scope.
+ * If false then materialization macros are prohibited from running.
+ *
+ * @returns Tree that represents an `scala.reflect.ArrayTag` for `tp` if everything is okay.
+ * EmptyTree if `allowMaterialization` is false, and there is no array tag in scope.
+ * EmptyTree if the result contains unresolved (i.e. not spliced) type parameters and abstract type members.
+ */
+ def resolveArrayTag(pos: Position, tp: Type, allowMaterialization: Boolean = true): Tree = {
+ val taggedTp = appliedType(ArrayTagClass.typeConstructor, List(tp))
+ resolveTag(pos, taggedTp, allowMaterialization)
+ }
+
+ /** Finds in scope or materializes a ClassTag.
+ * Should be used instead of ClassManifest every time compiler needs to persist an erasure.
+ *
+ * Once upon a time, we had an `ErasureTag` which was to `ClassTag` the same that `TypeTag` is for `ConcreteTypeTag`.
+ * However we found out that we don't really need this concept, so it got removed.
+ *
+ * @param pos Position for error reporting. Please, provide meaningful value.
+ * @param tp Type we're looking a ClassTag for, e.g. resolveClassTag(pos, IntClass.tpe) will look for ClassTag[Int].
+ * @param allowMaterialization If true (default) then the resolver is allowed to launch materialization macros when there's no class tag in scope.
+ * If false then materialization macros are prohibited from running.
+ *
+ * @returns Tree that represents an `scala.reflect.ClassTag` for `tp` if everything is okay.
+ * EmptyTree if the result contains unresolved (i.e. not spliced) type parameters and abstract type members.
+ * EmptyTree if `allowMaterialization` is false, and there is no class tag in scope.
+ */
+ def resolveClassTag(pos: Position, tp: Type, allowMaterialization: Boolean = true): Tree = {
+ val taggedTp = appliedType(ClassTagClass.typeConstructor, List(tp))
+ resolveTag(pos, taggedTp, allowMaterialization)
+ }
+
+ /** Finds in scope or materializes a TypeTag (if `concrete` is false) or a ConcreteTypeTag (if `concrete` is true).
+ *
+ * @param pos Position for error reporting. Please, provide meaningful value.
+ * @param pre Prefix that represents a universe this type tag will be bound to.
+ * If `pre` is set to `NoType`, then any type tag in scope will do, regardless of its affiliation.
+ * If `pre` is set to `NoType`, and tag resolution involves materialization, then `mkBasisPrefix` will be used.
+ * @param tp Type we're looking a TypeTag for, e.g. resolveTypeTag(pos, reflectBasisPrefix, IntClass.tpe, false) will look for scala.reflect.basis.TypeTag[Int].
+ * @param concrete If true then the result must not contain unresolved (i.e. not spliced) type parameters and abstract type members.
+ * If false then the function will always succeed (abstract types will be reified as free types).
+ * @param allowMaterialization If true (default) then the resolver is allowed to launch materialization macros when there's no type tag in scope.
+ * If false then materialization macros are prohibited from running.
+ *
+ * @returns Tree that represents a `scala.reflect.TypeTag` for `tp` if everything is okay.
+ * EmptyTree if `concrete` is true and the result contains unresolved (i.e. not spliced) type parameters and abstract type members.
+ * EmptyTree if `allowMaterialization` is false, and there is no array tag in scope.
+ */
+ def resolveTypeTag(pos: Position, pre: Type, tp: Type, concrete: Boolean, allowMaterialization: Boolean = true): Tree = {
+ val tagSym = if (concrete) ConcreteTypeTagClass else TypeTagClass
+ val tagTp = if (pre == NoType) TypeRef(BaseUniverseClass.asTypeConstructor, tagSym, List(tp)) else singleType(pre, pre member tagSym.name)
+ val taggedTp = appliedType(tagTp, List(tp))
+ resolveTag(pos, taggedTp, allowMaterialization)
+ }
+ }
+} \ No newline at end of file
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index cc36ed7428..30202ed3b5 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -26,7 +26,7 @@ import util.Statistics._
* @author Martin Odersky
* @version 1.0
*/
-trait Typers extends Modes with Adaptations with Taggings {
+trait Typers extends Modes with Adaptations with Tags {
self: Analyzer =>
import global._
@@ -96,7 +96,7 @@ trait Typers extends Modes with Adaptations with Taggings {
// this is disabled by: -Xoldpatmat, scaladoc or interactive compilation
@inline private def newPatternMatching = opt.virtPatmat && !forScaladoc && !forInteractive // && (phase.id < currentRun.uncurryPhase.id)
- abstract class Typer(context0: Context) extends TyperDiagnostics with Adaptation with Tagging with TyperContextErrors {
+ abstract class Typer(context0: Context) extends TyperDiagnostics with Adaptation with Tag with TyperContextErrors {
import context0.unit
import typeDebug.{ ptTree, ptBlock, ptLine }
import TyperErrorGen._
@@ -2512,11 +2512,18 @@ trait Typers extends Modes with Adaptations with Taggings {
}
}
- def typedRefinement(stats: List[Tree]) {
+ def typedRefinement(templ: Template) {
+ val stats = templ.body
namer.enterSyms(stats)
// need to delay rest of typedRefinement to avoid cyclic reference errors
unit.toCheck += { () =>
val stats1 = typedStats(stats, NoSymbol)
+ // this code kicks in only after typer, so `stats` will never be filled in time
+ // as a result, most of compound type trees with non-empty stats will fail to reify
+ // [Eugene++] todo. investigate whether something can be done about this
+ val att = templ.attachments.get[CompoundTypeTreeOriginalAttachment].getOrElse(CompoundTypeTreeOriginalAttachment(Nil, Nil))
+ templ.removeAttachment[CompoundTypeTreeOriginalAttachment]
+ templ addAttachment att.copy(stats = stats1)
for (stat <- stats1 if stat.isDef) {
val member = stat.symbol
if (!(context.owner.ancestors forall
@@ -4584,7 +4591,8 @@ trait Typers extends Modes with Adaptations with Taggings {
val decls = newScope
//Console.println("Owner: " + context.enclClass.owner + " " + context.enclClass.owner.id)
val self = refinedType(parents1 map (_.tpe), context.enclClass.owner, decls, templ.pos)
- newTyper(context.make(templ, self.typeSymbol, decls)).typedRefinement(templ.body)
+ newTyper(context.make(templ, self.typeSymbol, decls)).typedRefinement(templ)
+ templ addAttachment CompoundTypeTreeOriginalAttachment(parents1, Nil) // stats are set elsewhere
tree setType self
}
}
@@ -4856,7 +4864,7 @@ trait Typers extends Modes with Adaptations with Taggings {
val Some((level, componentType)) = erasure.GenericArray.unapply(tpt.tpe)
val tagType = List.iterate(componentType, level)(tpe => appliedType(ArrayClass.asType, List(tpe))).last
val newArrayApp = atPos(tree.pos) {
- val tag = resolveArrayTag(tagType, tree.pos)
+ val tag = resolveArrayTag(tree.pos, tagType)
if (tag.isEmpty) MissingArrayTagError(tree, tagType)
else new ApplyToImplicitArgs(Select(tag, nme.newArray), args)
}
diff --git a/src/compiler/scala/tools/reflect/FastTrack.scala b/src/compiler/scala/tools/reflect/FastTrack.scala
index 8658e3225d..534f6de682 100644
--- a/src/compiler/scala/tools/reflect/FastTrack.scala
+++ b/src/compiler/scala/tools/reflect/FastTrack.scala
@@ -1,6 +1,7 @@
package scala.tools
package reflect
+import scala.reflect.makro.runtime.ContextReifiers
import scala.reflect.reify.Taggers
import scala.tools.nsc.typechecker.{Analyzer, Macros}
@@ -15,6 +16,7 @@ trait FastTrack {
import language.implicitConversions
private implicit def context2taggers(c0: MacroContext) : Taggers { val c: c0.type } = new { val c: c0.type = c0 } with Taggers
+ private implicit def context2contextreifiers(c0: MacroContext) : ContextReifiers { val c: c0.type } = new { val c: c0.type = c0 } with ContextReifiers
implicit def fastTrackEntry2MacroRuntime(entry: FastTrackEntry): MacroRuntime = args => entry.run(args)
type FastTrackExpander = PartialFunction[(MacroContext, Tree), Tree]
@@ -36,10 +38,11 @@ trait FastTrack {
implicit class BindTo(sym: Symbol) { def bindTo(expander: FastTrackExpander): Unit = if (sym != NoSymbol) registry += sym -> FastTrackEntry(sym, expander) }
MacroInternal_materializeArrayTag bindTo { case (c, Apply(TypeApply(_, List(tt)), List(u))) => c.materializeArrayTag(u, tt.tpe) }
MacroInternal_materializeClassTag bindTo { case (c, Apply(TypeApply(_, List(tt)), List(u))) => c.materializeClassTag(u, tt.tpe) }
- MacroInternal_materializeTypeTag bindTo { case (c, Apply(TypeApply(_, List(tt)), List(u))) => c.materializeTypeTag(u, tt.tpe, concrete = false) }
- MacroInternal_materializeConcreteTypeTag bindTo { case (c, Apply(TypeApply(_, List(tt)), List(u))) => c.materializeTypeTag(u, tt.tpe, concrete = true) }
- ApiUniverseReify bindTo { case (c, Apply(TypeApply(_, List(tt)), List(expr))) => c.materializeExpr(c.prefix.tree, expr) }
- MacroContextReify bindTo { case (c, Apply(TypeApply(_, List(tt)), List(expr))) => c.materializeExpr(c.prefix.tree, expr) }
+ MacroInternal_materializeTypeTag bindTo { case (c, Apply(TypeApply(_, List(tt)), List(u))) => c.materializeTypeTag(u, EmptyTree, tt.tpe, concrete = false) }
+ MacroInternal_materializeConcreteTypeTag bindTo { case (c, Apply(TypeApply(_, List(tt)), List(u))) => c.materializeTypeTag(u, EmptyTree, tt.tpe, concrete = true) }
+ ApiUniverseReify bindTo { case (c, Apply(TypeApply(_, List(tt)), List(expr))) => c.materializeExpr(c.prefix.tree, EmptyTree, expr) }
+ MacroContextReify bindTo { case (c, Apply(TypeApply(_, List(tt)), List(expr))) => c.materializeExprForMacroContext(c.prefix.tree, expr) }
+ ReflectRuntimeCurrentMirror bindTo { case (c, _) => scala.reflect.runtime.Macros.currentMirror(c).tree }
registry
}
} \ No newline at end of file
diff --git a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala
index 3ef2337e0f..741f1b268f 100644
--- a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala
+++ b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala
@@ -79,7 +79,7 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf =>
var name = ft.name.toString
val namesakes = freeTerms takeWhile (_ != ft) filter (ft2 => ft != ft2 && ft.name == ft2.name)
if (namesakes.length > 0) name += ("$" + (namesakes.length + 1))
- freeTermNames += (ft -> newTermName(name + nme.MIRROR_FREE_VALUE_SUFFIX))
+ freeTermNames += (ft -> newTermName(name + nme.REIFY_FREE_VALUE_SUFFIX))
})
var expr = new Transformer {
override def transform(tree: Tree): Tree =
diff --git a/src/library/scala/reflect/api/StandardNames.scala b/src/library/scala/reflect/api/StandardNames.scala
index 80aed04073..9ec66b8531 100644
--- a/src/library/scala/reflect/api/StandardNames.scala
+++ b/src/library/scala/reflect/api/StandardNames.scala
@@ -47,12 +47,17 @@ trait StandardNames extends base.StandardNames {
val FAKE_LOCAL_THIS: TermName
val INITIALIZER: TermName
val LAZY_LOCAL: TermName
- val MIRROR_FREE_PREFIX: NameType
- val MIRROR_FREE_THIS_SUFFIX: NameType
- val MIRROR_FREE_VALUE_SUFFIX: NameType
+ val UNIVERSE_BUILD: NameType
+ val UNIVERSE_BUILD_PREFIX: NameType
+ val UNIVERSE_PREFIX: NameType
+ val UNIVERSE_SHORT: NameType
val MIRROR_PREFIX: NameType
val MIRROR_SHORT: NameType
- val MIRROR_SYMDEF_PREFIX: NameType
+ val MIRROR_UNTYPED: NameType
+ val REIFY_FREE_PREFIX: NameType
+ val REIFY_FREE_THIS_SUFFIX: NameType
+ val REIFY_FREE_VALUE_SUFFIX: NameType
+ val REIFY_SYMDEF_PREFIX: NameType
val MIXIN_CONSTRUCTOR: TermName
val MODULE_INSTANCE_FIELD: TermName
val OUTER: TermName
@@ -147,6 +152,8 @@ trait StandardNames extends base.StandardNames {
val REFINE_CLASS_NAME: TypeName
val REPEATED_PARAM_CLASS_NAME: TypeName
val WILDCARD_STAR: TypeName
+ val REIFY_TYPECREATOR_PREFIX: NameType
+ val REIFY_TREECREATOR_PREFIX: NameType
def dropSingletonName(name: Name): TypeName
def implClassName(name: Name): TypeName
diff --git a/src/library/scala/reflect/makro/Context.scala b/src/library/scala/reflect/makro/Context.scala
index 58fd0d3df3..09cd96664c 100644
--- a/src/library/scala/reflect/makro/Context.scala
+++ b/src/library/scala/reflect/makro/Context.scala
@@ -34,6 +34,6 @@ trait Context extends Aliases
val prefix: Expr[PrefixType]
/** Alias to the underlying mirror's reify */
- // implementation is magically hardwired to `scala.reflect.reify.Taggers`
+ // implementation is magically hardwired to `scala.reflect.makro.runtime.ContextReifiers`
def reify[T](expr: T): Expr[T] = macro ???
}
diff --git a/src/library/scala/reflect/makro/Reifiers.scala b/src/library/scala/reflect/makro/Reifiers.scala
index 427b68f2d7..535aaadc3d 100644
--- a/src/library/scala/reflect/makro/Reifiers.scala
+++ b/src/library/scala/reflect/makro/Reifiers.scala
@@ -3,15 +3,23 @@ package scala.reflect.makro
trait Reifiers {
self: Context =>
- /** Reification prefix that refers to the standard reflexive mirror, ``scala.reflect.mirror''.
+ /** Reification prefix that refers to the base reflexive universe, ``scala.reflect.basis''.
* Providing it for the ``prefix'' parameter of ``reifyTree'' or ``reifyType'' will create a tree that can be inspected at runtime.
*/
- val reflectMirrorPrefix: Tree
+ val basisUniverse: Tree
+
+ /** Reification prefix that refers to the runtime reflexive universe, ``scala.reflect.runtime.universe''.
+ * Providing it for the ``prefix'' parameter of ``reifyTree'' or ``reifyType'' will create a full-fledged tree that can be inspected at runtime.
+ */
+ val runtimeUniverse: Tree
/** Given a tree, generate a tree that when compiled and executed produces the original tree.
- * The produced tree will be bound to the mirror specified by ``prefix'' (also see ``reflectMirrorPrefix'').
* For more information and examples see the documentation for ``Universe.reify''.
*
+ * The produced tree will be bound to the specified ``universe'' and ``mirror''.
+ * Possible values for ``universe'' include ``basisUniverse'' and ``runtimeUniverse''.
+ * Possible values for ``mirror'' include ``EmptyTree'' (in that case the reifier will automatically pick an appropriate mirror).
+ *
* This function is deeply connected to ``Universe.reify'', a macro that reifies arbitrary expressions into runtime trees.
* They do very similar things (``Universe.reify'' calls ``Context.reifyTree'' to implement itself), but they operate on different metalevels (see below).
*
@@ -40,19 +48,24 @@ trait Reifiers {
* Typical usage of this function is to retain some of the trees received/created by a macro
* into the form that can be inspected (via pattern matching) or compiled/run (by a reflective ToolBox) during the runtime.
*/
- def reifyTree(prefix: Tree, tree: Tree): Tree
+ def reifyTree(universe: Tree, mirror: Tree, tree: Tree): Tree
/** Given a type, generate a tree that when compiled and executed produces the original type.
- * The produced tree will be bound to the mirror specified by ``prefix'' (also see ``reflectMirrorPrefix'').
+ * The produced tree will be bound to the specified ``universe'' and ``mirror''.
* For more information and examples see the documentation for ``Context.reifyTree'' and ``Universe.reify''.
*/
- def reifyType(prefix: Tree, tpe: Type, dontSpliceAtTopLevel: Boolean = false, concrete: Boolean = false): Tree
+ def reifyType(universe: Tree, mirror: Tree, tpe: Type, concrete: Boolean = false): Tree
/** Given a type, generate a tree that when compiled and executed produces the runtime class of the original type.
* If ``concrete'' is true, then this function will bail on types, who refer to abstract types (like `ClassTag` does).
*/
def reifyRuntimeClass(tpe: Type, concrete: Boolean = true): Tree
+ /** Given a type, generate a tree that when compiled and executed produces the runtime class of the enclosing class or module.
+ * Returns `EmptyTree` if there does not exist an enclosing class or module.
+ */
+ def reifyEnclosingRuntimeClass: Tree
+
/** Undoes reification of a tree.
*
* This reversion doesn't simply restore the original tree (that would lose the context of reification),