aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc/core/Denotations.scala
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2013-02-28 19:04:47 +0100
committerMartin Odersky <odersky@gmail.com>2013-02-28 19:04:47 +0100
commit9c77f0ec16c8e1f6555590a531783e193d3dc7ea (patch)
treeb3aa4a9e9505f90b3a21bf968bbcdd2fc43f9618 /src/dotty/tools/dotc/core/Denotations.scala
parentfe8ee1143f7aabc57212506b3bdd10d7abb63d67 (diff)
downloaddotty-9c77f0ec16c8e1f6555590a531783e193d3dc7ea.tar.gz
dotty-9c77f0ec16c8e1f6555590a531783e193d3dc7ea.tar.bz2
dotty-9c77f0ec16c8e1f6555590a531783e193d3dc7ea.zip
Polishing of Denotations and Transformers.
Diffstat (limited to 'src/dotty/tools/dotc/core/Denotations.scala')
-rw-r--r--src/dotty/tools/dotc/core/Denotations.scala170
1 files changed, 111 insertions, 59 deletions
diff --git a/src/dotty/tools/dotc/core/Denotations.scala b/src/dotty/tools/dotc/core/Denotations.scala
index 314e19533..3e6367f2a 100644
--- a/src/dotty/tools/dotc/core/Denotations.scala
+++ b/src/dotty/tools/dotc/core/Denotations.scala
@@ -29,11 +29,9 @@ import Decorators.SymbolIteratorDecorator
* | | | |
* | denot | denot | denot | denot
* v v v v
- * Denotation-+-----SingleDenotation-+------SymDenotation-+----ClassDenotation-+--CompleteClassDenotation
- * | | | +--LazyClassDenotation
- * +-----MultiDenotation | |
- * | +--CompleteSymDenotation
- * | +--LazySymDenotation
+ * Denotation-+-----SingleDenotation-+------SymDenotation-+----ClassDenotation
+ * | |
+ * +-----MultiDenotation |
* |
* +--UniqueRefDenotation
* +--JointRefDenotation
@@ -60,14 +58,7 @@ import Decorators.SymbolIteratorDecorator
* 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
+ * ClassDenotation A denotation representing a single class definition.
*/
object Denotations {
@@ -115,7 +106,7 @@ object Denotations {
*
* class A { def f: A }
* class B { def f: B }
- * val x: A | B = if (???) new A else new B
+ * val x: A | B = if (test) new A else new B
* val y = x.f
*
* Then the denotation of `y` is `SingleDenotation(NoSymbol, A | B)`.
@@ -149,12 +140,15 @@ object Denotations {
/** The variant of this denotation that's current in the given context. */
def current(implicit ctx: Context): Denotation
- /** The first non-empty symbol, exists also for overloaded denotations,
- * where an arbitrary variant's symbol is picked (with preference for existsing symbols) */
- def firstSym(implicit ctx: Context): Symbol
-
+ /** Does this denotation exist?
+ * A denotation does not exist if it has NoType as an info.
+ * This is the case for NoDenotation, and also for SymDenotations
+ * that come from package members (classes or modules) where no
+ * corresponding symbol was found in a classfile or source.
+ */
def exists: Boolean = true
+ /** If this denotation does not exist, fallback to alternative */
def orElse(that: => Denotation) = if (this.exists) this else that
/** The set of alternative single-denotations making up this denotation */
@@ -191,20 +185,21 @@ object Denotations {
def requiredSymbol(p: Symbol => Boolean, source: AbstractFile = null)(implicit ctx: Context): Symbol = {
val sym = disambiguate(p).symbol
if (sym.exists) sym else {
+ val firstSym = ((NoSymbol: Symbol) /: alternatives.map(_.symbol)) (_ orElse _)
val owner = if (firstSym.exists) firstSym.owner else NoSymbol
ctx.newStubSymbol(owner, firstSym.name, source)
}
}
/** Form a denotation by conjoining with denotation `that` */
- def &(that: Denotation)(implicit ctx: Context): Denotation =
+ 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)
+ if (r.exists) r else MultiDenotation(this, that)
case that @ MultiDenotation(denot1, denot2) =>
this & denot1 & denot2
}
@@ -215,13 +210,24 @@ object Denotations {
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)
+ if (d1.exists) denot1.derivedMultiDenotation(d1, denot2)
+ else {
+ val d2 = mergeDenot(denot12, denot2)
+ if (d2.exists) denot1.derivedMultiDenotation(denot11, d2)
+ else NoDenotation
+ }
case denot1: SingleDenotation =>
if (denot1 eq denot2) denot1
else if (denot1.signature == denot2.signature) {
+ /** symbols eligible for a joint denotation are:
+ * - type symbols, as long as they are not classes
+ * - term symbols, where concrete symbols take precedence over abstract ones.
+ */
def isEligible(sym1: Symbol, sym2: Symbol) =
if (sym1.isType) !sym1.isClass
- else !(sym1 is Deferred) || (sym2 is Deferred) || !sym2.exists
+ else sym1.exists && (
+ !(sym1 is Deferred) || !sym2.exists || (sym2 is Deferred))
+ /** Convert class info C to bounds C..C */
def normalize(info: Type) =
if (isType) info.bounds else info
val sym1 = denot1.symbol
@@ -241,7 +247,11 @@ object Denotations {
} else NoDenotation
}
- def |(that: Denotation)(pre: Type)(implicit ctx: Context): Denotation = {
+ /** Form a choice between this denotation and that one.
+ * @param pre The prefix type of the members of the denotation, used
+ * to determine an accessible symbol if it exists.
+ */
+ def | (that: Denotation)(pre: Type)(implicit ctx: Context): Denotation = {
def lubSym(sym1: Symbol, sym2: Symbol): Symbol = {
def qualifies(sym: Symbol) =
@@ -281,17 +291,18 @@ object Denotations {
def show(implicit ctx: Context): String = ctx.show(this)
}
- /** The class of overloaded denotations
- * @param variants The overloaded variants indexed by thheir signatures.
+ /** An overloaded denotation consisting of the alternatives of both given denotations.
*/
case class MultiDenotation(denot1: Denotation, denot2: Denotation) extends Denotation {
- final override def isType = false
- 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")
+ final def symbol = unsupported("symbol")
+ final def info = unsupported("info")
+ final def validFor = denot1.validFor & denot2.validFor
+ final def isType = false
def signature(implicit ctx: Context) = unsupported("signature")
- def firstSym(implicit ctx: Context): Symbol = denot1.firstSym orElse denot2.firstSym
+ def atSignature(sig: Signature)(implicit ctx: Context): SingleDenotation =
+ denot1.atSignature(sig) orElse denot2.atSignature(sig)
+ def current(implicit ctx: Context): Denotation =
+ derivedMultiDenotation(denot1.current, denot2.current)
def altsWith(p: Symbol => Boolean)(implicit ctx: Context): List[SingleDenotation] =
denot1.altsWith(p) ++ denot2.altsWith(p)
def suchThat(p: Symbol => Boolean)(implicit ctx: Context): SingleDenotation = {
@@ -304,17 +315,16 @@ object Denotations {
}
def hasAltWith(p: Symbol => Boolean)(implicit ctx: Context): Boolean =
denot1.hasAltWith(p) || denot2.hasAltWith(p)
- def atSignature(sig: Signature)(implicit ctx: Context): 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)
+ def derivedMultiDenotation(d1: Denotation, d2: Denotation) =
+ if ((d1 eq denot1) && (d2 eq denot2)) this else MultiDenotation(d1, d2)
}
+ /** A non-overloaded denotation */
abstract class SingleDenotation extends Denotation with PreDenotation {
override def isType = info.isInstanceOf[TypeType]
override def signature(implicit ctx: Context): Signature = {
- def sig(tp: Type): Signature = tp match {
+ if (isType) NotAMethod
+ else info match {
case tp: PolyType =>
tp.resultType match {
case mt: MethodType => mt.signature
@@ -323,14 +333,13 @@ object Denotations {
case mt: MethodType => mt.signature
case _ => NotAMethod
}
- if (isType) NotAMethod else sig(info)
}
- def firstSym(implicit ctx: Context): Symbol = symbol
- def derivedSingleDenotation(s: Symbol, i: Type): SingleDenotation =
- if ((s eq symbol) && (i eq info)) this else newLikeThis(s, i)
+ def derivedSingleDenotation(symbol: Symbol, info: Type): SingleDenotation =
+ if ((symbol eq this.symbol) && (info eq this.info)) this
+ else newLikeThis(symbol, info)
- protected def newLikeThis(s: Symbol, i: Type): SingleDenotation = this
+ protected def newLikeThis(symbol: Symbol, info: Type): SingleDenotation = this
def orElse(that: => SingleDenotation) = if (this.exists) this else that
@@ -362,11 +371,11 @@ object Denotations {
* @See current. Flock members are connected in a ring
* with their `nextInRun` fields.
*
- * There are the following invariants converning flock members
+ * There are the following invariants concerning flock members
*
- * 1) validity periods must be non-overlapping
- * 2) the union of all validity periods must be a contiguous
- * interval starting in FirstPhaseId.
+ * 1) validity periods are non-overlapping
+ * 2) the union of all validity periods is a contiguous
+ * interval.
*/
var nextInRun: SingleDenotation = this
@@ -379,9 +388,16 @@ object Denotations {
current
}
+ /** Produce a denotation in the same flock that is valid for given context
+ * If one doesn't already exist, create it.
+ * Pre: validFor.runId == ctx.period.runId.
+ * Usually called when !(validFor contains ctx.period)
+ * (even though this is not a precondition).
+ */
def current(implicit ctx: Context): SingleDenotation = {
val currentPeriod = ctx.period
val valid = _validFor
+ assert(valid.runId == currentPeriod.runId)
var current = this
if (currentPeriod.code > valid.code) {
// search for containing period as long as nextInRun increases.
@@ -392,26 +408,31 @@ object Denotations {
next = next.nextInRun
}
if (next.validFor.code > valid.code) {
- // in this case, containsPeriod(next._validFor, currentPeriod)
+ // in this case, next.validFor contains currentPeriod
current = next
} else {
// not found, current points to highest existing variant
var startPid = current.validFor.lastPhaseId + 1
- val trans = ctx.transformersFor(current)
- val endPid = trans.nextTransformer(startPid + 1).phaseId - 1
- next = trans.nextTransformer(startPid) transform current
+ val transformers = ctx.transformersFor(current)
+ val transformer = transformers.nextTransformer(startPid)
+ next = transformer transform current
if (next eq current)
startPid = current.validFor.firstPhaseId
else {
current.nextInRun = next
current = next
}
- current.validFor = Period(currentPeriod.runId, startPid, endPid)
+ current.validFor = Period(
+ currentPeriod.runId, startPid, transformer.lastPhaseId)
}
} else {
// currentPeriod < valid; in this case a version must exist
+ // but to be defensive we check for infinite loop anyway
+ var cnt = 0
do {
current = current.nextInRun
+ cnt += 1
+ assert(cnt <= MaxPossiblePhaseId)
} while (!(current.validFor contains currentPeriod))
}
current
@@ -457,18 +478,44 @@ object Denotations {
// --------------- PreDenotations -------------------------------------------------
- /** A PreDenotation represents a set of single denotations
+ /** A PreDenotation represents a group of single denotations
* It is used as an optimization to avoid forming MultiDenotations too eagerly.
*/
trait PreDenotation {
+
+ /** A denotation in the group exists */
def exists: Boolean
+
+ /** First denotation in the group */
def first: Denotation
+
+ /** Convert to full denotation by &-ing all elements */
def toDenot(implicit ctx: Context): Denotation
+
+ /** Group contains a denotation with given signature */
def containsSig(sig: Signature)(implicit ctx: Context): Boolean
+
+ /** Keep only those denotations in this group which have a signature
+ * that's not already defined by `denots`.
+ */
def filterDisjoint(denots: PreDenotation)(implicit ctx: Context): PreDenotation
+
+ /** Keep only those denotations in this group whose flags do not intersect
+ * with given `flags`.
+ */
def filterExcluded(flags: FlagSet)(implicit ctx: Context): PreDenotation
+
+ /** Keep only those denotations in this group which are accessible from
+ * type `pre`.
+ */
def filterAccessibleFrom(pre: Type)(implicit ctx: Context): PreDenotation
+
+ /** The denotations as seen from given prefix type `pre`, where `owner`
+ * is assumed to be the owner of all denotation symbols.
+ */
def asSeenFrom(pre: Type, owner: Symbol)(implicit ctx: Context): PreDenotation
+
+ /** The union of two groups. */
def union(that: PreDenotation) =
if (!this.exists) that
else if (that.exists) this
@@ -477,11 +524,6 @@ object Denotations {
case class DenotUnion(denots1: PreDenotation, denots2: PreDenotation) extends PreDenotation {
assert(denots1.exists && denots2.exists)
- private def derivedUnion(s1: PreDenotation, s2: PreDenotation) =
- 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 first = denots1.first
def toDenot(implicit ctx: Context) = denots1.toDenot & denots2.toDenot
@@ -497,10 +539,16 @@ object Denotations {
derivedUnion(denots1 filterAccessibleFrom pre, denots2 filterAccessibleFrom pre)
def asSeenFrom(pre: Type, owner: Symbol)(implicit ctx: Context): PreDenotation =
derivedUnion(denots1.asSeenFrom(pre, owner), denots2.asSeenFrom(pre, owner))
+ private def derivedUnion(denots1: PreDenotation, denots2: PreDenotation) =
+ if ((denots1 eq this.denots1) && (denots2 eq this.denots2)) this
+ else denots1 union denots2
}
- /** Creation method for denotations */
+ // --------------- Context Base Trait -------------------------------
+
trait DenotationsBase { this: ContextBase =>
+
+ /** The current denotation of the static reference given by path. */
def staticRef(path: Name)(implicit ctx: Context): Denotation = {
def recur(path: Name, len: Int): Denotation = {
val point = path.lastIndexOf('.', len - 1)
@@ -508,7 +556,7 @@ object Denotations {
if (point > 0) recur(path.toTermName, point).disambiguate(_.isParameterless)
else if (path.isTermName) defn.RootClass.denot
else defn.EmptyPackageClass.denot
- if (!owner.exists) owner
+ if (!owner.exists) NoDenotation
else {
val name = path slice (point + 1, len)
val result = owner.info.member(name)
@@ -523,6 +571,10 @@ object Denotations {
recur(path, path.length)
}
+ /** If we are looking for a non-existing term name in a package,
+ * assume it is a package for which we do not have a directory and
+ * enter it.
+ */
def missingHook(owner: Symbol, name: Name)(implicit ctx: Context): Symbol =
if (owner.isPackage && name.isTermName)
ctx.newCompletePackageSymbol(owner, name.asTermName).entered