summaryrefslogtreecommitdiff
path: root/src/compiler
diff options
context:
space:
mode:
authorEugene Burmako <xeno.by@gmail.com>2012-04-14 21:11:37 +0200
committerEugene Burmako <xeno.by@gmail.com>2012-04-14 21:11:37 +0200
commit5e4c47f33b8e25feb59ab4599231b1b8d3150de8 (patch)
treeff2ded10d14c5a6e859ac216e60244029a17a505 /src/compiler
parent3a2901da406f2478b5634b0636e56de9c4cd676d (diff)
downloadscala-5e4c47f33b8e25feb59ab4599231b1b8d3150de8.tar.gz
scala-5e4c47f33b8e25feb59ab4599231b1b8d3150de8.tar.bz2
scala-5e4c47f33b8e25feb59ab4599231b1b8d3150de8.zip
implements reification of tough types
Diffstat (limited to 'src/compiler')
-rw-r--r--src/compiler/scala/reflect/internal/StdNames.scala1
-rw-r--r--src/compiler/scala/reflect/internal/Symbols.scala4
-rw-r--r--src/compiler/scala/reflect/internal/TreeInfo.scala16
-rw-r--r--src/compiler/scala/reflect/internal/Types.scala33
-rw-r--r--src/compiler/scala/reflect/reify/codegen/AnnotationInfos.scala56
-rw-r--r--src/compiler/scala/reflect/reify/codegen/Symbols.scala114
-rw-r--r--src/compiler/scala/reflect/reify/codegen/Trees.scala20
-rw-r--r--src/compiler/scala/reflect/reify/codegen/Types.scala141
-rw-r--r--src/compiler/scala/reflect/reify/phases/Metalevels.scala2
-rw-r--r--src/compiler/scala/reflect/reify/phases/Reify.scala4
-rw-r--r--src/compiler/scala/tools/nsc/util/Position.scala10
11 files changed, 261 insertions, 140 deletions
diff --git a/src/compiler/scala/reflect/internal/StdNames.scala b/src/compiler/scala/reflect/internal/StdNames.scala
index ac2cf178bf..bf468affe6 100644
--- a/src/compiler/scala/reflect/internal/StdNames.scala
+++ b/src/compiler/scala/reflect/internal/StdNames.scala
@@ -206,6 +206,7 @@ trait StdNames extends NameManglers { self: SymbolTable =>
val MIRROR_FREE_PREFIX: NameType = "free$"
val MIRROR_FREE_THIS_SUFFIX: NameType = "$this"
val MIRROR_FREE_VALUE_SUFFIX: NameType = "$value"
+ val MIRROR_SYMDEF_PREFIX: NameType = "symdef$"
val MIXIN_CONSTRUCTOR: NameType = "$init$"
val MODULE_INSTANCE_FIELD: NameType = NameTransformer.MODULE_INSTANCE_NAME // "MODULE$"
val OUTER: NameType = "$outer"
diff --git a/src/compiler/scala/reflect/internal/Symbols.scala b/src/compiler/scala/reflect/internal/Symbols.scala
index 3bb57cea04..c9947c3c09 100644
--- a/src/compiler/scala/reflect/internal/Symbols.scala
+++ b/src/compiler/scala/reflect/internal/Symbols.scala
@@ -64,6 +64,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
this: Symbol =>
def kind: String = kindString
+ def isExistential: Boolean = this.isExistentiallyBound
def newNestedSymbol(name: Name, pos: Position, newFlags: Long, isClass: Boolean): Symbol = name match {
case n: TermName => newTermSymbol(n, pos, newFlags)
@@ -897,8 +898,10 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
if (!owner.isLocatable) return false
if (owner.isTerm) return false
+ if (isLocalDummy) return false
if (isType && isNonClassType) return false
+ if (isRefinementClass) return false
return true
}
@@ -2965,7 +2968,6 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
override def isFreeTerm = true
}
- // [Eugene] the NoSymbol origin works for type parameters. what about existential free types?
class FreeType(name0: TypeName, value0: => Any, val origin: String) extends TypeSkolem(NoSymbol, NoPosition, name0, NoSymbol) {
def value = value0
override def isFreeType = true
diff --git a/src/compiler/scala/reflect/internal/TreeInfo.scala b/src/compiler/scala/reflect/internal/TreeInfo.scala
index a8cca1625f..039c8e557a 100644
--- a/src/compiler/scala/reflect/internal/TreeInfo.scala
+++ b/src/compiler/scala/reflect/internal/TreeInfo.scala
@@ -590,7 +590,7 @@ abstract class TreeInfo {
}
object Reified {
- def unapply(tree: Tree): Option[(Tree, List[ValDef], Tree)] = tree match {
+ 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) =>
@@ -601,16 +601,16 @@ abstract class TreeInfo {
}
object ReifiedTree {
- def unapply(tree: Tree): Option[(Tree, List[ValDef], Tree, Tree)] = tree match {
+ def unapply(tree: Tree): Option[(Tree, List[Tree], Tree, Tree)] = tree match {
case reifee @ Block((mrDef @ ValDef(_, _, _, _)) :: symbolTable, Apply(Apply(_, List(tree)), List(Apply(_, List(tpe))))) if mrDef.name == nme.MIRROR_SHORT =>
- Some(reifee, symbolTable map (_.asInstanceOf[ValDef]), tree, tpe)
+ Some(reifee, symbolTable, tree, tpe)
case _ =>
None
}
}
object InlineableTreeSplice {
- def unapply(tree: Tree): Option[(Tree, List[ValDef], Tree, Tree, Symbol)] = tree match {
+ def unapply(tree: Tree): Option[(Tree, List[Tree], Tree, Tree, Symbol)] = tree match {
case select @ Select(ReifiedTree(splicee, symbolTable, tree, tpe), _) if select.symbol == ExprEval || select.symbol == ExprValue =>
Some(splicee, symbolTable, tree, tpe, select.symbol)
case _ =>
@@ -619,7 +619,7 @@ abstract class TreeInfo {
}
object InlinedTreeSplice {
- def unapply(tree: Tree): Option[(Tree, List[ValDef], Tree, Tree)] = tree match {
+ def unapply(tree: Tree): Option[(Tree, List[Tree], Tree, Tree)] = tree match {
case Select(ReifiedTree(splicee, symbolTable, tree, tpe), name) if name == ExprTree.name =>
Some(splicee, symbolTable, tree, tpe)
case _ =>
@@ -628,16 +628,16 @@ abstract class TreeInfo {
}
object ReifiedType {
- def unapply(tree: Tree): Option[(Tree, List[ValDef], Tree)] = tree match {
+ def unapply(tree: Tree): Option[(Tree, List[Tree], Tree)] = tree match {
case reifee @ Block((mrDef @ ValDef(_, _, _, _)) :: symbolTable, Apply(_, List(tpe))) if mrDef.name == nme.MIRROR_SHORT =>
- Some(reifee, symbolTable map (_.asInstanceOf[ValDef]), tpe)
+ Some(reifee, symbolTable, tpe)
case _ =>
None
}
}
object InlinedTypeSplice {
- def unapply(tree: Tree): Option[(Tree, List[ValDef], Tree)] = tree match {
+ def unapply(tree: Tree): Option[(Tree, List[Tree], Tree)] = tree match {
case Select(ReifiedType(splicee, symbolTable, tpe), name) if name == TypeTagTpe.name =>
Some(splicee, symbolTable, tpe)
case _ =>
diff --git a/src/compiler/scala/reflect/internal/Types.scala b/src/compiler/scala/reflect/internal/Types.scala
index 3efbe4b4df..d7c90d597c 100644
--- a/src/compiler/scala/reflect/internal/Types.scala
+++ b/src/compiler/scala/reflect/internal/Types.scala
@@ -266,6 +266,35 @@ trait Types extends api.Types { self: SymbolTable =>
def typeArguments = typeArgs
def erasure = transformedType(this)
def substituteTypes(from: List[Symbol], to: List[Type]): Type = subst(from, to)
+
+ // [Eugene] to be discussed and refactored
+ def isConcrete = {
+ def notConcreteSym(sym: Symbol) =
+ sym.isAbstractType && !sym.isExistential
+
+ def notConcreteTpe(tpe: Type): Boolean = tpe match {
+ case ThisType(_) => false
+ case SuperType(_, _) => false
+ case SingleType(pre, sym) => notConcreteSym(sym)
+ case ConstantType(_) => false
+ case TypeRef(_, sym, _) => notConcreteSym(sym)
+ case RefinedType(_, _) => false
+ case ExistentialType(_, _) => false
+ case AnnotatedType(_, tp, _) => notConcreteTpe(tp)
+ case _ => true
+ }
+
+ !notConcreteTpe(this)
+ }
+
+ // [Eugene] is this comprehensive?
+ // the only thingies that we want to splice are: 1) type parameters, 2) type members
+ // the thingies that we don't want to splice are: 1) concrete types (obviously), 2) existential skolems
+ // this check seems to cover them all, right?
+ // todo. after we discuss this, move the check to subclasses
+ def isSpliceable = {
+ this.isInstanceOf[TypeRef] && typeSymbol.isAbstractType && !typeSymbol.isExistential
+ }
}
/** The base class for all types */
@@ -2147,7 +2176,7 @@ trait Types extends api.Types { self: SymbolTable =>
sym.isPackageClass
|| pre.isGround && args.forall(_.isGround)
)
-
+
def etaExpand: Type = {
// must initialise symbol, see test/files/pos/ticket0137.scala
val tpars = initializedTypeParams
@@ -2763,7 +2792,7 @@ trait Types extends api.Types { self: SymbolTable =>
zippedArgs map { case (p, a) => p.name + "=" + a } mkString (origin + "[", ", ", "]")
)
}
-
+
trait UntouchableTypeVar extends TypeVar {
override def untouchable = true
override def isGround = true
diff --git a/src/compiler/scala/reflect/reify/codegen/AnnotationInfos.scala b/src/compiler/scala/reflect/reify/codegen/AnnotationInfos.scala
new file mode 100644
index 0000000000..1d218317dc
--- /dev/null
+++ b/src/compiler/scala/reflect/reify/codegen/AnnotationInfos.scala
@@ -0,0 +1,56 @@
+package scala.reflect.reify
+package codegen
+
+trait AnnotationInfos {
+ self: Reifier =>
+
+ import mirror._
+ 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
+ // why is that bad? take a look inside
+ def reifyAnnotationInfo(ann: AnnotationInfo): Tree = {
+ val reifiedArgs = ann.args map { arg =>
+ val saved1 = reifyTreeSymbols
+ val saved2 = reifyTreeTypes
+
+ try {
+ // one more quirk of reifying annotations
+ //
+ // when reifying AnnotatedTypes we need to reify all the types and symbols of inner ASTs
+ // that's because a lot of logic expects post-typer trees to have non-null tpes
+ //
+ // Q: reified trees are pre-typer, so there's shouldn't be a problem.
+ // 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
+
+ // todo. every AnnotationInfo is an island, entire of itself
+ // no regular Traverser or Transformer can reach it
+ // hence we need to run its contents through the entire reification pipeline
+ // e.g. to apply reshaping or to check metalevels
+ reify(arg)
+ } finally {
+ reifyTreeSymbols = saved1
+ reifyTreeTypes = saved2
+ }
+ }
+
+ def reifyClassfileAnnotArg(arg: ClassfileAnnotArg): Tree = arg match {
+ case LiteralAnnotArg(const) =>
+ mirrorFactoryCall(nme.LiteralAnnotArg, reifyProduct(const))
+ case ArrayAnnotArg(args) =>
+ mirrorFactoryCall(nme.ArrayAnnotArg, scalaFactoryCall(nme.Array, args map reifyClassfileAnnotArg: _*))
+ case NestedAnnotArg(ann) =>
+ mirrorFactoryCall(nme.NestedAnnotArg, reifyAnnotationInfo(ann))
+ }
+
+ // if you reify originals of anns, you get SO when trying to reify AnnotatedTypes, so screw it - after all, it's not that important
+ val reifiedAssocs = ann.assocs map (assoc => scalaFactoryCall(nme.Tuple2, reify(assoc._1), reifyClassfileAnnotArg(assoc._2)))
+ mirrorFactoryCall(nme.AnnotationInfo, reify(ann.atp), mkList(reifiedArgs), mkList(reifiedAssocs))
+ }
+} \ No newline at end of file
diff --git a/src/compiler/scala/reflect/reify/codegen/Symbols.scala b/src/compiler/scala/reflect/reify/codegen/Symbols.scala
index 3328f5e402..2fc0002838 100644
--- a/src/compiler/scala/reflect/reify/codegen/Symbols.scala
+++ b/src/compiler/scala/reflect/reify/codegen/Symbols.scala
@@ -46,13 +46,8 @@ trait Symbols {
}
} else {
// todo. make sure that free methods and free local defs work correctly
- if (sym.isTerm) {
- if (reifyDebug) println("Free term" + (if (sym.isCapturedVariable) " (captured)" else "") + ": " + sym)
- reifyFreeTerm(sym, Ident(sym))
- } else {
- if (reifyDebug) println("Free type: " + sym)
- reifyFreeType(sym, Ident(sym))
- }
+ if (sym.isTerm) reifyFreeTerm(sym, Ident(sym))
+ else reifyFreeType(sym, Ident(sym))
}
}
@@ -61,13 +56,16 @@ trait Symbols {
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, mirrorCall(nme.newFreeTerm, reify(sym.name.toString), reify(capturedTpe), capturedValue, reify(origin(sym))))
+ locallyReify(sym, name, mirrorCall(nme.newFreeTerm, reify(sym.name.toString), reify(capturedTpe), capturedValue, reify(origin(sym))))
} else {
- locallyReify(sym, mirrorCall(nme.newFreeTerm, reify(sym.name.toString), reify(sym.tpe), value, reify(origin(sym))))
+ locallyReify(sym, name, mirrorCall(nme.newFreeTerm, reify(sym.name.toString), reify(sym.tpe), value, reify(origin(sym))))
}
}
@@ -76,36 +74,104 @@ trait Symbols {
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))))
// todo. implement info reification for free types: type bounds, HK-arity, whatever else that can be useful
- locallyReify(sym, mirrorCall(nme.newFreeType, reify(sym.name.toString), reify(sym.info), phantomTypeTag, reify(origin(sym))))
+ locallyReify(sym, name, mirrorCall(nme.newFreeType, reify(sym.name.toString), reify(sym.info), phantomTypeTag, 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[ValDef]()
+ private val localReifications = ArrayBuffer[Tree]()
private val locallyReified = Map[Symbol, Tree]()
- def symbolTable: List[ValDef] = localReifications.toList
- def symbolTable_=(newSymbolTable: List[ValDef]): Unit = {
+ 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 freedef @ FreeDef(_, name, binding, _) =>
- if (!(locallyReified contains binding.symbol)) {
- localReifications += freedef
- locallyReified(binding.symbol) = Ident(name)
+ case entry =>
+ val att = entry.attachment
+ att match {
+ case sym: Symbol =>
+ // 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 locallyReify(sym: Symbol, reificode: => Tree): Tree = {
+ 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 Apply(Select(_, flavor), _) = reified
- // [Eugene] name clashes are impossible, right?
- var name = newTermName(nme.MIRROR_FREE_PREFIX + sym.name)
- if (flavor == nme.newFreeTerm && sym.isType) name = name.append(nme.MIRROR_FREE_THIS_SUFFIX);
- // todo. also reify annotations for free vars
- localReifications += ValDef(NoMods, name, TypeTree(), reified)
+ 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) setAttachment 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)
+ reified.attachment match {
+ case sym: Symbol => 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 {
+ val rset = Apply(Select(locallyReified(sym), nme.setTypeSignature), List(reifyType(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/Trees.scala b/src/compiler/scala/reflect/reify/codegen/Trees.scala
index 22f42aea49..5ad53c0009 100644
--- a/src/compiler/scala/reflect/reify/codegen/Trees.scala
+++ b/src/compiler/scala/reflect/reify/codegen/Trees.scala
@@ -8,6 +8,11 @@ trait Trees {
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
+
/**
* Reify a tree.
* For internal use only, use ``reified'' instead.
@@ -59,6 +64,17 @@ trait Trees {
reifyProduct(tree)
}
+ // usually we don't reify symbols/types, because they can be re-inferred during subsequent reflective compilation
+ // 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(reifySymRef(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(reifyType(tree.tpe)))
+ }
+
rtree
}
@@ -82,7 +98,7 @@ trait Trees {
case InlinedTreeSplice(_, inlinedSymbolTable, tree, _) =>
if (reifyDebug) println("inlining the splicee")
// all free vars local to the enclosing reifee should've already been inlined by ``Metalevels''
- inlinedSymbolTable foreach { case freedef @ FreeDef(_, _, binding, _) => assert(!binding.symbol.isLocalToReifee, freedef) }
+ inlinedSymbolTable collect { case freedef @ FreeDef(_, _, binding, _) if binding.symbol.isLocalToReifee => assert(false, freedef) }
symbolTable ++= inlinedSymbolTable
tree
case tree =>
@@ -152,7 +168,7 @@ trait Trees {
val tpe = tpe0.dealias
if (reifyDebug) println("reifying bound type %s (underlying type is %s, dealiased is %s)".format(sym0, tpe0, tpe))
- if (eligibleForSplicing(tpe)) {
+ if (tpe.isSpliceable) {
val spliced = spliceType(tpe)
if (spliced == EmptyTree) {
if (reifyDebug) println("splicing failed: reify as is")
diff --git a/src/compiler/scala/reflect/reify/codegen/Types.scala b/src/compiler/scala/reflect/reify/codegen/Types.scala
index 9bc113e8a4..948728088e 100644
--- a/src/compiler/scala/reflect/reify/codegen/Types.scala
+++ b/src/compiler/scala/reflect/reify/codegen/Types.scala
@@ -55,11 +55,9 @@ trait Types {
case tpe @ NullaryMethodType(restpe) =>
reifyProduct(tpe)
case tpe @ AnnotatedType(anns, underlying, selfsym) =>
-// reifyAnnotatedType(tpe)
- CannotReifyType(tpe)
+ reifyAnnotatedType(tpe)
case _ =>
-// reifyToughType(tpe)
- CannotReifyType(tpe)
+ reifyToughType(tpe)
}
}
@@ -70,13 +68,6 @@ trait Types {
var maybeConcrete = true
var definitelyConcrete = true
- def eligibleForSplicing(tpe: Type): Boolean = {
- // [Eugene] is this comprehensive?
- // the only thingies that we want to splice are: 1) type parameters, 2) type members
- // this check seems to cover them all, right?
- tpe.isInstanceOf[TypeRef] && tpe.typeSymbol.isAbstractType
- }
-
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]())
@@ -84,7 +75,7 @@ trait Types {
}
def spliceType(tpe: Type): Tree = {
- if (eligibleForSplicing(tpe)) {
+ if (tpe.isSpliceable) {
if (reifyDebug) println("splicing " + tpe)
if (spliceTypesEnabled) {
@@ -113,7 +104,7 @@ trait Types {
splice match {
case InlinedTypeSplice(_, inlinedSymbolTable, tpe) =>
// all free vars local to the enclosing reifee should've already been inlined by ``Metalevels''
- inlinedSymbolTable foreach { case freedef @ FreeDef(_, _, binding, _) => assert(!binding.symbol.isLocalToReifee, freedef) }
+ inlinedSymbolTable collect { case freedef @ FreeDef(_, _, binding, _) if binding.symbol.isLocalToReifee => assert(false, freedef) }
symbolTable ++= inlinedSymbolTable
reifyTrace("inlined the splicee: ")(tpe)
case tpe =>
@@ -134,93 +125,39 @@ trait Types {
EmptyTree
}
- // yet another thingie disabled for simplicity
- // in principle, we could retain and reify AnnotatedTypes
- // but that'd require reifying every type and symbol inside ann.args
- // however, since we've given up on tough types for the moment, the former would be problematic
-// private def reifyAnnotatedType(tpe: AnnotatedType): Tree = {
-// // ``Reshaper'' transforms annotation infos from symbols back into Modifier.annotations, which are trees
-// // so the only place on Earth that can lead to reification of AnnotationInfos is the Ay Tee Land
-// // therefore this function is as local as possible, don't move it out of this scope
-// def reifyAnnotationInfo(ann: AnnotationInfo): Tree = {
-// val reifiedArgs = ann.args map { arg =>
-// val saved1 = reifyTreeSymbols
-// val saved2 = reifyTreeTypes
-//
-// try {
-// // one more quirk of reifying annotations
-// //
-// // when reifying AnnotatedTypes we need to reify all the types and symbols of inner ASTs
-// // that's because a lot of logic expects post-typer trees to have non-null tpes
-// //
-// // Q: reified trees are pre-typer, so there's shouldn't be a problem.
-// // 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
-//
-// // todo. every AnnotationInfo is an island, entire of itself
-// // no regular Traverser or Transformer can reach it
-// // hence we need to run its contents through the entire reification pipeline
-// // e.g. to apply reshaping or to check metalevels
-// reify(arg)
-// } finally {
-// reifyTreeSymbols = saved1
-// reifyTreeTypes = saved2
-// }
-// }
-//
-// def reifyClassfileAnnotArg(arg: ClassfileAnnotArg): Tree = arg match {
-// case LiteralAnnotArg(const) =>
-// mirrorFactoryCall(nme.LiteralAnnotArg, reifyProduct(const))
-// case ArrayAnnotArg(args) =>
-// mirrorFactoryCall(nme.ArrayAnnotArg, scalaFactoryCall(nme.Array, args map reifyClassfileAnnotArg: _*))
-// case NestedAnnotArg(ann) =>
-// mirrorFactoryCall(nme.NestedAnnotArg, reifyAnnotationInfo(ann))
-// }
-//
-// // if you reify originals of anns, you get SO when trying to reify AnnotatedTypes, so screw it - after all, it's not that important
-// val reifiedAssocs = ann.assocs map (assoc => scalaFactoryCall(nme.Tuple2, reify(assoc._1), reifyClassfileAnnotArg(assoc._2)))
-// mirrorFactoryCall(nme.AnnotationInfo, reify(ann.atp), mkList(reifiedArgs), mkList(reifiedAssocs))
-// }
-//
-// val AnnotatedType(anns, underlying, selfsym) = tpe
-// mirrorFactoryCall(nme.AnnotatedType, mkList(anns map reifyAnnotationInfo), reify(underlying), reify(selfsym))
-// }
-
- // previous solution to reifying tough types involved creating dummy symbols (see ``registerReifiableSymbol'' calls below)
- // however such symbols lost all the connections with their origins and became almost useless, except for typechecking
- // hence this approach was replaced by less powerful, but more principled one based on ``reifyFreeType''
- // it's possible that later on we will revise and revive ``reifyToughType'', but for now it's disabled under an implementation restriction
-// /** Reify a tough type, i.e. the one that leads to creation of auxiliary symbols */
-// // This is the uncharted territory in the reifier
-// private def reifyToughType(tpe: Type): Tree = {
-// if (reifyDebug) println("tough type: %s (%s)".format(tpe, tpe.kind))
-//
-// def reifyScope(scope: Scope): Tree = {
-// scope foreach registerReifiableSymbol
-// mirrorCall(nme.newScopeWith, scope.toList map reify: _*)
-// }
-//
-// tpe match {
-// case tpe @ RefinedType(parents, decls) =>
-// registerReifiableSymbol(tpe.typeSymbol)
-// mirrorFactoryCall(tpe, reify(parents), reifyScope(decls), reify(tpe.typeSymbol))
-// case tpe @ ExistentialType(tparams, underlying) =>
-// tparams foreach registerReifiableSymbol
-// mirrorFactoryCall(tpe, reify(tparams), reify(underlying))
-// case tpe @ ClassInfoType(parents, decls, clazz) =>
-// registerReifiableSymbol(clazz)
-// mirrorFactoryCall(tpe, reify(parents), reifyScope(decls), reify(tpe.typeSymbol))
-// case tpe @ MethodType(params, restpe) =>
-// params foreach registerReifiableSymbol
-// mirrorFactoryCall(tpe, reify(params), reify(restpe))
-// case tpe @ PolyType(tparams, underlying) =>
-// tparams foreach registerReifiableSymbol
-// mirrorFactoryCall(tpe, reify(tparams), reify(underlying))
-// case _ =>
-// throw new Error("internal error: %s (%s) is not supported".format(tpe, tpe.kind))
-// }
-// }
+ /** 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/phases/Metalevels.scala b/src/compiler/scala/reflect/reify/phases/Metalevels.scala
index a329a1043d..bb0b8ac138 100644
--- a/src/compiler/scala/reflect/reify/phases/Metalevels.scala
+++ b/src/compiler/scala/reflect/reify/phases/Metalevels.scala
@@ -134,6 +134,8 @@ trait Metalevels {
// 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 =>
if (reifyDebug) println("inlineable free ref: %s in %s".format(name, showRaw(tree)))
val freedef @ FreeDef(_, _, binding, _) = freedefsToInline(name)
diff --git a/src/compiler/scala/reflect/reify/phases/Reify.scala b/src/compiler/scala/reflect/reify/phases/Reify.scala
index f6d6423605..02a96987ed 100644
--- a/src/compiler/scala/reflect/reify/phases/Reify.scala
+++ b/src/compiler/scala/reflect/reify/phases/Reify.scala
@@ -9,6 +9,7 @@ trait Reify extends Symbols
with Types
with Names
with Trees
+ with AnnotationInfos
with Positions
with Util {
@@ -30,6 +31,9 @@ trait Reify extends Symbols
case tpe: Type => reifyType(tpe)
case name: Name => reifyName(name)
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 pos: Position => reifyPosition(pos)
case mods: mirror.Modifiers => reifyModifiers(mods)
case xs: List[_] => reifyList(xs)
diff --git a/src/compiler/scala/tools/nsc/util/Position.scala b/src/compiler/scala/tools/nsc/util/Position.scala
index 573f7bc7b2..208cd5703a 100644
--- a/src/compiler/scala/tools/nsc/util/Position.scala
+++ b/src/compiler/scala/tools/nsc/util/Position.scala
@@ -40,7 +40,15 @@ trait Position extends scala.reflect.api.Position with scala.reflect.api.Attachm
/** A bit weird method that is necessary to safely update positions without destroying custom attachments */
// necessary for conformance with Attachment
- def withPos(pos: scala.reflect.api.Position) = pos
+ def withPos(newPos: scala.reflect.api.Position): scala.reflect.api.Attachment = newPos
+
+ /** Exposes itself as payload of Attachment */
+ // necessary for conformance with Attachment
+ def payload: Position = this
+
+ /** A bit weird method that is necessary to safely update positions without destroying custom attachments */
+ // necessary for conformance with Attachment
+ def withPayload(newPos: Any): scala.reflect.api.Attachment = newPos.asInstanceOf[Position]
/** Java file corresponding to the source file of this position.
*/