aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc/core/Denotations.scala
diff options
context:
space:
mode:
Diffstat (limited to 'src/dotty/tools/dotc/core/Denotations.scala')
-rw-r--r--src/dotty/tools/dotc/core/Denotations.scala671
1 files changed, 386 insertions, 285 deletions
diff --git a/src/dotty/tools/dotc/core/Denotations.scala b/src/dotty/tools/dotc/core/Denotations.scala
index 75f040e1d..12b522427 100644
--- a/src/dotty/tools/dotc/core/Denotations.scala
+++ b/src/dotty/tools/dotc/core/Denotations.scala
@@ -1,335 +1,436 @@
package dotty.tools.dotc
package core
-import Periods._, Contexts._, Symbols._, References._, Names._
-import Types._, Flags._, Decorators._
-import Scopes.Scope
-import collection.mutable
-import collection.immutable.BitSet
-
-trait Denotations { self: Context =>
-
- /** A set for hash consing superclass bitsets */
- private val uniqueBits = new util.HashSet[BitSet]("superbits", 1024)
-
-}
-
+import SymDenotations.{SymDenotation, NoDenotation}
+import Contexts.Context
+import Names.Name
+import Names.TypeName
+import Symbols.NoSymbol
+import Symbols.Symbol
+import Types._, Periods._, Flags._, Transformers._
+import Decorators.SymbolIteratorDecorator
+
+
+/** Denotations represent the meaning of symbols and named types.
+ * The following diagram shows how the principal types of denotations
+ * and their denoting entities relate to each other. Lines ending in
+ * a down-arrow `v` are member methods. The two methods shown in the diagram are
+ * "symbol" and "deref". Both methods are parameterized by the current context,
+ * and are effectively indexed by current period.
+ *
+ * Lines ending in a horizontal line mean subtying (right is a subtype of left).
+ *
+ * NamedType------NamedTypeWithSignature
+
+ * | | Symbol---------ClassSymbol
+ * | | | |
+ * | denot | denot | denot | denot
+ * v v v v
+ * Denotation-+-----SingleDenotation-+------SymDenotation-+----ClassDenotation-+--CompleteClassDenotation
+ * | | | +--LazyClassDenotation
+ * +-----MultiDenotation | |
+ * | +--CompleteSymDenotation
+ * | +--LazySymDenotation
+ * |
+ * +--UniqueRefDenotation
+ * +--JointRefDenotation
+ *
+ * Here's a short summary of the classes in this diagram.
+ *
+ * NamedType A type consisting of a prefix type and a name, with fields
+ * prefix: Type
+ * name: Name
+ * NamedTypeWithSignature A named type that has in addition a signature to select an overloaded variant, with new field
+ * signature: Signature
+ * Symbol A label for a definition or declaration in one compiler run
+ * ClassSymbol A symbol representing a class
+ * Denotation The meaning of a named type or symbol during a period
+ * MultiDenotation A denotation representing several overloaded members
+ * SingleDenotation A denotation representing a non-overloaded member or definition, with main fields
+ * symbol: Symbol
+ * info: Type
+ * UniqueRefDenotation A denotation referring to a single definition with some member type
+ * JointRefDenotation A denotation referring to a member that could resolve to several definitions
+ * SymDenotation A denotation representing a single definition with its original type, with main fields
+ * name: Name
+ * owner: Symbol
+ * flags: Flags
+ * privateWithin: Symbol
+ * annotations: List[Annotation]
+ * ClassDenotation A denotation representing a single class definition, with new fields
+ * typeParams: List[TypeSymbol]
+ * parents: List[Type]
+ * decls: Scope
+ * LazySymDenotation A sym-denotation with fields that are computed on demand
+ * CompleteSymDenotation A sym-denotation that has all fields completed
+ * LazyClassDenotation A class denotation with fields that are computed on demand
+ * CompleteClassDenotation A class denotation that has all fields completed
+ */
object Denotations {
- abstract class Denotation {
-
- /** The validity interval of this symbol */
- var valid: Interval = Nowhere
-
- /** The next instance of this symbol in the same run */
- private[core] var nextInRun: Denotation = this
-
- /**
- * The version of this symbol that was valid in the first phase
- * of this run
- */
- def initial: Denotation = {
- var sym = nextInRun
- while (sym.valid > this.valid) sym = sym.nextInRun
- sym
- }
-
- def owner: Symbol = ???
-
- def name: Name = ???
-
- def flags: FlagSet = ???
-
- def setFlag(flag: FlagSet): Unit = ???
-
- def tpe: Type = ???
-
- def info: Type = ???
-
- /* Validity and instance handling:
- *
- * Symbols have an interval of validity, defined
- * by their `valid` fields.
- *
- * There may be several symbols with different validity
- * representing the same underlying symbol at different phases.
- * These are called a "flock". Flock members are generated by
- * @see SymRef.trackSym. Flock members are connected in a ring
- * with their `nextInFlock` fields.
- *
- * There are the following invariants converning flock members
- *
- * 1) validity intervals must be non-overlapping
- * 2) the union of all validity intervals must be a contiguous
- * interval starting in FirstPhaseId.
- */
-
- /** is this symbol a type? */
+ /** The signature of a denotation.
+ * Overloaded denotations with the same name are distinguished by
+ * their signatures. A signature is a list of the fully qualified names
+ * of the type symbols of the erasure of the parameters of the
+ * denotation. For instance a definition
+ *
+ * def f(x: Int)(y: List[String]): String
+ *
+ * would have signature
+ *
+ * List("scala.Int".toTypeName, "scala.collection.immutable.List".toTypeName)
+ */
+ type Signature = List[TypeName]
+
+ /** The signature of a val or parameterless def, as opposed
+ * to List(), which is the signature of a zero-parameter def.
+ */
+ val NullSignature = List(Names.EmptyTypeName)
+
+ /** A denotation is the result of resolving
+ * a name (either simple identifier or select) during a given period.
+ *
+ * Denotation has two subclasses: MultiDenotation and SingleDenotation.
+ *
+ * A SingleDenotation refers to a `symbol` and a type (`info`) that the symbol has
+ * when seen from the reference.
+ *
+ * Denotations can be combined with `&` and `|`.
+ * & is conjunction, | is disjunction.
+ *
+ * `&` will create an overloaded denotation from two
+ * non-overloaded denotations if their signatures differ.
+ * Analogously `|` of two denotations with different signatures will give
+ * an empty denotation `NoDenotation`.
+ *
+ * A denotation might refer to `NoSymbol`. This is the case if the denotation
+ * was produced from a disjunction of two denotations with different symbols
+ * and there was no common symbol in a superclass that could substitute for
+ * both symbols. Here is an example:
+ *
+ * Say, we have:
+ *
+ * class A { def f: A }
+ * class B { def f: B }
+ * val x: A | B = if (???) new A else new B
+ * val y = x.f
+ *
+ * Then the denotation of `y` is `SingleDenotation(NoSymbol, A | B)`.
+ */
+ abstract class Denotation extends DotClass {
+
+ /** The referencing symbol, exists only for non-overloaded denotations */
+ def symbol: Symbol
+
+ /** The type info of the denotation, exists only for non-overloaded denotations */
+ def info: Type
+
+ /** The period during which this denotation is valid. */
+ def validFor: Period
+
+ /** Is this a reference to a type symbol? */
def isType: Boolean = false
- /** is this symbol a class? */
- def isClass: Boolean = false
+ /** Is this a reference to a term symbol? */
+ def isTerm: Boolean = false
- /** is this symbol a method? */
- def isMethod: Boolean = false
+ /** Is this denotation overloaded? */
+ def isOverloaded = isInstanceOf[MultiDenotation]
- /** is this symbol the result of an erroneous definition? */
- def isError: Boolean = false
+ /** The signature of the denotation */
+ def signature: Signature
- def withType(tp: Type): Denotation = ???
- }
+ /** Resolve overloaded denotation to pick the one with the given signature */
+ def atSignature(sig: Signature): SingleDenotation
- object NameFilter {
- final val WordSizeLog = 6
- final val DefinedNamesWords = 16
- final val DefinedNamesSize = DefinedNamesWords << WordSizeLog
- final val DefinedNamesMask = DefinedNamesSize - 1
+ /** The variant of this denotation that's current in the given context. */
+ def current(implicit ctx: Context): Denotation
- type FingerPrint = Array[Long]
+ def exists: Boolean = true
- def includeName(bits: FingerPrint, name: Name): Unit = {
- val hash = name.start & DefinedNamesMask
- bits(hash >> 6) |= (1 << hash)
- }
+ def filter(p: Symbol => Boolean)(implicit ctx: Context): Denotation
- def includeFingerPrint(bits1: FingerPrint, bits2: FingerPrint): Unit =
- for (i <- 0 until DefinedNamesWords) bits1(i) |= bits2(i)
+ /** Form a denotation by conjoining with denotation `that` */
+ def & (that: Denotation)(implicit ctx: Context): Denotation =
+ if (this eq that) this
+ else if (!this.exists) that
+ else if (!that.exists) this
+ else that match {
+ case that: SingleDenotation =>
+ val r = mergeDenot(this, that)
+ if (r ne NoDenotation) r else MultiDenotation(this, that)
+ case that @ MultiDenotation(denot1, denot2) =>
+ this & denot1 & denot2
+ }
- def containsName(bits: FingerPrint, name: Name): Boolean = {
- val hash = name.start & DefinedNamesMask
- (bits(hash >> 6) & (1 << hash)) != 0
+ /** Try to merge denot1 and denot2 without adding a new signature.
+ * If unsuccessful, return NoDenotation.
+ */
+ private def mergeDenot(denot1: Denotation, denot2: SingleDenotation)(implicit ctx: Context): Denotation = denot1 match {
+ case denot1 @ MultiDenotation(denot11, denot12) =>
+ val d1 = mergeDenot(denot11, denot2)
+ if (d1 ne NoDenotation) d1 else mergeDenot(denot12, denot2)
+ case denot1: SingleDenotation =>
+ if (denot1 eq denot2) denot1
+ else if (denot1.signature == denot2.signature) {
+ def isEligible(sym1: Symbol, sym2: Symbol) =
+ if (sym1.isType) !sym1.isClass
+ else sym1.isConcrete || sym2.isDeferred || !sym2.exists
+ def normalize(info: Type) =
+ if (isType) info.bounds else info
+ val sym1 = denot1.symbol
+ val info1 = denot1.info
+ val sym2 = denot2.symbol
+ val info2 = denot2.info
+ val sym1Eligible = isEligible(sym1, sym2)
+ val sym2Eligible = isEligible(sym2, sym1)
+ val bounds1 = normalize(info1)
+ val bounds2 = normalize(info2)
+ if (sym2Eligible && bounds2 <:< bounds1) denot2
+ else if (sym1Eligible && bounds1 <:< bounds2) denot1
+ else new JointRefDenotation(
+ if (sym2Eligible) sym2 else sym1,
+ bounds1 & bounds2,
+ denot1.validFor & denot2.validFor)
+ } else NoDenotation
}
- def newNameFilter: FingerPrint = new Array[Long](DefinedNamesWords)
- }
-
- class ClassDenotation(val parents: List[Type], val decls: Scope, val clazz: ClassSymbol) extends Denotation {
- import NameFilter._
- import util.LRU8Cache
+ def | (that: Denotation)(pre: Type)(implicit ctx: Context): Denotation = {
- def typeParams: List[TypeSymbol] = ???
+ def lubSym(sym1: Symbol, sym2: Symbol): Symbol = {
+ def qualifies(sym: Symbol) =
+ sym.isAccessibleFrom(pre) && sym2.owner.isSubClass(sym.owner)
+ sym1.allOverriddenSymbols findSymbol qualifies
+ }
- private var memberCacheVar: LRU8Cache[Name, RefSet] = null
+ def throwError = throw new MatchError(s"$this | $that")
- private def memberCache: LRU8Cache[Name, RefSet] = {
- if (memberCacheVar == null) memberCacheVar = new LRU8Cache
- memberCacheVar
+ if (this eq that) this
+ else if (!this.exists) this
+ else if (!that.exists) that
+ else this match {
+ case denot1 @ MultiDenotation(denot11, denot12) =>
+ denot1.derivedMultiDenotation((denot11 | that)(pre), (denot12 | that)(pre))
+ case _ =>
+ that match {
+ case denot2 @ MultiDenotation(denot21, denot22) =>
+ denot2.derivedMultiDenotation((this | denot21)(pre), (this | denot22)(pre))
+ case denot2: SingleDenotation =>
+ this match {
+ case denot1: SingleDenotation =>
+ if (denot1.signature != denot2.signature) NoDenotation
+ else new JointRefDenotation(
+ lubSym(denot1.symbol, denot2.symbol),
+ denot1.info | denot2.info,
+ denot1.validFor & denot2.validFor)
+ case _ =>
+ throwError
+ }
+ case _ =>
+ throwError
+ }
+ }
}
+ }
- private var thisTypeCache: ThisType = null
-
- def thisType(implicit ctx: Context): Type = {
- if (thisTypeCache == null)
- thisTypeCache = ThisType(clazz)
- thisTypeCache
- }
+ /** The class of overloaded denotations
+ * @param variants The overloaded variants indexed by thheir signatures.
+ */
+ case class MultiDenotation(denot1: Denotation, denot2: Denotation) extends Denotation {
+ final override def isType = false
+ final override def isTerm = true
+ def derivedMultiDenotation(d1: Denotation, d2: Denotation) =
+ if ((d1 eq denot1) && (d2 eq denot2)) this else MultiDenotation(d1, d2)
+ def symbol = unsupported("symbol")
+ def info = unsupported("info")
+ def signature = unsupported("signature")
+ def filter(p: Symbol => Boolean)(implicit ctx: Context): Denotation =
+ (denot1 filter p) & (denot2 filter p)
+ def atSignature(sig: Signature): SingleDenotation =
+ denot1.atSignature(sig) orElse denot2.atSignature(sig)
+ def validFor = denot1.validFor & denot2.validFor
+ def current(implicit ctx: Context): Denotation =
+ derivedMultiDenotation(denot1.current, denot2.current)
+ }
- private var typeConstructorCache: Type = null
+ abstract class SingleDenotation extends Denotation with DenotationSet {
- def typeConstructor(implicit ctx: Context): Type = {
- if (typeConstructorCache == null)
- typeConstructorCache = NamedType(thisType, clazz.name)
- typeConstructorCache
+ override def isType = symbol.isType
+ override def isTerm = symbol.isTerm
+ override def signature: Signature = {
+ def sig(tp: Type): Signature = tp match {
+ case tp: PolyType =>
+ tp.resultType match {
+ case mt: MethodType => mt.signature
+ case _ => List()
+ }
+ case mt: MethodType => mt.signature
+ case _ => NullSignature
+ }
+ if (isType) NullSignature else sig(info)
}
- private var typeTemplateCache: Type = null
+ def derivedSingleDenotation(s: Symbol, i: Type): SingleDenotation =
+ if ((s eq symbol) && (i eq info)) this else copy(s, i)
- def typeTemplate(implicit ctx: Context): Type = {
- if (typeTemplateCache == null)
- AppliedType.make(typeConstructor, typeParams map (_.typeConstructor))
- typeTemplateCache
- }
+ protected def copy(s: Symbol, i: Type): SingleDenotation = this
- private var baseClassesVar: List[ClassSymbol] = null
- private var superClassBitsVar: BitSet = null
-
- private def computeSuperClassBits(implicit ctx: Context): Unit = {
- val seen = new mutable.BitSet
- val locked = new mutable.BitSet
- def addBaseClasses(bcs: List[ClassSymbol], to: List[ClassSymbol])
- : List[ClassSymbol] = bcs match {
- case bc :: bcs1 =>
- val id = bc.superId
- if (seen contains id) to
- else if (locked contains id) throw new CyclicReference(clazz)
- else {
- locked += id
- val bcs1added = addBaseClasses(bcs1, to)
- seen += id
- if (bcs1added eq bcs1) bcs else bc :: bcs1added
- }
- case _ =>
- to
- }
- def addParentBaseClasses(ps: List[Type], to: List[ClassSymbol]): List[ClassSymbol] = ps match {
- case p :: ps1 =>
- addBaseClasses(p.baseClasses, addParentBaseClasses(ps1, to))
- case _ =>
- to
- }
- baseClassesVar = clazz :: addParentBaseClasses(parents, Nil)
- superClassBitsVar = ctx.root.uniqueBits.findEntryOrUpdate(seen.toImmutable)
- }
+ def orElse(that: => SingleDenotation) = if (this.exists) this else that
- def superClassBits(implicit ctx: Context): BitSet = {
- if (superClassBitsVar == null) computeSuperClassBits
- superClassBitsVar
- }
+ def filter(p: Symbol => Boolean)(implicit ctx: Context): SingleDenotation =
+ if (p(symbol)) this else NoDenotation
- def baseClasses(implicit ctx: Context): List[ClassSymbol] = {
- if (baseClassesVar == null) computeSuperClassBits
- baseClassesVar
- }
+ def atSignature(sig: Signature): SingleDenotation =
+ if (sig == signature) this else NoDenotation
- /** Is this class a subclass of `clazz`? */
- final def isSubClass(clazz: ClassSymbol)(implicit ctx: Context): Boolean = {
- superClassBits contains clazz.superId
- }
+ // ------ Transformations -----------------------------------------
- private var definedFingerPrintCache: FingerPrint = null
+ private[this] var _validFor: Period = Nowhere
- private def computeDefinedFingerPrint(implicit ctx: Context): FingerPrint = {
- var bits = newNameFilter
- var e = decls.lastEntry
- while (e != null) {
- includeName(bits, clazz.name)
- e = e.prev
- }
- var ps = parents
- while (ps.nonEmpty) {
- val parent = ps.head.typeSymbol
- parent.deref match {
- case classd: ClassDenotation =>
- includeFingerPrint(bits, classd.definedFingerPrint)
- parent.deref setFlag Frozen
- case _ =>
- }
- ps = ps.tail
- }
- definedFingerPrintCache = bits
- bits
- }
+ def validFor = _validFor
+ def validFor_=(p: Period) =
+ _validFor = p
- /** Enter a symbol in current scope.
- * Note: We require that this does not happen after the first time
- * someone does a findMember on a subclass.
+ /** The next SingleDenotation in this run, with wrap-around from last to first.
+ *
+ * There may be several `SingleDenotation`s with different validity
+ * representing the same underlying definition at different phases.
+ * These are called a "flock". Flock members are generated by
+ * @See current. Flock members are connected in a ring
+ * with their `nextInRun` fields.
+ *
+ * There are the following invariants converning flock members
+ *
+ * 1) validity periods must be non-overlapping
+ * 2) the union of all validity periods must be a contiguous
+ * interval starting in FirstPhaseId.
*/
- def enter(sym: Symbol)(implicit ctx: Context) = {
- require((clazz.flags & Frozen) == Flags.Empty)
- decls enter sym
- if (definedFingerPrintCache != null)
- includeName(definedFingerPrintCache, sym.name)
- if (memberCacheVar != null)
- memberCache invalidate sym.name
- }
+ var nextInRun: SingleDenotation = this
- /** Delete symbol from current scope.
- * Note: We require that this does not happen after the first time
- * someone does a findMember on a subclass.
+ /** The version of this SingleDenotation that was valid in the first phase
+ * of this run.
*/
- def delete(sym: Symbol)(implicit ctx: Context) = {
- require((clazz.flags & Frozen) == Flags.Empty)
- decls unlink sym
- if (definedFingerPrintCache != null)
- computeDefinedFingerPrint
- if (memberCacheVar != null)
- memberCache invalidate sym.name
+ def initial: SingleDenotation = {
+ var current = nextInRun
+ while (current.validFor.code > this._validFor.code) current = current.nextInRun
+ current
}
- def definedFingerPrint(implicit ctx: Context): FingerPrint = {
- val fp = definedFingerPrintCache
- if (fp != null) fp else computeDefinedFingerPrint
- }
-
- final def memberRefsNamed(name: Name)(implicit ctx: Context): RefSet = {
- var refs: RefSet = memberCache lookup name
- if (refs == null) {
- if (containsName(definedFingerPrint, name)) {
- val ownRefs = decls.refsNamed(name)
- refs = ownRefs
- var ps = parents
- while (ps.nonEmpty) {
- val parentSym = ps.head.typeSymbol
- parentSym.deref match {
- case parentd: ClassDenotation =>
- refs = refs union
- parentd.memberRefsNamed(name)
- .filterExcluded(Flags.Private)
- .asSeenFrom(thisType, parentSym)
- .filterDisjoint(ownRefs)
- case _ =>
- }
- }
+ def current(implicit ctx: Context): SingleDenotation = {
+ val currentPeriod = ctx.period
+ val valid = _validFor
+ var current = this
+ if (currentPeriod.code > valid.code) {
+ // search for containing period as long as nextInRun increases.
+ var next = nextInRun
+ while (next.validFor.code > valid.code &&
+ !(next.validFor contains currentPeriod)) {
+ current = next
+ next = next.nextInRun
+ }
+ if (next.validFor.code > valid.code) {
+ // in this case, containsPeriod(next._validFor, currentPeriod)
+ current = next
} else {
- refs = NoRef
+ // not found, current points to highest existing variant
+ var startPid = current.validFor.lastPhaseId + 1
+ val trans = ctx.root.transformersFor(current)
+ val endPid = trans.nextTransformer(startPid + 1).phaseId - 1
+ next = trans.nextTransformer(startPid) transform current
+ if (next eq current)
+ startPid = current.validFor.firstPhaseId
+ else {
+ current.nextInRun = next
+ current = next
+ }
+ current.validFor = Period(currentPeriod.runId, startPid, endPid)
}
- memberCache enter (name, refs)
+ } else {
+ // currentPeriod < valid; in this case a version must exist
+ do {
+ current = current.nextInRun
+ } while (!(current.validFor contains currentPeriod))
}
- refs
+ current
}
- private var baseTypeCache: java.util.HashMap[UniqueType, Type] = null
-
- final def baseTypeOf(tp: Type)(implicit ctx: Context): Type = {
-
- def computeBaseTypeOf(tp: Type): Type = tp match {
- case AppliedType(tycon, args) =>
- baseTypeOf(tycon).subst(tycon.typeParams, args)
- case tp: TypeProxy =>
- baseTypeOf(tp.underlying)
- case AndType(tp1, tp2) =>
- baseTypeOf(tp1) & baseTypeOf(tp2)
- case OrType(tp1, tp2) =>
- baseTypeOf(tp1) | baseTypeOf(tp2)
- case tp @ ClassInfo(pre, classd) =>
- def reduce(bt: Type, ps: List[Type]): Type = ps match {
- case p :: ps1 => reduce(bt & baseTypeOf(p), ps1)
- case _ => bt
- }
- if (classd.clazz == clazz) tp.typeTemplate
- else reduce(NoType, classd.parents).substThis(classd.clazz, tp.prefix)
- }
+ //final def asSymDenotation = asInstanceOf[SymDenotation]
+
+ // ------ DenotationSet ops ----------------------------------------------
+
+ def toDenot(implicit ctx: Context) = this
+ def containsSig(sig: Signature)(implicit ctx: Context) =
+ signature == sig
+ def filterDisjoint(denots: DenotationSet)(implicit ctx: Context): DenotationSet =
+ if (denots.containsSig(signature)) NoDenotation else this
+ def filterExcluded(flags: FlagSet)(implicit ctx: Context): DenotationSet =
+ if (symbol is flags) NoDenotation else this
+ def filterAccessibleFrom(pre: Type)(implicit ctx: Context): DenotationSet =
+ if (symbol.isAccessibleFrom(pre)) this else NoDenotation
+ def asSeenFrom(pre: Type, owner: Symbol)(implicit ctx: Context): DenotationSet =
+ derivedSingleDenotation(symbol, info.asSeenFrom(pre, owner))
+ }
- if (clazz.isStatic && clazz.typeParams.isEmpty) clazz.typeConstructor
- else tp match {
- case tp: UniqueType =>
- if (baseTypeCache == null)
- baseTypeCache = new java.util.HashMap[UniqueType, Type]
- var basetp = baseTypeCache get tp
- if (basetp == null) {
- baseTypeCache.put(tp, NoType)
- basetp = computeBaseTypeOf(tp)
- baseTypeCache.put(tp, basetp)
- } else if (basetp == NoType) {
- throw new CyclicReference(clazz)
- }
- basetp
- case _ =>
- computeBaseTypeOf(tp)
- }
- }
+ class UniqueRefDenotation(val symbol: Symbol,
+ val info: Type,
+ initValidFor: Period) extends SingleDenotation {
+ validFor = initValidFor
+ override protected def copy(s: Symbol, i: Type): SingleDenotation = new UniqueRefDenotation(s, i, validFor)
+ }
- private var memberNamesCache: Map[NameFilter, Set[Name]] = Map()
+ class JointRefDenotation(val symbol: Symbol,
+ val info: Type,
+ initValidFor: Period) extends SingleDenotation {
+ validFor = initValidFor
+ override protected def copy(s: Symbol, i: Type): SingleDenotation = new JointRefDenotation(s, i, validFor)
+ }
- def memberNames(keepOnly: NameFilter)(implicit ctx: Context): Set[Name] =
- memberNamesCache get keepOnly match {
- case Some(names) =>
- names
- case _ =>
- val inheritedNames = (parents flatMap (_.memberNames(thisType, keepOnly))).toSet
- val ownNames = decls.iterator map (_.name)
- val candidates = inheritedNames ++ ownNames
- val names = candidates filter (keepOnly(thisType, _))
- memberNamesCache += (keepOnly -> names)
- names
- }
+ class ErrorDenotation(implicit ctx: Context) extends SingleDenotation {
+ val symbol = NoSymbol
+ val info = NoType
+ validFor = Period.allInRun(ctx.runId)
+ }
+
+// --------------- DenotationSets -------------------------------------------------
+
+ /** A DenotationSet represents a set of single denotations
+ * It is used as an optimization to avoid forming MultiDenotations too eagerly.
+ */
+ trait DenotationSet {
+ def exists: Boolean
+ def toDenot(implicit ctx: Context): Denotation
+ def containsSig(sig: Signature)(implicit ctx: Context): Boolean
+ def filterDisjoint(denots: DenotationSet)(implicit ctx: Context): DenotationSet
+ def filterExcluded(flags: FlagSet)(implicit ctx: Context): DenotationSet
+ def filterAccessibleFrom(pre: Type)(implicit ctx: Context): DenotationSet
+ def asSeenFrom(pre: Type, owner: Symbol)(implicit ctx: Context): DenotationSet
+ def union(that: DenotationSet) =
+ if (!this.exists) that
+ else if (that.exists) this
+ else DenotUnion(this, that)
}
- object NoDenotation extends Denotation {
- override def owner: Symbol = throw new AssertionError("NoDenotation.owner")
- override def name: Name = BootNameTable.newTermName("<none>")
- override def flags = Flags.Empty
- override def tpe: Type = NoType
- override def info: Type = NoType
+ case class DenotUnion(denots1: DenotationSet, denots2: DenotationSet) extends DenotationSet {
+ assert(denots1.exists && denots2.exists)
+ private def derivedUnion(s1: DenotationSet, s2: DenotationSet) =
+ if (!s1.exists) s2
+ else if (!s2.exists) s1
+ else if ((s1 eq denots2) && (s2 eq denots2)) this
+ else new DenotUnion(s1, s2)
+ def exists = true
+ def toDenot(implicit ctx: Context) = denots1.toDenot & denots2.toDenot
+ def containsSig(sig: Signature)(implicit ctx: Context) =
+ (denots1 containsSig sig) || (denots2 containsSig sig)
+ //def filter(p: Symbol => Boolean)(implicit ctx: Context) =
+ // derivedUnion(denots1 filter p, denots2 filter p)
+ def filterDisjoint(denots: DenotationSet)(implicit ctx: Context): DenotationSet =
+ derivedUnion(denots1 filterDisjoint denots, denots2 filterDisjoint denots)
+ def filterExcluded(flags: FlagSet)(implicit ctx: Context): DenotationSet =
+ derivedUnion(denots1 filterExcluded flags, denots2 filterExcluded flags)
+ def filterAccessibleFrom(pre: Type)(implicit ctx: Context): DenotationSet =
+ derivedUnion(denots1 filterAccessibleFrom pre, denots2 filterAccessibleFrom pre)
+ def asSeenFrom(pre: Type, owner: Symbol)(implicit ctx: Context): DenotationSet =
+ derivedUnion(denots1.asSeenFrom(pre, owner), denots2.asSeenFrom(pre, owner))
}
-} \ No newline at end of file
+}
+