package dotty.tools
package dotc
package core
import Periods._
import Transformers._
import Names._, Scopes._
import Flags._
import java.lang.AssertionError
import Decorators._
import Symbols._
import Contexts._
import SymDenotations._
import Types._, Annotations._, Positions._, StdNames._, Trees._
import Denotations.{ Denotation, SingleDenotation, MultiDenotation }
import collection.mutable
import io.AbstractFile
/** Creation methods for symbols */
trait Symbols { this: Context =>
// ---- Fundamental symbol creation methods ----------------------------------
def newLazySymbol[N <: Name](owner: Symbol, name: N, initFlags: FlagSet, completer: SymCompleter, coord: Coord = NoCoord) =
new Symbol(coord, new LazySymDenotation(_, owner, name, initFlags, completer)) {
type ThisName = N
}
def newLazyClassSymbol(owner: Symbol, name: TypeName, initFlags: FlagSet, completer: ClassCompleter, assocFile: AbstractFile = null, coord: Coord = NoCoord) =
new ClassSymbol(coord, new LazyClassDenotation(_, owner, name, initFlags, completer)(this), assocFile)
def newLazyModuleSymbols(owner: Symbol,
name: TermName,
flags: FlagSet,
completer: ClassCompleter,
assocFile: AbstractFile = null,
coord: Coord = NoCoord): (TermSymbol, ClassSymbol)
= {
val module = newLazySymbol(
owner, name, flags | ModuleCreationFlags, new ModuleCompleter(condensed), coord)
val modcls = newLazyClassSymbol(
owner, name.toTypeName, flags | ModuleClassCreationFlags, completer, assocFile, coord)
module.denot.asInstanceOf[LazySymDenotation].info =
TypeRef(owner.thisType(ctx), modcls)
modcls.denot.asInstanceOf[LazyClassDenotation].selfType =
TermRef(owner.thisType, module)
(module, modcls)
}
def newSymbol[N <: Name](owner: Symbol, name: N, flags: FlagSet, info: Type, privateWithin: Symbol = NoSymbol, coord: Coord = NoCoord) =
new Symbol(coord, CompleteSymDenotation(_, owner, name, flags, info, privateWithin)) {
type ThisName = N
}
def newClassSymbol(
owner: Symbol,
name: TypeName,
flags: FlagSet,
parents: List[TypeRef],
privateWithin: Symbol = NoSymbol,
optSelfType: Type = NoType,
decls: Scope = newScope,
assocFile: AbstractFile = null,
coord: Coord = NoCoord)
=
new ClassSymbol(coord, new CompleteClassDenotation(
_, owner, name, flags, parents, privateWithin, optSelfType, decls)(this), assocFile)
def newModuleSymbols(
owner: Symbol,
name: TermName,
flags: FlagSet,
classFlags: FlagSet,
parents: List[TypeRef],
privateWithin: Symbol = NoSymbol,
decls: Scope = newScope,
assocFile: AbstractFile = null,
coord: Coord = NoCoord): (TermSymbol, ClassSymbol)
= {
val module = newLazySymbol(
owner, name, flags | ModuleCreationFlags,
new ModuleCompleter(condensed), coord)
val modcls = newClassSymbol(
owner, name.toTypeName, classFlags | ModuleClassCreationFlags, parents, privateWithin,
optSelfType = TermRef(owner.thisType, module),
decls, assocFile, coord)
module.denot.asInstanceOf[LazySymDenotation].info =
TypeRef(owner.thisType, modcls)
(module, modcls)
}
def newStubSymbol(owner: Symbol, name: Name, file: AbstractFile = null): Symbol = {
def stub = new StubCompleter(ctx.condensed)
name match {
case name: TermName => ctx.newLazyModuleSymbols(owner, name, EmptyFlags, stub, file)._1
case name: TypeName => ctx.newLazyClassSymbol(owner, name, EmptyFlags, stub, file)
}
}
// ---- Derived symbol creation methods -------------------------------------
def newLazyPackageSymbols(owner: Symbol, name: TermName, completer: ClassCompleter) =
newLazyModuleSymbols(owner, name, PackageCreationFlags, completer)
def newPackageSymbols(
owner: Symbol,
name: TermName,
decls: Scope = newScope) =
newModuleSymbols(
owner, name, PackageCreationFlags, PackageCreationFlags, Nil, NoSymbol, decls)
def newLocalDummy(cls: Symbol, coord: Coord = NoCoord) =
newSymbol(cls, nme.localDummyName(cls), EmptyFlags, NoType)
def newImportSymbol(expr: Shared[Type], coord: Coord = NoCoord) =
newSymbol(NoSymbol, nme.IMPORT, EmptyFlags, ImportType(expr), coord = coord)
def newConstructor(cls: ClassSymbol, flags: FlagSet, paramNames: List[TermName], paramTypes: List[Type], privateWithin: Symbol = NoSymbol, coord: Coord = NoCoord) =
newSymbol(cls, nme.CONSTRUCTOR, flags | Method, MethodType(paramNames, paramTypes)(_ => cls.typeConstructor), privateWithin, coord)
def newDefaultConstructor(cls: ClassSymbol) =
newConstructor(cls, EmptyFlags, Nil, Nil)
def newSelfSym(cls: ClassSymbol) =
ctx.newSymbol(cls, nme.THIS, SyntheticArtifact, cls.selfType)
/** Create new type parameters with given owner, names, and flags.
* @param boundsFn A function that, given type refs to the newly created
* parameters returns a list of their bounds.
*/
def newTypeParams(
owner: Symbol,
names: List[TypeName],
flags: FlagSet,
boundsFn: List[TypeRef] => List[Type]) = {
lazy val tparams: List[TypeSymbol] = names map { name =>
newLazySymbol(owner, name, flags | TypeParam, { denot =>
denot.info = bounds(denot.symbol.asType)
})
}
lazy val bounds = (tparams zip boundsFn(tparams map (_.typeConstructor))).toMap
tparams
}
type OwnerMap = Symbol => Symbol
/** Map given symbols, subjecting all types to given type map and owner map. Cross symbol
* references are brought over from originals to copies.
* Do not copy any symbols if all their attributes stay the same.
*/
def mapSymbols(originals: List[Symbol], typeMap: TypeMap = IdentityTypeMap, ownerMap: OwnerMap = identity) = {
if (originals forall (sym =>
sym.isInvariantUnder(typeMap) && ownerMap(sym.owner) == sym.owner))
originals
else {
lazy val copies: List[Symbol] = originals map { orig =>
if (orig.isClass)
newLazyClassSymbol(ownerMap(orig.owner), orig.asClass.name, orig.flags, copyClassCompleter, orig.asClass.associatedFile, orig.coord)
else
newLazySymbol(ownerMap(orig.owner), orig.name, orig.flags, copySymCompleter, orig.coord)
}
lazy val prev = (copies zip originals).toMap
lazy val copyTypeMap = typeMap andThen ((tp: Type) => tp.substSym(originals, copies))
lazy val mapper = new TypedTrees.TreeMapper(typeMap, ownerMap)
def mapAnnotations(denot: isLazy[_]): Unit = {
denot.annotations = denot.annotations.mapConserve(mapper.apply)
denot.privateWithin = ownerMap(denot.privateWithin)
}
def copySymCompleter(denot: LazySymDenotation): Unit = {
denot.info = copyTypeMap(prev(denot.symbol).info)
mapAnnotations(denot)
}
def copyClassCompleter(denot: LazyClassDenotation): Unit = {
denot.parents = prev(denot.symbol).asClass.parents mapConserve (
tp => copyTypeMap(tp).asInstanceOf[TypeRef])
denot.selfType = copyTypeMap(prev(denot.symbol).asClass.selfType)
denot.decls = copyTypeMap.mapOver(prev(denot.symbol).asClass.decls)
mapAnnotations(denot)
}
copies
}
}
// ----- Locating predefined symbols ----------------------------------------
def requiredPackage(path: PreName): TermSymbol =
base.staticRef(path.toTermName).requiredSymbol(_.isPackage).asTerm
def requiredClass(path: PreName): ClassSymbol =
base.staticRef(path.toTypeName).requiredSymbol(_.isClass).asClass
def requiredModule(path: PreName): TermSymbol =
base.staticRef(path.toTermName).requiredSymbol(_.isModule).asTerm
}
object Symbols {
/** A Symbol represents a Scala definition/declaration or a package.
*/
class Symbol(val coord: Coord, denotf: Symbol => SymDenotation) extends DotClass {
type ThisName <: Name
/** Is symbol different from NoSymbol? */
def exists = true
/** This symbol, if it exists, otherwise the result of evaluating `that` */
def orElse(that: => Symbol) = if (exists) this else that
/** If this symbol satisfies predicate `p` this symbol, otherwise `NoSymbol` */
def filter(p: Symbol => Boolean): Symbol = if (p(this)) this else NoSymbol
private[this] var _id: Int = _
/** The unique id of this symbol */
def id(implicit ctx: Context) = {
if (_id == 0) _id = ctx.nextId
_id
}
/** The last denotation of this symbol */
private[this] var lastDenot: SymDenotation = denotf(this)
/** The current denotation of this symbol */
final def denot(implicit ctx: Context): SymDenotation = {
var denot = lastDenot
if (!(denot.validFor contains ctx.period)) denot = denot.current.asInstanceOf[SymDenotation]
denot
}
/** Subclass tests and casts */
final def isTerm(implicit ctx: Context): Boolean = denot.isTerm
final def isType(implicit ctx: Context): Boolean = denot.isType
final def isClass: Boolean = isInstanceOf[ClassSymbol]
final def asTerm(implicit ctx: Context): TermSymbol = { assert(isTerm, this); asInstanceOf[TermSymbol] }
final def asType(implicit ctx: Context): TypeSymbol = { assert(isType, this); asInstanceOf[TypeSymbol] }
final def asClass: ClassSymbol = asInstanceOf[ClassSymbol]
/** A unique, densely packed integer tag for each class symbol, -1
* for all other symbols. To save memory, this method
* should be called only if class is a super class of some other class.
*/
def superId: Int = -1
final def entered(implicit ctx: Context): this.type = {
this.owner.info.decls.enter(this)
this
}
/** Is symbol a primitive value class? */
def isPrimitiveValueClass(implicit ctx: Context) = defn.ScalaValueClasses contains this
/** Is symbol a phantom class for which no runtime representation exists? */
def isPhantomClass(implicit ctx: Context) = defn.PhantomClasses contains this
/** The current name of this symbol */
final def name(implicit ctx: Context): ThisName = denot.name.asInstanceOf[ThisName]
/** The source or class file from which this class was generated, null if not applicable. */
def associatedFile(implicit ctx: Context): AbstractFile =
this.denot.topLevelClass.symbol.associatedFile
/** The class file from which this class was generated, null if not applicable. */
final def binaryFile(implicit ctx: Context): AbstractFile =
pickFile(associatedFile, classFile = true)
/** The source file from which this class was generated, null if not applicable. */
final def sourceFile(implicit ctx: Context): AbstractFile =
pickFile(associatedFile, classFile = false)
/** Desire to re-use the field in ClassSymbol which stores the source
* file to also store the classfile, but without changing the behavior
* of sourceFile (which is expected at least in the IDE only to
* return actual source code.) So sourceFile has classfiles filtered out.
*/
private def pickFile(file: AbstractFile, classFile: Boolean): AbstractFile =
if ((file eq null) || classFile != (file.path endsWith ".class")) null else file
def show(implicit ctx: Context): String = ctx.show(this)
def showLocated(implicit ctx: Context): String = ctx.showLocated(this)
def showDcl(implicit ctx: Context): String = ctx.showDcl(this)
def showKind(implicit ctx: Context): String = ctx.showKind(this)
def showName(implicit ctx: Context): String = ctx.showName(this)
def showFullName(implicit ctx: Context): String = ctx.showFullName(this)
}
type TermSymbol = Symbol { type ThisName = TermName }
type TypeSymbol = Symbol { type ThisName = TypeName }
class ClassSymbol(coord: Coord, denotf: ClassSymbol => ClassDenotation, assocFile: AbstractFile) extends Symbol(coord, s => denotf(s.asClass)) {
type ThisName = TypeName
/** The source or class file from which this class was generated, null if not applicable. */
override def associatedFile(implicit ctx: Context): AbstractFile =
if (this.owner.isPackageClass) assocFile
else super.associatedFile
final def classDenot(implicit ctx: Context): ClassDenotation =
denot.asInstanceOf[ClassDenotation]
private var superIdHint: Int = -1
def superId(implicit ctx: Context): Int = {
val hint = superIdHint
val key = this.typeConstructor
if (hint >= 0 && hint <= ctx.lastSuperId && (ctx.classOfId(hint) eq key))
hint
else {
val id = ctx.superIdOfClass get key match {
case Some(id) =>
id
case None =>
val id = ctx.nextSuperId
ctx.superIdOfClass(key) = id
ctx.classOfId(id) = key
id
}
superIdHint = id
id
}
}
}
class ErrorSymbol(val underlying: Symbol, msg: => String)(implicit ctx: Context) extends Symbol(NoCoord, sym => underlying.denot) {
type ThisName = underlying.ThisName
}
object NoSymbol extends Symbol(NoCoord, sym => NoDenotation) {
override def exists = false
}
implicit class Copier[N <: Name](sym: Symbol { type ThisName = N })(implicit ctx: Context) {
/** Copy a symbol, overriding selective fields */
def copy(
owner: Symbol = sym.owner,
name: N = sym.name,
flags: FlagSet = sym.flags,
privateWithin: Symbol = sym.privateWithin,
info: Type = sym.info,
coord: Coord = sym.coord): Symbol =
if (sym.isClass) {
assert(info eq sym.info)
new ClassCopier(sym.asClass).copy(owner, name.asTypeName, flags, privateWithin = privateWithin, coord = coord)
} else
ctx.newSymbol(owner, name, flags, info, privateWithin, sym.coord)
}
implicit class ClassCopier(cls: ClassSymbol)(implicit ctx: Context) {
/** Copy a class symbol, overriding selective fields */
def copy(
owner: Symbol = cls.owner,
name: TypeName = cls.name.asTypeName,
flags: FlagSet = cls.flags,
parents: List[TypeRef] = cls.classDenot.parents,
privateWithin: Symbol = cls.privateWithin,
selfType: Type = cls.selfType,
decls: Scope = cls.decls,
associatedFile: AbstractFile = cls.associatedFile,
coord: Coord = cls.coord) =
ctx.newClassSymbol(owner, name, flags, parents, privateWithin, selfType, decls, associatedFile, coord)
}
implicit def defn(implicit ctx: Context): Definitions = ctx.definitions
implicit def toFlagSet(sym: Symbol)(implicit ctx: Context): FlagSet = sym.flags
implicit def toDenot(sym: Symbol)(implicit ctx: Context): SymDenotation = sym.denot
implicit def toClassDenot(cls: ClassSymbol)(implicit ctx: Context): ClassDenotation = cls.classDenot
}