Towards better reflection APIs. Also, LiftCode now produces reflect.Trees, not reflect.runtime.Mirror.Trees which should make reified trees much easier to use. Interruped (for now) attempt to base manifests exclusively on reflect.Type. Review by vogt.

git-svn-id: http://lampsvn.epfl.ch/svn-repos/scala/scala/trunk@26014 5e8d7ff9-d8ef-0310-90f0-a4852d11357a
This commit is contained in:
odersky 2011-11-15 18:33:07 +00:00
parent 2bcff7cb4c
commit d075bce0b1
21 changed files with 904 additions and 448 deletions

View File

@ -331,12 +331,11 @@ 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).
*/

View File

@ -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

View File

@ -40,10 +40,25 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
* EnclosingMethod attributes.
*/
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] {

View File

@ -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 {

View File

@ -234,9 +234,18 @@ trait Types extends api.Types { self: SymbolTable =>
super.tpe_=(NoType)
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 =
@ -2062,7 +2071,7 @@ A type's typeSymbol should never be inspected directly.
sym.skipPackageObject.fullName + "."
else if (isStable && nme.isSingletonName(sym.name))
nme.dropSingletonName(sym.name) + "."
else
else
super.prefixString
)
override def kind = "TypeRef"

View File

@ -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))
}

View File

@ -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)

View File

@ -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

View File

@ -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)
}

View File

@ -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

View File

@ -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")

View File

@ -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
@ -32,12 +33,12 @@ abstract class LiftCode extends Transform with TypingTransformers {
def newTransformer(unit: CompilationUnit): Transformer =
new Codifier(unit)
class Codifier(unit: CompilationUnit) extends TypingTransformer(unit) {
val reifyDebug = settings.Yreifydebug.value
val debugTrace = util.trace when reifyDebug
/** Set of mutable local variables that are free in some inner method. */
private val freeMutableVars: mutable.Set[Symbol] = new mutable.HashSet
private val converted: mutable.Set[Symbol] = new mutable.HashSet // debug
@ -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,10 +76,10 @@ 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) {
localTyper.typedPos(tree.pos) {
Select(tree setType sym.tpe, nme.elem)
}
case _ =>
@ -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)))
}
@ -468,7 +135,7 @@ abstract class LiftCode extends Transform with TypingTransformers {
else
traverse(arg)
}
/** The rhs of a closure represents escape. */
case Function(vparams, body) =>
vparams foreach traverse
@ -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)
}
}

View File

@ -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)

View File

@ -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)

View File

@ -13,7 +13,7 @@ package scala.reflect
/** This type is required by the compiler and <b>should not be used in client code</b>. */
class Code[T: Manifest](val tree: scala.reflect.mirror.Tree) {
val manifest = implicitly[Manifest[T]]
override def toString = "Code(manifest = " + manifest + ")"
override def toString = "Code(tree = "+tree+", manifest = "+manifest+")"
}
/** This type is required by the compiler and <b>should not be used in client code</b>. */

View File

@ -284,4 +284,24 @@ object Manifest {
override lazy val tpe = mirror.RefinedType((parents map (_.tpe)).toList, newScope)
override def toString = parents.mkString(" with ")
}
/** A generic manifest factory from a reflect.Type. Except where
* mandated by performance considerations, we should replace most
* other manifest factories by this one. There's just one thing
* that needs to be done first: A Manifest's type can refer
* to type variables that are controlled by manifests. In that
* case the reified type needs to contain the type passed in the manifest
* instead of the reference to the manifest. Note that splicing manifests
* into manfifests is completely analogous to splicing code blocks into
* code blocks. Manifest[T] and Code[T] are really the same thing, only one
* works for types, the other for trees.
* Another complication is that once we generate manifests from types, we really
* should have reflection as a standard component shipped with the standard library,
* instead of in scala-compiler.jar.
*/
def apply[T](_tpe: mirror.Type): Manifest[T] = new Manifest[T] {
override lazy val tpe = _tpe
override def erasure = mirror.typeToClass(_tpe.erasedType)
override def toString = _tpe.toString
}
}

View File

