diff options
author | Martin Odersky <odersky@gmail.com> | 2011-11-15 18:33:07 +0000 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2011-11-15 18:33:07 +0000 |
commit | 8a64ed85b9a63fd08c13f6730f038ba233d27fb6 (patch) | |
tree | 02770db6dbae39192acd196205b9c45bb0df017a /src/compiler | |
parent | 7abc466d64681ea7f2610068702019fee66b0579 (diff) | |
download | scala-8a64ed85b9a63fd08c13f6730f038ba233d27fb6.tar.gz scala-8a64ed85b9a63fd08c13f6730f038ba233d27fb6.tar.bz2 scala-8a64ed85b9a63fd08c13f6730f038ba233d27fb6.zip |
Towards better reflection APIs.
Diffstat (limited to 'src/compiler')
14 files changed, 447 insertions, 376 deletions
diff --git a/src/compiler/scala/reflect/internal/Scopes.scala b/src/compiler/scala/reflect/internal/Scopes.scala index 3ea43c22f2..fb3012adff 100644 --- a/src/compiler/scala/reflect/internal/Scopes.scala +++ b/src/compiler/scala/reflect/internal/Scopes.scala @@ -331,13 +331,12 @@ trait Scopes extends api.Scopes { self: SymbolTable => */ def scopeTransform(owner: Symbol)(op: => Scope): Scope = op - def newScopeWith(elems: Symbol*) = { + def newScopeWith(elems: Symbol*): Scope = { val scope = newScope elems foreach scope.enter scope } - /** The empty scope (immutable). */ object EmptyScope extends Scope { diff --git a/src/compiler/scala/reflect/internal/SymbolTable.scala b/src/compiler/scala/reflect/internal/SymbolTable.scala index 4b9b9d5959..0e9210f1f7 100644 --- a/src/compiler/scala/reflect/internal/SymbolTable.scala +++ b/src/compiler/scala/reflect/internal/SymbolTable.scala @@ -18,6 +18,7 @@ abstract class SymbolTable extends api.Universe with Constants with BaseTypeSeqs with InfoTransformers + with transform.Transforms with StdNames with AnnotationInfos with AnnotationCheckers diff --git a/src/compiler/scala/reflect/internal/Symbols.scala b/src/compiler/scala/reflect/internal/Symbols.scala index a49a5ebd1e..89183b99c7 100644 --- a/src/compiler/scala/reflect/internal/Symbols.scala +++ b/src/compiler/scala/reflect/internal/Symbols.scala @@ -41,9 +41,24 @@ trait Symbols extends api.Symbols { self: SymbolTable => */ val originalOwner = perRunCaches.newMap[Symbol, Symbol]() + abstract class AbsSymbolImpl extends AbsSymbol { this: Symbol => + def newNestedSymbol(pos: Position, name: Name) = name match { + case n: TermName => newValue(pos, n) + case n: TypeName => newAliasType(pos, n) + } + def typeSig: Type = info + def typeSigIn(site: Type): Type = site.memberInfo(this) + def asType: Type = tpe + def asTypeIn(site: Type): Type = site.memberType(this) + def asTypeConstructor: Type = typeConstructor + def setInternalFlags(flag: Long): this.type = { setFlag(flag); this } + def setTypeSig(tpe: Type): this.type = { setInfo(tpe); this } + def setAnnotations(annots: AnnotationInfo*): this.type = { setAnnotations(annots.toList); this } + } + /** The class for all symbols */ abstract class Symbol(initOwner: Symbol, initPos: Position, initName: Name) - extends AbsSymbol + extends AbsSymbolImpl with HasFlags with Annotatable[Symbol] { diff --git a/src/compiler/scala/reflect/internal/Trees.scala b/src/compiler/scala/reflect/internal/Trees.scala index 3adba8b66d..1ccd668fd6 100644 --- a/src/compiler/scala/reflect/internal/Trees.scala +++ b/src/compiler/scala/reflect/internal/Trees.scala @@ -248,12 +248,6 @@ trait Trees extends api.Trees { self: SymbolTable => def This(sym: Symbol): Tree = This(sym.name.toTypeName) setSymbol sym - def Select(qualifier: Tree, sym: Symbol): Select = - Select(qualifier, sym.name) setSymbol sym - - def Ident(sym: Symbol): Ident = - Ident(sym.name) setSymbol sym - /** Block factory that flattens directly nested blocks. */ def Block(stats: Tree*): Block = stats match { diff --git a/src/compiler/scala/reflect/internal/Types.scala b/src/compiler/scala/reflect/internal/Types.scala index 91cc0a6215..c8d7cb3a1e 100644 --- a/src/compiler/scala/reflect/internal/Types.scala +++ b/src/compiler/scala/reflect/internal/Types.scala @@ -235,8 +235,17 @@ trait Types extends api.Types { self: SymbolTable => override def tpe_=(t: Type) = if (t != NoType) throw new UnsupportedOperationException("tpe_=("+t+") inapplicable for <empty>") } + abstract class AbsTypeImpl extends AbsType { this: Type => + def declaration(name: Name): Symbol = decl(name) + def nonPrivateDeclaration(name: Name): Symbol = nonPrivateDecl(name) + def allDeclarations = decls + def allMembers = members + def typeArguments = typeArgs + def erasedType = transformedType(this) + } + /** The base class for all types */ - abstract class Type extends AbsType with Annotatable[Type] { + abstract class Type extends AbsTypeImpl with Annotatable[Type] { /** Types for which asSeenFrom always is the identity, no matter what * prefix or owner. */ @@ -1063,7 +1072,7 @@ trait Types extends api.Types { self: SymbolTable => /** A base class for types that represent a single value * (single-types and this-types). */ - abstract class SingletonType extends SubType with SimpleTypeProxy { + abstract class SingletonType extends SubType with SimpleTypeProxy with AbsSingletonType { def supertype = underlying override def isTrivial = false override def isStable = true @@ -1435,7 +1444,7 @@ trait Types extends api.Types { self: SymbolTable => override def isHigherKinded = ( parents.nonEmpty && (parents forall (_.isHigherKinded)) && - !phase.erasedTypes // @MO to AM: please check this class! + !phase.erasedTypes ) override def typeParams = diff --git a/src/compiler/scala/reflect/internal/transform/Transforms.scala b/src/compiler/scala/reflect/internal/transform/Transforms.scala index c2f3dc6092..a7cc99ba3b 100644 --- a/src/compiler/scala/reflect/internal/transform/Transforms.scala +++ b/src/compiler/scala/reflect/internal/transform/Transforms.scala @@ -4,13 +4,36 @@ package transform trait Transforms { self: SymbolTable => - object refChecks extends { val global: Transforms.this.type = self } with RefChecks - object uncurry extends { val global: Transforms.this.type = self } with UnCurry - object erasure extends { val global: Transforms.this.type = self } with Erasure + /** We need to encode laziness by hand here because the three components refChecks, uncurry and erasure + * are overwritten by objects in Global. + * It would be best of objects could override lazy values. See SI-5187. + * In the absence of this, the Lazy functionality should probably be somewhere + * in the standard library. Or is it already? + */ + private class Lazy[T](op: => T) { + private var value: T = _ + private var _isDefined = false + def isDefined = _isDefined + def force: T = { + if (!isDefined) { value = op; _isDefined = true } + value + } + } + + private val refChecksLazy = new Lazy(new { val global: Transforms.this.type = self } with RefChecks) + private val uncurryLazy = new Lazy(new { val global: Transforms.this.type = self } with UnCurry) + private val erasureLazy = new Lazy(new { val global: Transforms.this.type = self } with Erasure) + + def refChecks = refChecksLazy.force + def uncurry = uncurryLazy.force + def erasure = erasureLazy.force def transformedType(sym: Symbol) = erasure.transformInfo(sym, uncurry.transformInfo(sym, refChecks.transformInfo(sym, sym.info))) + def transformedType(tpe: Type) = + erasure.scalaErasure(uncurry.uncurry(tpe)) + }
\ No newline at end of file diff --git a/src/compiler/scala/reflect/internal/transform/UnCurry.scala b/src/compiler/scala/reflect/internal/transform/UnCurry.scala index 1d63aa4582..fd6d4e177d 100644 --- a/src/compiler/scala/reflect/internal/transform/UnCurry.scala +++ b/src/compiler/scala/reflect/internal/transform/UnCurry.scala @@ -17,7 +17,7 @@ trait UnCurry { case _ => false } - protected val uncurry: TypeMap = new TypeMap { + val uncurry: TypeMap = new TypeMap { def apply(tp0: Type): Type = { // tp0.typeSymbolDirect.initialize val tp = expandAlias(tp0) diff --git a/src/compiler/scala/reflect/runtime/Mirror.scala b/src/compiler/scala/reflect/runtime/Mirror.scala index faec0a7783..9490dc4ad7 100644 --- a/src/compiler/scala/reflect/runtime/Mirror.scala +++ b/src/compiler/scala/reflect/runtime/Mirror.scala @@ -38,6 +38,9 @@ class Mirror extends Universe with RuntimeTypes with TreeBuildUtil with ToolBoxe override def classToType(jclazz: java.lang.Class[_]): Type = typeToScala(jclazz) override def classToSymbol(jclazz: java.lang.Class[_]): Symbol = classToScala(jclazz) + override def typeToClass(tpe: Type): java.lang.Class[_] = typeToJavaClass(tpe) + override def symbolToClass(sym: Symbol): java.lang.Class[_] = classToJava(sym) + } object Mirror extends Mirror diff --git a/src/compiler/scala/reflect/runtime/TreeBuildUtil.scala b/src/compiler/scala/reflect/runtime/TreeBuildUtil.scala index 090862c759..8c9e6a2565 100644 --- a/src/compiler/scala/reflect/runtime/TreeBuildUtil.scala +++ b/src/compiler/scala/reflect/runtime/TreeBuildUtil.scala @@ -1,12 +1,13 @@ -package scala.reflect.runtime +package scala.reflect +package runtime -trait TreeBuildUtil extends Universe { +trait TreeBuildUtil extends Universe with api.TreeBuildUtil { - def staticClass(name: String): Symbol = definitions.getClass(newTypeName(name)) - def staticModule(name: String): Symbol = definitions.getModule(newTermName(name)) + def staticClass(fullname: String): Symbol = definitions.getClass(newTypeName(fullname)) + def staticModule(fullname: String): Symbol = definitions.getModule(newTermName(fullname)) - def thisModuleType(name: String) = - definitions.getModule(name).moduleClass.thisType + def thisModuleType(fullname: String) = + definitions.getModule(fullname).moduleClass.thisType /** Selects type symbol with given name from the defined members of prefix type */ @@ -40,9 +41,9 @@ trait TreeBuildUtil extends Universe { selectIn(owner.info, idx) } - def freeVar(name: String, info: Type, value: Any) = new FreeVar(name, info, value) - def newScopeWith(decls: List[Symbol]) = new Scope(decls) + def modifiersFromInternalFlags(flags: Long, privateWithin: Name, annotations: List[Tree]): Modifiers = + Modifiers(flags, privateWithin, annotations) }
\ No newline at end of file diff --git a/src/compiler/scala/reflect/runtime/Universe.scala b/src/compiler/scala/reflect/runtime/Universe.scala index a2c48b4c3f..c786bb86c5 100644 --- a/src/compiler/scala/reflect/runtime/Universe.scala +++ b/src/compiler/scala/reflect/runtime/Universe.scala @@ -8,7 +8,7 @@ import internal.{SomePhase, NoPhase, Phase, TreeGen} * It also provides methods to go from Java members to Scala members, * using the code in JavaConversions. */ -class Universe extends SymbolTable with internal.transform.Transforms { +class Universe extends SymbolTable { type AbstractFileType = AbstractFile diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index 11c0911337..fcbcb94e94 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -417,7 +417,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb } with Pickler // phaseName = "refchecks" - object refChecks extends { + override object refChecks extends { val global: Global.this.type = Global.this val runsAfter = List[String]("pickler") val runsRightAfter = None @@ -431,7 +431,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb } with LiftCode // phaseName = "uncurry" - object uncurry extends { + override object uncurry extends { val global: Global.this.type = Global.this val runsAfter = List[String]("refchecks", "liftcode") val runsRightAfter = None @@ -459,7 +459,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb } with SpecializeTypes // phaseName = "erasure" - object erasure extends { + override object erasure extends { val global: Global.this.type = Global.this val runsAfter = List[String]("explicitouter") val runsRightAfter = Some("explicitouter") diff --git a/src/compiler/scala/tools/nsc/transform/LiftCode.scala b/src/compiler/scala/tools/nsc/transform/LiftCode.scala index 82df75067d..ac2788b8ef 100644 --- a/src/compiler/scala/tools/nsc/transform/LiftCode.scala +++ b/src/compiler/scala/tools/nsc/transform/LiftCode.scala @@ -12,7 +12,8 @@ import scala.collection.{ mutable, immutable } import scala.collection.mutable.ListBuffer import scala.tools.nsc.util.FreshNameCreator -/** Translate expressions of the form reflect.Code.lift(exp) +/** + * Translate expressions of the form reflect.Code.lift(exp) * to the reified "reflect trees" representation of exp. * Also: mutable variables that are accessed from a local function are wrapped in refs. * @@ -21,9 +22,9 @@ import scala.tools.nsc.util.FreshNameCreator */ abstract class LiftCode extends Transform with TypingTransformers { - import global._ // the global environment - import definitions._ // standard classes and methods - import typer.{typed, atOwner} // methods to type trees + import global._ // the global environment + import definitions._ // standard classes and methods + import typer.{ typed, atOwner } // methods to type trees val symbols: global.type = global @@ -49,7 +50,7 @@ abstract class LiftCode extends Transform with TypingTransformers { super.transformUnit(unit) } for (v <- freeMutableVars) //!!! remove - assert(converted contains v, "unconverted: "+v+" in "+v.owner+" in unit "+unit) + assert(converted contains v, "unconverted: " + v + " in " + v.owner + " in unit " + unit) } override def transform(tree: Tree): Tree = { @@ -75,7 +76,7 @@ abstract class LiftCode extends Transform with TypingTransformers { } sym resetFlag MUTABLE sym removeAnnotation VolatileAttr - converted += sym// dereference boxed variables + converted += sym // dereference boxed variables treeCopy.ValDef(tree, mods &~ MUTABLE, name, tpt1, rhs1) case Ident(name) if freeMutableVars(sym) => localTyper.typedPos(tree.pos) { @@ -86,348 +87,14 @@ abstract class LiftCode extends Transform with TypingTransformers { } } - /** - * Given a tree, generate a tree that when exeuted ar tuntime produces the original tree. - * For instance: Given - * - * var x = 1; Code(x + 1) - * - * The `x + 1` expression is reified to - * - * $mr.Apply($mr.Select($mr.Ident($mr.freeVar("x". <Int>, x), "+"), List($mr.Literal($mr.Constant(1)))))) - * - * Or, the term name 'abc' is reified to: - * - * $mr.Apply($mr.Select($mr.Ident("newTermName")), List(Literal(Constant("abc"))))) - * - * todo: Treat embedded Code blocks by merging them into containing block - * - */ - class Reifier() { - - final val mirrorFullName = "scala.reflect.runtime.Mirror" - final val mirrorShortName = "$mr" - final val mirrorPrefix = mirrorShortName + "." - final val scalaPrefix = "scala." - final val localPrefix = "$local" - final val memoizerName = "$memo" - - private val reifiableSyms = mutable.ArrayBuffer[Symbol]() // the symbols that are reified with the tree - private val symIndex = mutable.HashMap[Symbol, Int]() // the index of a reifiable symbol in `reifiableSyms` - private var boundSyms = Set[Symbol]() // set of all symbols that are bound in tree to be reified - - /** Generate tree of the form - * - * { val $mr = scala.reflect.runtime.Mirror - * $local1 = new TypeSymbol(owner1, NoPosition, name1) - * ... - * $localN = new TermSymbol(ownerN, NoPositiion, nameN) - * $local1.setInfo(tpe1) - * ... - * $localN.setInfo(tpeN) - * $localN.setAnnotations(annotsN) - * rtree - * } - * - * where - * - * - `$localI` are free type symbols in the environment, as well as local symbols - * of refinement types. - * - `tpeI` are the info's of `symI` - * - `rtree` is code that generates `tree` at runtime, maintaining all attributes. - */ - def reifyTopLevel(tree: Tree): Tree = { - val rtree = reify(tree) - Block(mirrorAlias :: reifySymbolTableSetup, rtree) - } - - private def isLocatable(sym: Symbol) = - sym.isPackageClass || sym.owner.isClass || sym.isTypeParameter && sym.paramPos >= 0 - - private def registerReifiableSymbol(sym: Symbol): Unit = - if (!(symIndex contains sym)) { - sym.owner.ownersIterator.find(!isLocatable(_)) match { - case Some(outer) => registerReifiableSymbol(outer) - case None => - } - symIndex(sym) = reifiableSyms.length - reifiableSyms += sym - } - - // helper methods - - private def localName(sym: Symbol) = localPrefix + symIndex(sym) - - private def call(fname: String, args: Tree*): Tree = - Apply(termPath(fname), args.toList) - - private def mirrorSelect(name: String): Tree = - termPath(mirrorPrefix + name) - - private def mirrorCall(name: String, args: Tree*): Tree = - call(mirrorPrefix + name, args: _*) - - private def mirrorFactoryCall(value: Product, args: Tree*): Tree = - mirrorCall(value.productPrefix, args: _*) - - private def scalaFactoryCall(name: String, args: Tree*): Tree = - call(scalaPrefix + name + ".apply", args: _*) - - private def mkList(args: List[Tree]): Tree = - scalaFactoryCall("collection.immutable.List", args: _*) - - /** Reify a case object defined in Mirror - */ - private def reifyCaseObject(value: Product) = mirrorSelect(value.productPrefix) - - /** Reify an instance of a case class defined in Mirror - */ - private def reifyCaseClassInstance(value: Product) = - mirrorFactoryCall(value, (value.productIterator map reify).toList: _*) - - private def reifyAggregate(name: String, args: Any*) = - scalaFactoryCall(name, (args map reify).toList: _*) - - /** Reify a list - */ - private def reifyList(xs: List[Any]): Tree = - mkList(xs map reify) - - /** Reify a name */ - private def reifyName(name: Name) = - mirrorCall(if (name.isTypeName) "newTypeName" else "newTermName", Literal(Constant(name.toString))) - - private def isFree(sym: Symbol) = - !(symIndex contains sym) - - /** Reify a reference to a symbol - */ - private def reifySymRef(sym: Symbol): Tree = { - symIndex get sym match { - case Some(idx) => - Ident(localName(sym)) - case None => - if (sym == NoSymbol) - mirrorSelect("NoSymbol") - else if (sym.isModuleClass) - Select(reifySymRef(sym.sourceModule), "moduleClass") - else if (sym.isStatic && sym.isClass) - mirrorCall("staticClass", reify(sym.fullName)) - else if (sym.isStatic && sym.isModule) - mirrorCall("staticModule", reify(sym.fullName)) - else if (isLocatable(sym)) - if (sym.isTypeParameter) - mirrorCall("selectParam", reify(sym.owner), reify(sym.paramPos)) - else { - if (reifyDebug) println("locatable: "+sym+" "+sym.isPackageClass+" "+sym.owner+" "+sym.isTypeParameter) - val rowner = reify(sym.owner) - val rname = reify(sym.name.toString) - if (sym.isType) - mirrorCall("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("selectOverloadedMethod", rowner, rname, reify(index)) - } else - mirrorCall("selectTerm", rowner, rname) - } - else { - if (sym.isTerm) { - if (reifyDebug) println("Free: "+sym) - mirrorCall("freeVar", reify(sym.name.toString), reify(sym.tpe), Ident(sym)) - } else { - if (reifyDebug) println("Late local: "+sym) - registerReifiableSymbol(sym) - reifySymRef(sym) - } - } - } - } - - /** reify the creation of a symbol - */ - private def reifySymbolDef(sym: Symbol): Tree = { - if (reifyDebug) println("reify sym def "+sym) - var rsym: Tree = New( - typePath(mirrorPrefix + (if (sym.isType) "TypeSymbol" else "TermSymbol")), - List(List(reify(sym.owner), reify(sym.pos), reify(sym.name)))) - if (sym.flags != 0L) - rsym = Apply(Select(rsym, "setFlag"), List(Literal(Constant(sym.flags)))) - ValDef(NoMods, localName(sym), TypeTree(), rsym) - } - - /** Generate code to add type and annotation info to a reified symbol - */ - private def fillInSymbol(sym: Symbol): Tree = { - val rset = Apply(Select(reifySymRef(sym), "setInfo"), List(reifyType(sym.info))) - if (sym.annotations.isEmpty) rset - else Apply(Select(rset, "setAnnotations"), List(reify(sym.annotations))) - } - - /** Reify a scope */ - private def reifyScope(scope: Scope): Tree = { - scope foreach registerReifiableSymbol - mirrorCall("newScopeWith", scope.toList map reifySymRef: _*) - } - - /** Reify a list of symbols that need to be created */ - private def reifySymbols(syms: List[Symbol]): Tree = { - syms foreach registerReifiableSymbol - mkList(syms map reifySymRef) - } - - /** Reify a type that defines some symbols */ - private def reifyTypeBinder(value: Product, bound: List[Symbol], underlying: Type): Tree = - mirrorFactoryCall(value, reifySymbols(bound), reify(underlying)) - - /** Reify a type */ - private def reifyType(tpe0: Type): Tree = { - val tpe = tpe0.normalize - val tsym = tpe.typeSymbol - if (tsym.isClass && tpe == tsym.typeConstructor && tsym.isStatic) - Select(reifySymRef(tpe.typeSymbol), "typeConstructor") - else tpe match { - case NoType | NoPrefix => - reifyCaseObject(tpe.asInstanceOf[Product]) - case tpe @ ThisType(clazz) => - if (clazz.isModuleClass && clazz.isStatic) mirrorCall("thisModuleType", reify(clazz.fullName)) - else reifyCaseClassInstance(tpe) - case SuperType(_, _) | SingleType(_, _) | ConstantType(_) | - TypeRef(_, _, _) | AnnotatedType(_, _, _) | - TypeBounds(_, _) | NullaryMethodType(_) | OverloadedType(_, _) => - reifyCaseClassInstance(tpe.asInstanceOf[Product]) - case t @ RefinedType(parents, decls) => - registerReifiableSymbol(tpe.typeSymbol) - mirrorFactoryCall(t, reify(parents), reify(decls), reify(t.typeSymbol)) - case t @ ClassInfoType(parents, decls, clazz) => - registerReifiableSymbol(clazz) - mirrorFactoryCall(t, reify(parents), reify(decls), reify(t.typeSymbol)) - case t @ ExistentialType(tparams, underlying) => - reifyTypeBinder(t, tparams, underlying) - case t @ PolyType(tparams, underlying) => - reifyTypeBinder(t, tparams, underlying) - case t @ MethodType(params, restpe) => - reifyTypeBinder(t, params, restpe) - case _ => - abort("cannot reify type " + tpe + " of class " + tpe.getClass) - } - } - - /** Reify a tree */ - private def reifyTree(tree: Tree): Tree = tree match { - case EmptyTree => - reifyCaseObject(tree) - case This(_) if !(boundSyms contains tree.symbol) => - reifyFree(tree) - case Ident(_) if !(boundSyms contains tree.symbol) => - reifyFree(tree) - case TypeTree() if (tree.tpe != null) => - mirrorCall("TypeTree", reifyType(tree.tpe)) - case _ => - if (tree.isDef) boundSyms += tree.symbol - reifyCaseClassInstance(tree.asInstanceOf[Product]) -/* - if (tree.isDef || tree.isInstanceOf[Function]) - registerReifiableSymbol(tree.symbol) - if (tree.hasSymbol) - rtree = Apply(Select(rtree, "setSymbol"), List(reifySymRef(tree.symbol))) - Apply(Select(rtree, "setType"), List(reifyType(tree.tpe))) -*/ - } - - /** Reify a free reference. The result will be either a mirror reference - * to a global value, or else a mirror Literal. - */ - private def reifyFree(tree: Tree): Tree = - mirrorCall("Ident", reifySymRef(tree.symbol)) - - /** Reify an arbitary value */ - private def reify(value: Any): Tree = { - value match { - case tree: Tree => - reifyTree(tree) - case sym: Symbol => - reifySymRef(sym) - case tpe: Type => - reifyType(tpe) - case xs: List[_] => - scalaFactoryCall("collection.immutable.List", xs map reify: _*) - case xs: Array[_] => - scalaFactoryCall("Array", xs map reify: _*) - case scope: Scope => - reifyScope(scope) - case x: Name => - reifyName(x) - case pos: Position => // todo: consider whether we should also reify positions - reifyCaseObject(NoPosition) - case Constant(_) | AnnotationInfo(_, _, _) | Modifiers(_, _, _) => - reifyCaseClassInstance(value.asInstanceOf[Product]) - case arg: ClassfileAnnotArg => - reifyCaseClassInstance(arg.asInstanceOf[Product]) - case x: Product if x.getClass.getName startsWith "scala.Tuple" => - reifyCaseClassInstance(x) - case () => Literal(Constant(())) - case x: String => Literal(Constant(x)) - case x: Boolean => Literal(Constant(x)) - case x: Byte => Literal(Constant(x)) - case x: Short => Literal(Constant(x)) - case x: Char => Literal(Constant(x)) - case x: Int => Literal(Constant(x)) - case x: Long => Literal(Constant(x)) - case x: Float => Literal(Constant(x)) - case x: Double => Literal(Constant(x)) - case _ => cannotReify(value) - } - } - - /** An (unreified) path that refers to definition with given fully qualified name - * @param mkName Creator for last portion of name (either TermName or TypeName) - */ - private def path(fullname: String, mkName: String => Name): Tree = { - val parts = fullname split "\\." - val prefixParts = parts.init - val lastName = mkName(parts.last) - if (prefixParts.isEmpty) Ident(lastName) - else { - val prefixTree = ((Ident(prefixParts.head): Tree) /: prefixParts.tail)(Select(_, _)) - Select(prefixTree, lastName) - } - } - - /** An (unreified) path that refers to term definition with given fully qualified name */ - private def termPath(fullname: String): Tree = path(fullname, newTermName) - - /** An (unreified) path that refers to type definition with given fully qualified name */ - private def typePath(fullname: String): Tree = path(fullname, newTypeName) - - private def mirrorAlias = - ValDef(NoMods, mirrorShortName, TypeTree(), termPath(mirrorFullName)) - - /** Generate code that generates a symbol table of all symbols registered in `reifiableSyms` - */ - private def reifySymbolTableSetup: List[Tree] = { - val symDefs, fillIns = new mutable.ArrayBuffer[Tree] - var i = 0 - while (i < reifiableSyms.length) { - // fillInSymbol might create new reifiableSyms, that's why this is done iteratively - symDefs += reifySymbolDef(reifiableSyms(i)) - fillIns += fillInSymbol(reifiableSyms(i)) - i += 1 - } - - symDefs.toList ++ fillIns.toList - } - - private def cannotReify(value: Any): Nothing = - abort("don't know how to reify " + value + " of class " + value.getClass) - - } - def codify(tree: Tree): Tree = debugTrace("codified " + tree + " -> ") { val targetType = definitions.CodeClass.primaryConstructor.info.paramTypes.head val reifier = new Reifier() val arg = gen.mkAsInstanceOf(reifier.reifyTopLevel(tree), targetType, wrapInApply = false) - New(TypeTree(appliedType(definitions.CodeClass.typeConstructor, List(tree.tpe))), + val treetpe = + if (tree.tpe.typeSymbol.isAnonymousClass) tree.tpe.typeSymbol.classBound + else tree.tpe + New(TypeTree(appliedType(definitions.CodeClass.typeConstructor, List(treetpe))), List(List(arg))) } @@ -499,4 +166,356 @@ abstract class LiftCode extends Transform with TypingTransformers { } } } + + /** + * Given a tree or type, generate a tree that when executed at runtime produces the original tree or type. + * For instance: Given + * + * var x = 1; Code(x + 1) + * + * The `x + 1` expression is reified to + * + * $mr.Apply($mr.Select($mr.Ident($mr.freeVar("x". <Int>, x), "+"), List($mr.Literal($mr.Constant(1)))))) + * + * Or, the term name 'abc' is reified to: + * + * $mr.Apply($mr.Select($mr.Ident("newTermName")), List(Literal(Constant("abc"))))) + * + * todo: Treat embedded Code blocks by merging them into containing block + * + */ + class Reifier() { + + final val mirrorFullName = "scala.reflect.mirror" + final val mirrorShortName = "$mr" + final val mirrorPrefix = mirrorShortName + "." + final val scalaPrefix = "scala." + final val localPrefix = "$local" + final val memoizerName = "$memo" + + val reifyDebug = settings.Yreifydebug.value + + private val reifiableSyms = mutable.ArrayBuffer[Symbol]() // the symbols that are reified with the tree + private val symIndex = mutable.HashMap[Symbol, Int]() // the index of a reifiable symbol in `reifiableSyms` + private var boundSyms = Set[Symbol]() // set of all symbols that are bound in tree to be reified + + /** + * Generate tree of the form + * + * { val $mr = scala.reflect.runtime.Mirror + * $local1 = new TypeSymbol(owner1, NoPosition, name1) + * ... + * $localN = new TermSymbol(ownerN, NoPositiion, nameN) + * $local1.setInfo(tpe1) + * ... + * $localN.setInfo(tpeN) + * $localN.setAnnotations(annotsN) + * rtree + * } + * + * where + * + * - `$localI` are free type symbols in the environment, as well as local symbols + * of refinement types. + * - `tpeI` are the info's of `symI` + * - `rtree` is code that generates `data` at runtime, maintaining all attributes. + * - `data` is typically a tree or a type. + */ + def reifyTopLevel(data: Any): Tree = { + val rtree = reify(data) + Block(mirrorAlias :: reifySymbolTableSetup, rtree) + } + + private def isLocatable(sym: Symbol) = + sym.isPackageClass || sym.owner.isClass || sym.isTypeParameter && sym.paramPos >= 0 + + private def registerReifiableSymbol(sym: Symbol): Unit = + if (!(symIndex contains sym)) { + sym.owner.ownersIterator.find(!isLocatable(_)) match { + case Some(outer) => registerReifiableSymbol(outer) + case None => + } + symIndex(sym) = reifiableSyms.length + reifiableSyms += sym + } + + // helper methods + + private def localName(sym: Symbol) = localPrefix + symIndex(sym) + + private def call(fname: String, args: Tree*): Tree = + Apply(termPath(fname), args.toList) + + private def mirrorSelect(name: String): Tree = + termPath(mirrorPrefix + name) + + private def mirrorCall(name: String, args: Tree*): Tree = + call(mirrorPrefix + name, args: _*) + + private def mirrorFactoryCall(value: Product, args: Tree*): Tree = + mirrorCall(value.productPrefix, args: _*) + + private def scalaFactoryCall(name: String, args: Tree*): Tree = + call(scalaPrefix + name + ".apply", args: _*) + + private def mkList(args: List[Tree]): Tree = + scalaFactoryCall("collection.immutable.List", args: _*) + + /** + * Reify a case object defined in Mirror + */ + private def reifyCaseObject(value: Product) = mirrorSelect(value.productPrefix) + + /** + * Reify an instance of a case class defined in Mirror + */ + private def reifyCaseClassInstance(value: Product) = + mirrorFactoryCall(value, (value.productIterator map reify).toList: _*) + + private def reifyAggregate(name: String, args: Any*) = + scalaFactoryCall(name, (args map reify).toList: _*) + + /** + * Reify a list + */ + private def reifyList(xs: List[Any]): Tree = + mkList(xs map reify) + + /** Reify a name */ + private def reifyName(name: Name) = + mirrorCall(if (name.isTypeName) "newTypeName" else "newTermName", Literal(Constant(name.toString))) + + private def isFree(sym: Symbol) = + !(symIndex contains sym) + + /** + * Reify a reference to a symbol + */ + private def reifySymRef(sym: Symbol): Tree = { + symIndex get sym match { + case Some(idx) => + Ident(localName(sym)) + case None => + if (sym == NoSymbol) + mirrorSelect("NoSymbol") + else if (sym.isModuleClass) + Select(reifySymRef(sym.sourceModule), "moduleClass") + else if (sym.isStatic && sym.isClass) + mirrorCall("staticClass", reify(sym.fullName)) + else if (sym.isStatic && sym.isModule) + mirrorCall("staticModule", reify(sym.fullName)) + else if (isLocatable(sym)) + if (sym.isTypeParameter) + mirrorCall("selectParam", reify(sym.owner), reify(sym.paramPos)) + else { + if (reifyDebug) println("locatable: " + sym + " " + sym.isPackageClass + " " + sym.owner + " " + sym.isTypeParameter) + val rowner = reify(sym.owner) + val rname = reify(sym.name.toString) + if (sym.isType) + mirrorCall("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("selectOverloadedMethod", rowner, rname, reify(index)) + } else + mirrorCall("selectTerm", rowner, rname) + } + else { + if (sym.isTerm) { + if (reifyDebug) println("Free: " + sym) + mirrorCall("freeVar", reify(sym.name.toString), reify(sym.tpe), Ident(sym)) + } else { + if (reifyDebug) println("Late local: " + sym) + registerReifiableSymbol(sym) + reifySymRef(sym) + } + } + } + } + + /** + * reify the creation of a symbol + */ + private def reifySymbolDef(sym: Symbol): Tree = { + if (reifyDebug) println("reify sym def " + sym) + var rsym: Tree = + Apply( + Select(reify(sym.owner), "newNestedSymbol"), + List(reify(sym.pos), reify(sym.name))) + if (sym.flags != 0L) + rsym = Apply(Select(rsym, "setInternalFlags"), List(Literal(Constant(sym.flags)))) + ValDef(NoMods, localName(sym), TypeTree(), rsym) + } + + /** + * Generate code to add type and annotation info to a reified symbol + */ + private def fillInSymbol(sym: Symbol): Tree = { + val rset = Apply(Select(reifySymRef(sym), "setTypeSig"), List(reifyType(sym.info))) + if (sym.annotations.isEmpty) rset + else Apply(Select(rset, "setAnnotations"), List(reify(sym.annotations))) + } + + /** Reify a scope */ + private def reifyScope(scope: Scope): Tree = { + scope foreach registerReifiableSymbol + mirrorCall("newScopeWith", scope.toList map reifySymRef: _*) + } + + /** Reify a list of symbols that need to be created */ + private def reifySymbols(syms: List[Symbol]): Tree = { + syms foreach registerReifiableSymbol + mkList(syms map reifySymRef) + } + + /** Reify a type that defines some symbols */ + private def reifyTypeBinder(value: Product, bound: List[Symbol], underlying: Type): Tree = + mirrorFactoryCall(value, reifySymbols(bound), reify(underlying)) + + /** Reify a type */ + private def reifyType(tpe0: Type): Tree = { + val tpe = tpe0.normalize + val tsym = tpe.typeSymbol + if (tsym.isClass && tpe == tsym.typeConstructor && tsym.isStatic) + Select(reifySymRef(tpe.typeSymbol), "asTypeConstructor") + else tpe match { + case NoType | NoPrefix => + reifyCaseObject(tpe.asInstanceOf[Product]) + case tpe @ ThisType(clazz) => + if (clazz.isModuleClass && clazz.isStatic) mirrorCall("thisModuleType", reify(clazz.fullName)) + else reifyCaseClassInstance(tpe) + case SuperType(_, _) | SingleType(_, _) | ConstantType(_) | + TypeRef(_, _, _) | AnnotatedType(_, _, _) | + TypeBounds(_, _) | NullaryMethodType(_) | OverloadedType(_, _) => + reifyCaseClassInstance(tpe.asInstanceOf[Product]) + case t @ RefinedType(parents, decls) => + registerReifiableSymbol(tpe.typeSymbol) + mirrorFactoryCall(t, reify(parents), reify(decls), reify(t.typeSymbol)) + case t @ ClassInfoType(parents, decls, clazz) => + registerReifiableSymbol(clazz) + mirrorFactoryCall(t, reify(parents), reify(decls), reify(t.typeSymbol)) + case t @ ExistentialType(tparams, underlying) => + reifyTypeBinder(t, tparams, underlying) + case t @ PolyType(tparams, underlying) => + reifyTypeBinder(t, tparams, underlying) + case t @ MethodType(params, restpe) => + reifyTypeBinder(t, params, restpe) + case _ => + cannotReify(tpe) + } + } + + /** Reify a tree */ + private def reifyTree(tree: Tree): Tree = tree match { + case EmptyTree => + reifyCaseObject(tree) + case This(_) if !(boundSyms contains tree.symbol) => + reifyFree(tree) + case Ident(_) if !(boundSyms contains tree.symbol) => + reifyFree(tree) + case TypeTree() if (tree.tpe != null) => + mirrorCall("TypeTree", reifyType(tree.tpe)) + case _ => + if (tree.isDef) boundSyms += tree.symbol + reifyCaseClassInstance(tree.asInstanceOf[Product]) + /* + if (tree.isDef || tree.isInstanceOf[Function]) + registerReifiableSymbol(tree.symbol) + if (tree.hasSymbol) + rtree = Apply(Select(rtree, "setSymbol"), List(reifySymRef(tree.symbol))) + Apply(Select(rtree, "setType"), List(reifyType(tree.tpe))) +*/ + } + + /** + * Reify a free reference. The result will be either a mirror reference + * to a global value, or else a mirror Literal. + */ + private def reifyFree(tree: Tree): Tree = + mirrorCall("Ident", reifySymRef(tree.symbol)) + + /** Reify an arbitary value */ + private def reify(value: Any): Tree = { + value match { + case tree: Tree => + reifyTree(tree) + case sym: Symbol => + reifySymRef(sym) + case tpe: Type => + reifyType(tpe) + case xs: List[_] => + scalaFactoryCall("collection.immutable.List", xs map reify: _*) + case xs: Array[_] => + scalaFactoryCall("Array", xs map reify: _*) + case scope: Scope => + reifyScope(scope) + case x: Name => + reifyName(x) + case pos: Position => // todo: consider whether we should also reify positions + reifyCaseObject(NoPosition) + case Constant(_) | AnnotationInfo(_, _, _) => + reifyCaseClassInstance(value.asInstanceOf[Product]) + case Modifiers(flags, qual, annots) => + mirrorCall("modifiersFromInternalFlags", reify(flags), reify(qual), reify(annots)) + case arg: ClassfileAnnotArg => + reifyCaseClassInstance(arg.asInstanceOf[Product]) + case x: Product if x.getClass.getName startsWith "scala.Tuple" => + reifyCaseClassInstance(x) + case () => Literal(Constant(())) + case x: String => Literal(Constant(x)) + case x: Boolean => Literal(Constant(x)) + case x: Byte => Literal(Constant(x)) + case x: Short => Literal(Constant(x)) + case x: Char => Literal(Constant(x)) + case x: Int => Literal(Constant(x)) + case x: Long => Literal(Constant(x)) + case x: Float => Literal(Constant(x)) + case x: Double => Literal(Constant(x)) + case _ => cannotReify(value) + } + } + + /** + * An (unreified) path that refers to definition with given fully qualified name + * @param mkName Creator for last portion of name (either TermName or TypeName) + */ + private def path(fullname: String, mkName: String => Name): Tree = { + val parts = fullname split "\\." + val prefixParts = parts.init + val lastName = mkName(parts.last) + if (prefixParts.isEmpty) Ident(lastName) + else { + val prefixTree = ((Ident(prefixParts.head): Tree) /: prefixParts.tail)(Select(_, _)) + Select(prefixTree, lastName) + } + } + + /** An (unreified) path that refers to term definition with given fully qualified name */ + private def termPath(fullname: String): Tree = path(fullname, newTermName) + + /** An (unreified) path that refers to type definition with given fully qualified name */ + private def typePath(fullname: String): Tree = path(fullname, newTypeName) + + private def mirrorAlias = + ValDef(NoMods, mirrorShortName, TypeTree(), termPath(mirrorFullName)) + + /** + * Generate code that generates a symbol table of all symbols registered in `reifiableSyms` + */ + private def reifySymbolTableSetup: List[Tree] = { + val symDefs, fillIns = new mutable.ArrayBuffer[Tree] + var i = 0 + while (i < reifiableSyms.length) { + // fillInSymbol might create new reifiableSyms, that's why this is done iteratively + symDefs += reifySymbolDef(reifiableSyms(i)) + fillIns += fillInSymbol(reifiableSyms(i)) + i += 1 + } + + symDefs.toList ++ fillIns.toList + } + + private def cannotReify(value: Any): Nothing = + abort("don't know how to reify " + value + " of class " + value.getClass) + } } diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala index d58df50451..2c32d22081 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala @@ -1110,7 +1110,7 @@ trait Implicits { // a manifest should have been found by normal searchImplicit EmptyTree } - case RefinedType(parents, decls) => + case RefinedType(parents, decls) => // !!! not yet: if !full || decls.isEmpty => // refinement is not generated yet if (hasLength(parents, 1)) findManifest(parents.head) else if (full) manifestFactoryCall("intersectionType", tp, parents map findSubManifest: _*) @@ -1119,7 +1119,14 @@ trait Implicits { mot(tp1.skolemizeExistential, from, to) case _ => EmptyTree - } +/* !!! the following is almost right, but we have to splice nested manifest + * !!! types into this type. This requires a substantial extension of + * !!! reifiers. + val reifier = new liftcode.Reifier() + val rtree = reifier.reifyTopLevel(tp1) + manifestFactoryCall("apply", tp, rtree) +*/ + } } mot(tp, Nil, Nil) diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index e758c8960a..fd75b03297 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -368,8 +368,8 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { val tp1 = apply(tree.tpe) if (hiddenSymbols.isEmpty) tree setType tp1 else if (hiddenSymbols exists (_.isErroneous)) setError(tree) - else if (isFullyDefined(pt)) tree setType pt //todo: eliminate - else if (tp1.typeSymbol.isAnonymousClass) // todo: eliminate + else if (isFullyDefined(pt)) tree setType pt + else if (tp1.typeSymbol.isAnonymousClass) check(owner, scope, pt, tree setType tp1.typeSymbol.classBound) else if (owner == NoSymbol) tree setType packSymbols(hiddenSymbols.reverse, tp1) |