aboutsummaryrefslogblamecommitdiff
path: root/src/dotty/tools/dotc/core/Denotations.scala
blob: aa3768a99986b322c34ecab4248b78ed777864a5 (plain) (tree)
















































































































































































































































                                                                                 
package dotty.tools.dotc
package core

import Periods._, Contexts._, Symbols._, RefSets._, Names._
import Types._, Flags._, Decorators._
import Scopes.Scope
import collection.immutable.BitSet
import collection.mutable
import util.LRU8Cache

trait Denotations { self: Context =>

  /** A set for hash consing superclass bitsets */
  private val uniqueBits = new util.HashSet[BitSet]("superbits", 1024)

}

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: Long = ???

    def setFlag(flag: Long): 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? */
    def isType: Boolean = false

    /** is this symbol a class? */
    def isClass: Boolean = false

    /** is this symbol a method? */
    def isMethod: Boolean = false

    /** is this symbol the result of an erroneous definition? */
    def isError: Boolean = false

    def asClass: ClassDenotation = ???

    def withType(tp: Type): Denotation = ???
  }

  object NameFilter {
    final val WordSizeLog = 6
    final val DefinedNamesWords = 16
    final val DefinedNamesSize = DefinedNamesWords << WordSizeLog
    final val DefinedNamesMask = DefinedNamesSize - 1

    type FingerPrint = Array[Long]

    def includeName(bits: FingerPrint, name: Name): Unit = {
      val hash = name.start & DefinedNamesMask
      bits(hash >> 6) |= (1 << hash)
    }

    def includeFingerPrint(bits1: FingerPrint, bits2: FingerPrint): Unit =
      for (i <- 0 until DefinedNamesWords) bits1(i) |= bits2(i)

    def containsName(bits: FingerPrint, name: Name): Boolean = {
      val hash = name.start & DefinedNamesMask
      (bits(hash >> 6) & (1 << hash)) != 0
    }

    def newNameFilter: FingerPrint = new Array[Long](DefinedNamesWords)
  }

  class ClassDenotation(parents: List[Type], decls: Scope) extends Denotation {

    import NameFilter._

    lazy val baseClasses: List[ClassSymbol] = ???

    private var memberCacheVar: LRU8Cache[Name, RefSet] = null

    private def memberCache: LRU8Cache[Name, RefSet] = {
      if (memberCacheVar == null) memberCacheVar = new LRU8Cache
      memberCacheVar
    }

    def thisType: Type = ???

    private var superClassBitsCache: BitSet = null

    private def computeSuperClassBits(implicit ctx: Context): BitSet = {
      val b = BitSet.newBuilder
      for (bc <- baseClasses) b += bc.superId
      val bits = ctx.root.uniqueBits.findEntryOrUpdate(b.result())
      superClassBitsCache = bits
      bits
    }

    def superClassBits(implicit ctx: Context): BitSet = {
      val bits = superClassBitsCache
      if (bits != null) bits else computeSuperClassBits
    }

    /** Is this class a subclass of `clazz`? */
    final def isSubClass(clazz: ClassSymbol)(implicit ctx: Context): Boolean = {
      superClassBits contains clazz.superId
    }

    private var definedFingerPrintCache: FingerPrint = null

    private def computeDefinedFingerPrint(implicit ctx: Context): FingerPrint = {
      var bits = newNameFilter
      var e = decls.lastEntry
      while (e != null) {
        includeName(bits, name)
        e = e.prev
      }
      var ps = parents
      while (ps.nonEmpty) {
        val parent = ps.head.typeSymbol.asClass.deref
        includeFingerPrint(bits, parent.definedFingerPrint)
        parent setFlag Frozen
        ps = ps.tail
      }
      definedFingerPrintCache = bits
      bits
    }

    /** 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.
     */
    def enter(sym: Symbol)(implicit ctx: Context) = {
      require((flags & Frozen) == 0)
      decls enter sym
      if (definedFingerPrintCache != null)
        includeName(definedFingerPrintCache, sym.name)
      if (memberCacheVar != null)
        memberCache invalidate sym.name
    }

    /** Delete symbol from current scope.
     *  Note: We require that this does not happen after the first time
     *  someone does a findMember on a subclass.
     */
    def delete(sym: Symbol)(implicit ctx: Context) = {
      require((flags & Frozen) == 0)
      decls unlink sym
      if (definedFingerPrintCache != null)
        computeDefinedFingerPrint
      if (memberCacheVar != null)
        memberCache invalidate sym.name
    }

    def definedFingerPrint(implicit ctx: Context): FingerPrint = {
      val fp = definedFingerPrintCache
      if (fp != null) fp else computeDefinedFingerPrint
    }

    final def declsNamed(name: Name)(implicit ctx: Context): RefSet = {
      var syms: RefSet = NoType
      var e = decls lookupEntry name
      while (e != null) {
        syms = syms union e.sym.refType
        e = decls lookupNextEntry e
      }
      syms
    }

    final def memberRefsNamed(name: Name)(implicit ctx: Context): RefSet = {
      var refs: RefSet = memberCache lookup name
      if (refs == null) {
        if (containsName(definedFingerPrint, name)) {
          val ownRefs = declsNamed(name)
          refs = ownRefs
          var ps = parents
          val ownType = thisType
          while (ps.nonEmpty) {
            val parentSym = ps.head.typeSymbol.asClass
            val parent = parentSym.deref
            refs = refs union
              parent.memberRefsNamed(name)
                .filterExcluded(Flags.Private)
                .seenFrom(thisType, parentSym)
                .filterDisjoint(ownRefs)
            ps = ps.tail
          }
        } else {
          refs = NoType
        }
        memberCache enter (name, refs)
      }
      refs
    }
  }

  object NoDenotation extends Denotation {
    override def owner: Symbol = throw new AssertionError("NoDenotation.owner")
    override def name: Name = BootNameTable.newTermName("<none>")
    override def flags: Long = 0
    override def tpe: Type = NoType
    override def info: Type = NoType
  }


}