@ -5,7 +5,7 @@ package api
* runtime entities such as class names and object instances
* with a refexive universe.
*/
trait Mirror extends Universe with RuntimeTypes {
trait Mirror extends Universe with RuntimeTypes with TreeBuildUtil {
/** The Scala class symbol that has given fully qualified name
* @param name The fully qualified name of the class to be returned
@ -65,17 +65,15 @@ trait Mirror extends Universe with RuntimeTypes {
*/
def classToSymbol(clazz: java.lang.Class[_]): Symbol
/*
/** Selects term symbol with given name and type from the defined members of prefix type
* @pre The prefix type
* @name The name of the selected member
* @tpe The type of the selected member
/** Maps a Scala type to the corresponding Java class object
*/
def selectTerm(pre: Type, name: String, tpe: Type) : Symbol
/** Selects type symbol with given name from the defined members of prefix type
*/
def selectType(pre: Type, name: String): Symbol
def typeToClass(tpe: Type): java.lang.Class[_]
*/
/** Maps a Scala symbol to the corresponding Java class object
* @throws ClassNotFoundException if there is no Java class
* corresponding to the given Scala symbol.
* Note: If the Scala symbol is ArrayClass, a ClassNotFound exception is thrown
* because there is no unique Java class corresponding to a Scala generic array
*/
def symbolToClass(sym: Symbol): java.lang.Class[_]
}

View File

@ -4,7 +4,7 @@ package api
trait Symbols { self: Universe =>
type Symbol >: Null <: AbsSymbol
abstract class AbsSymbol { this: Symbol =>
/** The modifiers of this symbol
@ -103,10 +103,10 @@ trait Symbols { self: Universe =>
*/
def sourceModule: Symbol
/** If symbol is an object definition, it's implied associated class,
* otherwise NoSymbol
/** If symbol is an object definition, its implied associated class,
* otherwise NoSymbol
*/
def moduleClass: Symbol
def moduleClass: Symbol // needed for LiftCode
/** The top-level class containing this symbol. */
def toplevelClass: Symbol
@ -122,7 +122,50 @@ trait Symbols { self: Universe =>
def isClass : Boolean
def isAliasType : Boolean
def isAbstractType : Boolean
/** The type signature of this symbol.
* Note if symbol is a member of a class, one almost always is interested
* in `typeSigIn` with a site type instead.
*/
def typeSig: Type
/** The type signature of this symbol seen as a member of given type `site`.
*/
def typeSigIn(site: Type): Type
/** The type constructor corresponding to this type symbol.
*/
def asTypeConstructor: Type // needed by LiftCode
/** A type reference that refers to this type symbol
* Note if symbol is a member of a class, one almost always is interested
* in `asTypeIn` with a site type instead.
*/
def asType: Type
/** A type reference that refers to this type symbol seen as a member of given type `site`.
*/
def asTypeIn(site: Type): Type
/** A fresh symbol with given position `pos` and name `name` that has
* the current symbol as its owner.
*/
def newNestedSymbol(pos: Position, name: Name): Symbol // needed by LiftCode
/** Low-level operation to set the symbol's flags
* @return the symbol itself
*/
def setInternalFlags(flags: Long): this.type // needed by LiftCode
/** Set symbol's type signature to given type
* @return the symbol itself
*/
def setTypeSig(tpe: Type): this.type // needed by LiftCode
/** Set symbol's annotations to given annotations `annots`.
*/
def setAnnotations(annots: AnnotationInfo*): this.type // needed by LiftCode
}
val NoSymbol: Symbol
}

View File

@ -542,8 +542,14 @@ trait Trees /*extends reflect.generic.Trees*/ { self: Universe =>
case class Select(qualifier: Tree, name: Name)
extends RefTree
def Select(qualifier: Tree, sym: Symbol): Select =
Select(qualifier, sym.name) setSymbol sym
/** Identifier <name> */
case class Ident(name: Name) extends RefTree { }
def Ident(sym: Symbol): Ident =
Ident(sym.name) setSymbol sym
class BackQuotedIdent(name: Name) extends Ident(name)

View File

@ -3,46 +3,324 @@ package api
trait Types { self: Universe =>
/** This class declares operations that are visible in a Type.
*/
abstract class AbsType {
/** The type symbol associated with the type, or `NoSymbol` for types
* that do not refer to a type symbol.
*/
def typeSymbol: Symbol
def decl(name: Name): Symbol
/** The defined or declared members with name `name` in this type;
* an OverloadedSymbol if several exist, NoSymbol if none exist.
* Alternatives of overloaded symbol appear in the order they are declared.
*/
def declaration(name: Name): Symbol
/** The member with given name, either directly declared or inherited,
* an OverloadedSymbol if several exist, NoSymbol if none exist.
*/
def member(name: Name): Symbol
/** The non-private member with given name, either directly declared or inherited,
* an OverloadedSymbol if several exist, NoSymbol if none exist.
*/
def nonPrivateMember(name: Name): Symbol
/** An iterable containing all members of this type (directly declared or inherited)
* Members appear in the linearization order of their owners.
* Members with the same owner appear in reverse order of their declarations.
*/
def allMembers: Iterable[Symbol]
/** An iterable containing all non-private members of this type (directly declared or inherited)
* Members appear in the linearization order of their owners.
* Members with the same owner appear in reverse order of their declarations.
*/
def nonPrivateMembers: Iterable[Symbol]
/** Substitute types in `to` for corresponding occurrences of references to
* symbols `from` in this type.
*/
def subst(from: List[Symbol], to: List[Type]): Type
/** If this is a parameterized types, the type arguments.
* Otherwise the empty list
*/
def typeArguments: List[Type]
/** Is this type a type constructor that is missing its type arguments?
*/
def isHigherKinded: Boolean
/**
* Expands type aliases and converts higher-kinded TypeRefs to PolyTypes.
* Functions on types are also implemented as PolyTypes.
*
* Example: (in the below, <List> is the type constructor of List)
* TypeRef(pre, <List>, List()) is replaced by
* PolyType(X, TypeRef(pre, <List>, List(X)))
*/
def normalize: Type
/** Does this type conform to given type argument `that`? */
def <:< (that: Type): Boolean
/** Is this type equivalent to given type argument `that`? */
def =:= (that: Type): Boolean
/** The list of all baseclasses of this type (including its own typeSymbol)
* in reverse linearization order, starting with the class itself and ending
* in class Any.
*/
def baseClasses: List[Symbol]
/** The least type instance of given class which is a supertype
* of this type. Example:
* {{{
* class D[T]
* class C extends p.D[Int]
* ThisType(C).baseType(D) = p.D[Int]
* }}}
*/
def baseType(clazz: Symbol): Type
/** This type as seen from prefix `pre` and class `clazz`. This means:
* Replace all thistypes of `clazz` or one of its subclasses
* by `pre` and instantiate all parameters by arguments of `pre`.
* Proceed analogously for thistypes referring to outer classes.
*
* Example:
* class D[T] { def m: T }
* class C extends p.D[Int]
* T.asSeenFrom(ThisType(C), D) (where D is owner of m)
* = Int
*/
def asSeenFrom(pre: Type, clazz: Symbol): Type
/** The erased type corresponding to this type after
* all transcformations from Scala to Java have been performed.
*/
def erasedType: Type
/** Apply `f` to each part of this type, returning
* a new type. children get mapped before their parents */
def map(f: Type => Type): Type
/** Apply `f` to each part of this type, for side effects only */
def foreach(f: Type => Unit)
/** Returns optionally first type (in a preorder traversal) which satisfies predicate `p`,
* or None if none exists.
*/
def find(p: Type => Boolean): Option[Type]
/** Is there part of this type which satisfies predicate `p`? */
def exists(p: Type => Boolean): Boolean
/** Does this type contain a reference to given symbol? */
def contains(sym: Symbol): Boolean
}
/** This class declares methods that are visible in a `SingleType`.
*/
trait AbsSingletonType extends AbsType {
/** The type underlying a singleton type */
def underlying: Type
/** Widen from singleton type to its underlying non-singleton
* base type by applying one or more `underlying` dereferences,
* identity for all other types.
*
* class Outer { class C ; val x: C }
* val o: Outer
* <o.x.type>.widen = o.C
*/
def widen: Type
}
/** This class declares methods that are visible in a `CompoundType` (i.e.
* a class/trait/object template or refined type of the form
* {{{
* P_1 with ... with P_m { D_1; ...; D_n }
* }}}
* P_n
*/
trait AbsCompoundType extends AbsType {
/** The list of parent types of this compound type */
def parents: List[Type]
/** The collection of declarations in this compound type
*/
def allDeclarations: Iterable[Symbol]
}
/** The type of Scala types, and also Scala type signatures.
* (No difference is internally made between the two).
*/
type Type >: Null <: AbsType
/** The type of Scala singleton types, i.e. types that are inhabited
* by only one nun-null value. These include types of the forms
* {{{
* C.this.type
* C.super.type
* x.type
* }}}
* as well as constant types.
*/
type SingletonType >: Null <: Type
/** This constant is used as a special value that indicates that no meaningful type exists.
*/
val NoType: Type
/** This constant is used as a special value denoting the empty prefix in a path dependent type.
* For instance `x.type` is represented as `SingleType(NoPrefix, <x>)`, where `<x>` stands for
* the symbol for `x`.
*/
val NoPrefix: Type
/** The `ThisType` type describes types of the form on the left with the
* correspnding ThisType representations to the right.
* {{{
* C.this.type ThisType(C)
* }}}
*/
type ThisType <: SingletonType
/** The constructor/deconstructor for `ThisType` instances. */
val ThisType: ThisTypeExtractor
type TypeRef <: Type
val TypeRef: TypeRefExtractor
/** An extractor class to create and pattern match with syntax `ThisType(sym)`
* where `sym` is the class prefix of the this type.
*/
abstract class ThisTypeExtractor {
def apply(sym: Symbol): Type
def unapply(tpe: ThisType): Option[Symbol]
}
/** The `TypeRef` type describes types of any of the forms on the left,
* with their TypeRef representations to the right.
* {{{
* T # C[T_1, ..., T_n] TypeRef(T, C, List(T_1, ..., T_n))
* p.C[T_1, ..., T_n] TypeRef(p.type, C, List(T_1, ..., T_n))
* C[T_1, ..., T_n] TypeRef(NoPrefix, C, List(T_1, ..., T_n))
* T # C TypeRef(T, C, Nil)
* p.C TypeRef(p.type, C, Nil)
* C TypeRef(NoPrefix, C, Nil)
* }}}
*/
type TypeRef <: Type
/** The constructor/deconstructor for `TypeRef` instances. */
val TypeRef: TypeRefExtractor
/** An extractor class to create and pattern match with syntax `TypeRef(pre, sym, args)`
* Here, `pre` is the prefix of the type reference, `sym` is the symbol
* referred to by the type reference, and `args` is a possible empty list of
* type argumenrts.
*/
abstract class TypeRefExtractor {
def apply(pre: Type, sym: Symbol, args: List[Type]): Type
def unapply(tpe: TypeRef): Option[(Type, Symbol, List[Type])]
}
/** The `SingleType` type describes types of any of the forms on the left,
* with their TypeRef representations to the right.
* {{{
* (T # x).type SingleType(T, x)
* p.x.type SingleType(p.type, x)
* x.type SingleType(NoPrefix, x)
*/
type SingleType <: SingletonType
/** The constructor/deconstructor for `SingleType` instances. */
val SingleType: SingleTypeExtractor
/** An extractor class to create and pattern match with syntax `SingleType(pre, sym)`
* Here, `pre` is the prefix of the single-type, and `sym` is the stable value symbol
* referred to by the single-type.
*/
abstract class SingleTypeExtractor {
def apply(pre: Type, sym: Symbol): Type
def unapply(tpe: SingleType): Option[(Type, Symbol)]
}
/** The `SuperType` type is not directly written, but arises when `C.super` is used
* as a prefix in a `TypeRef` or `SingleType`. It's internal presentation is
* {{{
* SuperType(thistpe, supertpe)
* }}}
* Here, `thistpe` is the type of the corresponding this-type. For instance,
* in the type arising from C.super, the `thistpe` part would be `ThisType(C)`.
* `supertpe` is the type of the super class referred to by the `super`.
*/
type SuperType <: SingletonType
/** The constructor/deconstructor for `SuperType` instances. */
val SuperType: SuperTypeExtractor
type TypeBounds <: Type
val TypeBounds: TypeBoundsExtractor
/** An extractor class to create and pattern match with syntax `SingleType(thistpe, supertpe)`
*/
abstract class SuperTypeExtractor {
def apply(thistpe: Type, supertpe: Type): Type
def unapply(tpe: SuperType): Option[(Type, Type)]
}
type CompoundType <: Type
type RefinedType <: CompoundType
val RefinedType: RefinedTypeExtractor
type ClassInfoType <: CompoundType
val ClassInfoType: ClassInfoTypeExtractor
type ConstantType <: Type
/** The `ConstantType` type is not directly written in user programs, but arises as the type of a constant.
* The REPL expresses constant types like Int(11). Here are some constants with their types.
* {{{
* 1 ConstantType(Constant(1))
* "abc" ConstantType(Constant("abc"))
* }}}
*/
type ConstantType <: SingletonType
/** The constructor/deconstructor for `ConstantType` instances. */
val ConstantType: ConstantTypeExtractor
type MethodType <: Type
val MethodType: MethodTypeExtractor
/** An extractor class to create and pattern match with syntax `ConstantType(constant)`
* Here, `constant` is the constant value represented by the type.
*/
abstract class ConstantTypeExtractor {
def apply(value: Constant): ConstantType
def unapply(tpe: ConstantType): Option[Constant]
}
/** A subtype of Type representing refined types as well as `ClassInfo` signatures.
*/
type CompoundType <: /*AbsCompoundType with*/ Type
/** The `RefinedType` type defines types of any of the forms on the left,
* with their RefinedType representations to the right.
* {{{
* P_1 with ... with P_m { D_1; ...; D_n} RefinedType(List(P_1, ..., P_m), Scope(D_1, ..., D_n))
* P_1 with ... with P_m RefinedType(List(P_1, ..., P_m), Scope())
* { D_1; ...; D_n} RefinedType(List(AnyRef), Scope(D_1, ..., D_n))
* }}}
*/
type RefinedType <: CompoundType
/** The constructor/deconstructor for `RefinedType` instances. */
val RefinedType: RefinedTypeExtractor
/** An extractor class to create and pattern match with syntax `RefinedType(parents, decls)`
* Here, `parents` is the list of parent types of the class, and `decls` is the scope
* containing all declarations in the class.
*/
abstract class RefinedTypeExtractor {
def apply(parents: List[Type], decls: Scope): RefinedType
/** An alternative constructor that passes in the synthetic classs symbol
* that backs the refined type. (Normally, a fresh class symbol is created automatically).
*/
def apply(parents: List[Type], decls: Scope, clazz: Symbol): RefinedType
def unapply(tpe: RefinedType): Option[(List[Type], Scope)]
}
type NullaryMethodType <: Type
val NullaryMethodType: NullaryMethodTypeExtractor
@ -55,52 +333,86 @@ trait Types { self: Universe =>
type AnnotatedType <: Type
val AnnotatedType: AnnotatedTypeExtractor
/** The `MethodType` type signature is used to indicate parameters and result type of a method
*/
type MethodType <: Type
abstract class ThisTypeExtractor {
def apply(sym: Symbol): Type
def unapply(tpe: ThisType): Option[Symbol]
/** The constructor/deconstructor for `MethodType` instances. */
val MethodType: MethodTypeExtractor
/** An extractor class to create and pattern match with syntax `MethodType(params, respte)`
* Here, `params` is a potentially empty list of parameter symbols of the method,
* and `restpe` is the result type of the method. If the method is curried, `restpe` would
* be another `MethodType`.
* Note: `MethodType(Nil, Int)` would be the type of a method defined with an empty parameter list.
* {{{
* def f(): Int
* }}}
* If the method is completely parameterless, as in
* {{{
* def f: Int
* }}}
* its type is a `NullaryMethodType`.
*/
abstract class MethodTypeExtractor {
def apply(params: List[Symbol], resultType: Type): MethodType
def unapply(tpe: MethodType): Option[(List[Symbol], Type)]
}
/** The `TypeBounds` type signature is used to indicate lower and upper type bounds
* of type parameters and abstract types. It is not a first-class type.
* If an abstract type or type parameter is declared with any of the forms
* on the left, its type signature is the TypeBounds type on the right.
* {{{
* T >: L <: U TypeBounds(L, U)
* T >: L TypeBounds(L, Any)
* T <: U TypeBounds(Nothing, U)
* }}}
*/
type TypeBounds <: Type
abstract class SingleTypeExtractor {
def apply(pre: Type, sym: Symbol): Type
def unapply(tpe: SingleType): Option[(Type, Symbol)]
}
abstract class SuperTypeExtractor {
def apply(thistpe: Type, supertpe: Type): Type
def unapply(tpe: SuperType): Option[(Type, Type)]
}
abstract class TypeRefExtractor {
def apply(pre: Type, sym: Symbol, args: List[Type]): Type
def unapply(tpe: TypeRef): Option[(Type, Symbol, List[Type])]
}
/** The constructor/deconstructor for `TypeBounds` instances. */
val TypeBounds: TypeBoundsExtractor
/** An extractor class to create and pattern match with syntax `TypeBound(lower, upper)`
* Here, `lower` is the lower bound of the `TypeBounds` pair, and `upper` is
* the upper bound.
*/
abstract class TypeBoundsExtractor {
def apply(lo: Type, hi: Type): TypeBounds
def unapply(tpe: TypeBounds): Option[(Type, Type)]
}
abstract class RefinedTypeExtractor {
def apply(parents: List[Type], decls: Scope): RefinedType
def apply(parents: List[Type], decls: Scope, clazz: Symbol): RefinedType
def unapply(tpe: RefinedType): Option[(List[Type], Scope)]
}
/** The `ClassInfo` type signature is used to define parents and declarations
* of classes, traits, and objects. If a class, trait, or object C is declared like this
* {{{
* C extends P_1 with ... with P_m { D_1; ...; D_n}
* }}}
* its `ClassInfo` type has the following form:
* {{{
* ClassInfo(List(P_1, ..., P_m), Scope(D_1, ..., D_n), C)
* }}}
*/
type ClassInfoType <: CompoundType
/** The constructor/deconstructor for `ClassInfoType` instances. */
val ClassInfoType: ClassInfoTypeExtractor
/** An extractor class to create and pattern match with syntax `ClassInfo(parents, decls, clazz)`
* Here, `parents` is the list of parent types of the class, `decls` is the scope
* containing all declarations in the class, and `clazz` is the symbol of the class
* itself.
*/
abstract class ClassInfoTypeExtractor {
def apply(parents: List[Type], decls: Scope, clazz: Symbol): ClassInfoType
def unapply(tpe: ClassInfoType): Option[(List[Type], Scope, Symbol)]
}
abstract class ConstantTypeExtractor {
def apply(value: Constant): ConstantType
def unapply(tpe: ConstantType): Option[Constant]
}
abstract class MethodTypeExtractor {
def apply(params: List[Symbol], resultType: Type): MethodType
def unapply(tpe: MethodType): Option[(List[Symbol], Type)]
}
abstract class NullaryMethodTypeExtractor {
def apply(resultType: Type): NullaryMethodType
@ -121,5 +433,11 @@ trait Types { self: Universe =>
def apply(annotations: List[AnnotationInfo], underlying: Type, selfsym: Symbol): AnnotatedType
def unapply(tpe: AnnotatedType): Option[(List[AnnotationInfo], Type, Symbol)]
}
/** The least upper bound wrt <:< of a list of types */
def lub(xs: List[Type]): Type
/** The greatest lower bound wrt <:< of a list of types */
def glb(ts: List[Type]): Type
}

View File

@ -10,7 +10,7 @@ scala> def codeOf[A](code: Code[A]) = code
codeOf: [A](code: scala.reflect.Code[A])scala.reflect.Code[A]
scala> codeOf((x: Iterable[_]) => throw new Exception)
res0: scala.reflect.Code[Iterable[_] => Nothing] = Code(manifest = scala.Function1[scala.collection.Iterable[Any], Nothing])
res0: scala.reflect.Code[Iterable[_] => Nothing] = Code(tree = ((x: Iterable[Any]) => throw new scala.`package`.Exception()), manifest = scala.Function1[scala.collection.Iterable[Any], Nothing])
scala>