aboutsummaryrefslogtreecommitdiff
path: root/compiler/src/dotty/tools/dotc/core/SymDenotations.scala
diff options
context:
space:
mode:
authorFelix Mulder <felix.mulder@gmail.com>2016-11-02 11:08:28 +0100
committerGuillaume Martres <smarter@ubuntu.com>2016-11-22 01:35:07 +0100
commit8a61ff432543a29234193cd1f7c14abd3f3d31a0 (patch)
treea8147561d307af862c295cfc8100d271063bb0dd /compiler/src/dotty/tools/dotc/core/SymDenotations.scala
parent6a455fe6da5ff9c741d91279a2dc6fe2fb1b472f (diff)
downloaddotty-8a61ff432543a29234193cd1f7c14abd3f3d31a0.tar.gz
dotty-8a61ff432543a29234193cd1f7c14abd3f3d31a0.tar.bz2
dotty-8a61ff432543a29234193cd1f7c14abd3f3d31a0.zip
Move compiler and compiler tests to compiler dir
Diffstat (limited to 'compiler/src/dotty/tools/dotc/core/SymDenotations.scala')
-rw-r--r--compiler/src/dotty/tools/dotc/core/SymDenotations.scala2004
1 files changed, 2004 insertions, 0 deletions
diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala
new file mode 100644
index 000000000..8b7c28e19
--- /dev/null
+++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala
@@ -0,0 +1,2004 @@
+package dotty.tools
+package dotc
+package core
+
+import Periods._, Contexts._, Symbols._, Denotations._, Names._, NameOps._, Annotations._
+import Types._, Flags._, Decorators._, DenotTransformers._, StdNames._, Scopes._, Comments._
+import NameOps._
+import Scopes.Scope
+import collection.mutable
+import collection.immutable.BitSet
+import scala.reflect.io.AbstractFile
+import Decorators.SymbolIteratorDecorator
+import ast._
+import annotation.tailrec
+import CheckRealizable._
+import util.SimpleMap
+import util.Stats
+import config.Config
+import config.Printers.{completions, incremental, noPrinter}
+
+trait SymDenotations { this: Context =>
+ import SymDenotations._
+
+ /** Factory method for SymDenotion creation. All creations
+ * should be done via this method.
+ */
+ def SymDenotation(
+ symbol: Symbol,
+ owner: Symbol,
+ name: Name,
+ initFlags: FlagSet,
+ initInfo: Type,
+ initPrivateWithin: Symbol = NoSymbol)(implicit ctx: Context): SymDenotation = {
+ val result =
+ if (symbol.isClass)
+ if (initFlags is Package) new PackageClassDenotation(symbol, owner, name, initFlags, initInfo, initPrivateWithin, ctx.runId)
+ else new ClassDenotation(symbol, owner, name, initFlags, initInfo, initPrivateWithin, ctx.runId)
+ else new SymDenotation(symbol, owner, name, initFlags, initInfo, initPrivateWithin)
+ result.validFor = stablePeriod
+ result
+ }
+
+ def stillValid(denot: SymDenotation): Boolean =
+ if (denot.is(ValidForever) || denot.isRefinementClass || denot.isImport) true
+ else {
+ val initial = denot.initial
+ val firstPhaseId = initial.validFor.firstPhaseId.max(ctx.typerPhase.id)
+ if ((initial ne denot) || ctx.phaseId != firstPhaseId)
+ ctx.withPhase(firstPhaseId).stillValidInOwner(initial)
+ else
+ stillValidInOwner(denot)
+ }
+
+ private[SymDenotations] def stillValidInOwner(denot: SymDenotation): Boolean = try {
+ val owner = denot.owner.denot
+ stillValid(owner) && (
+ !owner.isClass
+ || owner.isRefinementClass
+ || owner.is(Scala2x)
+ || (owner.unforcedDecls.lookupAll(denot.name) contains denot.symbol)
+ || denot.isSelfSym)
+ } catch {
+ case ex: StaleSymbol => false
+ }
+
+ /** Explain why symbol is invalid; used for debugging only */
+ def traceInvalid(denot: Denotation): Boolean = {
+ def show(d: Denotation) = s"$d#${d.symbol.id}"
+ def explain(msg: String) = {
+ println(s"${show(denot)} is invalid at ${this.period} because $msg")
+ false
+ }
+ denot match {
+ case denot: SymDenotation =>
+ def explainSym(msg: String) = explain(s"$msg\n defined = ${denot.definedPeriodsString}")
+ if (denot.is(ValidForever) || denot.isRefinementClass) true
+ else {
+ implicit val ctx: Context = this
+ val initial = denot.initial
+ if ((initial ne denot) || ctx.phaseId != initial.validFor.firstPhaseId) {
+ ctx.withPhase(initial.validFor.firstPhaseId).traceInvalid(initial)
+ } else try {
+ val owner = denot.owner.denot
+ if (!traceInvalid(owner)) explainSym("owner is invalid")
+ else if (!owner.isClass || owner.isRefinementClass || denot.isSelfSym) true
+ else if (owner.unforcedDecls.lookupAll(denot.name) contains denot.symbol) true
+ else explainSym(s"decls of ${show(owner)} are ${owner.unforcedDecls.lookupAll(denot.name).toList}, do not contain ${denot.symbol}")
+ } catch {
+ case ex: StaleSymbol => explainSym(s"$ex was thrown")
+ }
+ }
+ case _ =>
+ explain("denotation is not a SymDenotation")
+ }
+ }
+}
+
+object SymDenotations {
+
+ /** A sym-denotation represents the contents of a definition
+ * during a period.
+ */
+ class SymDenotation private[SymDenotations] (
+ symbol: Symbol,
+ ownerIfExists: Symbol,
+ final val name: Name,
+ initFlags: FlagSet,
+ initInfo: Type,
+ initPrivateWithin: Symbol = NoSymbol) extends SingleDenotation(symbol) {
+
+ //assert(symbol.id != 4940, name)
+
+ override def hasUniqueSym: Boolean = exists
+
+ /** Debug only
+ override def validFor_=(p: Period) = {
+ super.validFor_=(p)
+ }
+ */
+ if (Config.checkNoSkolemsInInfo) assertNoSkolems(initInfo)
+
+ // ------ Getting and setting fields -----------------------------
+
+ private[this] var myFlags: FlagSet = adaptFlags(initFlags)
+ private[this] var myInfo: Type = initInfo
+ private[this] var myPrivateWithin: Symbol = initPrivateWithin
+ private[this] var myAnnotations: List[Annotation] = Nil
+
+ /** The owner of the symbol; overridden in NoDenotation */
+ def owner: Symbol = ownerIfExists
+
+ /** Same as owner, except returns NoSymbol for NoSymbol */
+ def maybeOwner: Symbol = if (exists) owner else NoSymbol
+
+ /** The flag set */
+ final def flags(implicit ctx: Context): FlagSet = { ensureCompleted(); myFlags }
+
+ /** The flag set without forcing symbol completion.
+ * Should be used only for printing.
+ */
+ private[dotc] final def flagsUNSAFE = myFlags
+
+ /** Adapt flag set to this denotation's term or type nature */
+ private def adaptFlags(flags: FlagSet) = if (isType) flags.toTypeFlags else flags.toTermFlags
+
+ /** Update the flag set */
+ final def flags_=(flags: FlagSet): Unit =
+ myFlags = adaptFlags(flags)
+
+ /** Set given flags(s) of this denotation */
+ final def setFlag(flags: FlagSet): Unit = { myFlags |= flags }
+
+ /** Unset given flags(s) of this denotation */
+ final def resetFlag(flags: FlagSet): Unit = { myFlags &~= flags }
+
+ /** Set applicable flags from `flags` which is a subset of {NoInits, PureInterface} */
+ final def setApplicableFlags(flags: FlagSet): Unit = {
+ val mask = if (myFlags.is(Trait)) NoInitsInterface else NoInits
+ setFlag(flags & mask)
+ }
+
+ /** Has this denotation one of the flags in `fs` set? */
+ final def is(fs: FlagSet)(implicit ctx: Context) = {
+ (if (fs <= FromStartFlags) myFlags else flags) is fs
+ }
+
+ /** Has this denotation one of the flags in `fs` set, whereas none of the flags
+ * in `butNot` are set?
+ */
+ final def is(fs: FlagSet, butNot: FlagSet)(implicit ctx: Context) =
+ (if (fs <= FromStartFlags && butNot <= FromStartFlags) myFlags else flags) is (fs, butNot)
+
+ /** Has this denotation all of the flags in `fs` set? */
+ final def is(fs: FlagConjunction)(implicit ctx: Context) =
+ (if (fs <= FromStartFlags) myFlags else flags) is fs
+
+ /** Has this denotation all of the flags in `fs` set, whereas none of the flags
+ * in `butNot` are set?
+ */
+ final def is(fs: FlagConjunction, butNot: FlagSet)(implicit ctx: Context) =
+ (if (fs <= FromStartFlags && butNot <= FromStartFlags) myFlags else flags) is (fs, butNot)
+
+ /** The type info.
+ * The info is an instance of TypeType iff this is a type denotation
+ * Uncompleted denotations set myInfo to a LazyType.
+ */
+ final def info(implicit ctx: Context): Type = myInfo match {
+ case myInfo: LazyType => completeFrom(myInfo); info
+ case _ => myInfo
+ }
+
+ /** The type info, or, if symbol is not yet completed, the completer */
+ final def infoOrCompleter = myInfo
+
+ /** Optionally, the info if it is completed */
+ final def unforcedInfo: Option[Type] = myInfo match {
+ case myInfo: LazyType => None
+ case _ => Some(myInfo)
+ }
+
+ private def completeFrom(completer: LazyType)(implicit ctx: Context): Unit = {
+ if (completions ne noPrinter) {
+ completions.println(i"${" " * indent}completing ${if (isType) "type" else "val"} $name")
+ indent += 1
+ }
+ if (myFlags is Touched) throw CyclicReference(this)
+ myFlags |= Touched
+
+ // completions.println(s"completing ${this.debugString}")
+ try completer.complete(this)(ctx.withPhase(validFor.firstPhaseId))
+ catch {
+ case ex: CyclicReference =>
+ completions.println(s"error while completing ${this.debugString}")
+ throw ex
+ }
+ finally
+ if (completions ne noPrinter) {
+ indent -= 1
+ completions.println(i"${" " * indent}completed $name in $owner")
+ }
+ // completions.println(s"completed ${this.debugString}")
+ }
+
+ protected[dotc] def info_=(tp: Type) = {
+ /* // DEBUG
+ def illegal: String = s"illegal type for $this: $tp"
+ if (this is Module) // make sure module invariants that allow moduleClass and sourceModule to work are kept.
+ tp match {
+ case tp: ClassInfo => assert(tp.selfInfo.isInstanceOf[TermRefBySym], illegal)
+ case tp: NamedType => assert(tp.isInstanceOf[TypeRefBySym], illegal)
+ case tp: ExprType => assert(tp.resultType.isInstanceOf[TypeRefBySym], illegal)
+ case _ =>
+ }
+ */
+ if (Config.checkNoSkolemsInInfo) assertNoSkolems(tp)
+ myInfo = tp
+ }
+
+ /** The name, except
+ * - if this is a module class, strip the module class suffix
+ * - if this is a companion object with a clash-avoiding name, strip the
+ * "avoid clash" suffix
+ */
+ def effectiveName(implicit ctx: Context) =
+ if (this is ModuleClass) name.stripModuleClassSuffix
+ else name.stripAvoidClashSuffix
+
+ /** The privateWithin boundary, NoSymbol if no boundary is given.
+ */
+ final def privateWithin(implicit ctx: Context): Symbol = { ensureCompleted(); myPrivateWithin }
+
+ /** Set privateWithin. */
+ protected[core] final def privateWithin_=(sym: Symbol): Unit =
+ myPrivateWithin = sym
+
+ /** The annotations of this denotation */
+ final def annotations(implicit ctx: Context): List[Annotation] = {
+ ensureCompleted(); myAnnotations
+ }
+
+ /** Update the annotations of this denotation */
+ private[core] final def annotations_=(annots: List[Annotation]): Unit =
+ myAnnotations = annots
+
+ /** Does this denotation have an annotation matching the given class symbol? */
+ final def hasAnnotation(cls: Symbol)(implicit ctx: Context) =
+ dropOtherAnnotations(annotations, cls).nonEmpty
+
+ /** Apply transform `f` to all annotations of this denotation */
+ final def transformAnnotations(f: Annotation => Annotation)(implicit ctx: Context): Unit =
+ annotations = annotations.mapConserve(f)
+
+ /** Keep only those annotations that satisfy `p` */
+ final def filterAnnotations(p: Annotation => Boolean)(implicit ctx: Context): Unit =
+ annotations = annotations.filterConserve(p)
+
+ /** Optionally, the annotation matching the given class symbol */
+ final def getAnnotation(cls: Symbol)(implicit ctx: Context): Option[Annotation] =
+ dropOtherAnnotations(annotations, cls) match {
+ case annot :: _ => Some(annot)
+ case nil => None
+ }
+
+ /** The same as getAnnotation, but without ensuring
+ * that the symbol carrying the annotation is completed
+ */
+ final def unforcedAnnotation(cls: Symbol)(implicit ctx: Context): Option[Annotation] =
+ dropOtherAnnotations(myAnnotations, cls) match {
+ case annot :: _ => Some(annot)
+ case nil => None
+ }
+
+ /** Add given annotation to the annotations of this denotation */
+ final def addAnnotation(annot: Annotation): Unit =
+ annotations = annot :: myAnnotations
+
+ /** Remove annotation with given class from this denotation */
+ final def removeAnnotation(cls: Symbol)(implicit ctx: Context): Unit =
+ annotations = myAnnotations.filterNot(_ matches cls)
+
+ /** Remove any annotations with same class as `annot`, and add `annot` */
+ final def updateAnnotation(annot: Annotation)(implicit ctx: Context): Unit = {
+ removeAnnotation(annot.symbol)
+ addAnnotation(annot)
+ }
+
+ /** Add all given annotations to this symbol */
+ final def addAnnotations(annots: TraversableOnce[Annotation])(implicit ctx: Context): Unit =
+ annots.foreach(addAnnotation)
+
+ @tailrec
+ private def dropOtherAnnotations(anns: List[Annotation], cls: Symbol)(implicit ctx: Context): List[Annotation] = anns match {
+ case ann :: rest => if (ann matches cls) anns else dropOtherAnnotations(rest, cls)
+ case Nil => Nil
+ }
+
+ /** The denotation is completed: info is not a lazy type and attributes have defined values */
+ final def isCompleted: Boolean = !myInfo.isInstanceOf[LazyType]
+
+ /** The denotation is in train of being completed */
+ final def isCompleting: Boolean = (myFlags is Touched) && !isCompleted
+
+ /** The completer of this denotation. @pre: Denotation is not yet completed */
+ final def completer: LazyType = myInfo.asInstanceOf[LazyType]
+
+ /** Make sure this denotation is completed */
+ final def ensureCompleted()(implicit ctx: Context): Unit = info
+
+ /** The symbols defined in this class or object.
+ * Careful! This does not force the type, so is compilation order dependent.
+ * This method should be used only in the following circumstances:
+ *
+ * 1. When accessing type parameters or type parameter accessors (both are entered before
+ * completion).
+ * 2. When obtaining the current scope in order to enter, rename or delete something there.
+ * 3. When playing it safe in order not to raise CylicReferences, e.g. for printing things
+ * or taking more efficient shortcuts (e.g. the stillValid test).
+ */
+ final def unforcedDecls(implicit ctx: Context): Scope = myInfo match {
+ case cinfo: LazyType =>
+ val knownDecls = cinfo.decls
+ if (knownDecls ne EmptyScope) knownDecls
+ else { completeFrom(cinfo); unforcedDecls } // complete-once
+ case _ => info.decls
+ }
+
+ /** If this is a package class, the symbols entered in it
+ * before it is completed. (this is needed to eagerly enter synthetic
+ * aliases such as AnyRef into a package class without forcing it.
+ * Right now, the only usage is for the AnyRef alias in Definitions.
+ */
+ final private[core] def currentPackageDecls(implicit ctx: Context): MutableScope = myInfo match {
+ case pinfo: SymbolLoaders # PackageLoader => pinfo.currentDecls
+ case _ => unforcedDecls.openForMutations
+ }
+
+ // ------ Names ----------------------------------------------
+
+ /** The expanded name of this denotation. */
+ final def expandedName(implicit ctx: Context) =
+ if (is(ExpandedName) || isConstructor) name
+ else {
+ def legalize(name: Name): Name = // JVM method names may not contain `<' or `>' characters
+ if (is(Method)) name.replace('<', '(').replace('>', ')') else name
+ legalize(name.expandedName(initial.owner))
+ }
+ // need to use initial owner to disambiguate, as multiple private symbols with the same name
+ // might have been moved from different origins into the same class
+
+ /** The name with which the denoting symbol was created */
+ final def originalName(implicit ctx: Context) = {
+ val d = initial
+ if (d is ExpandedName) d.name.unexpandedName else d.name // !!!DEBUG, was: effectiveName
+ }
+
+ /** The encoded full path name of this denotation, where outer names and inner names
+ * are separated by `separator` strings.
+ * Never translates expansions of operators back to operator symbol.
+ * Drops package objects. Represents terms in the owner chain by a simple `~`.
+ * (Note: scalac uses nothing to represent terms, which can cause name clashes
+ * between same-named definitions in different enclosing methods. Before this commit
+ * we used `$' but this can cause ambiguities with the class separator '$').
+ * A separator "" means "flat name"; the real separator in this case is "$" and
+ * enclosing packages do not form part of the name.
+ */
+ def fullNameSeparated(separator: String)(implicit ctx: Context): Name = {
+ var sep = separator
+ var stopAtPackage = false
+ if (sep.isEmpty) {
+ sep = "$"
+ stopAtPackage = true
+ }
+ if (symbol == NoSymbol ||
+ owner == NoSymbol ||
+ owner.isEffectiveRoot ||
+ stopAtPackage && owner.is(PackageClass)) name
+ else {
+ var encl = owner
+ while (!encl.isClass && !encl.isPackageObject) {
+ encl = encl.owner
+ sep += "~"
+ }
+ if (owner.is(ModuleClass, butNot = Package) && sep == "$") sep = "" // duplicate scalac's behavior: don't write a double '$$' for module class members.
+ val fn = encl.fullNameSeparated(separator) ++ sep ++ name
+ if (isType) fn.toTypeName else fn.toTermName
+ }
+ }
+
+ /** The encoded flat name of this denotation, where joined names are separated by `separator` characters. */
+ def flatName(implicit ctx: Context): Name = fullNameSeparated("")
+
+ /** `fullName` where `.' is the separator character */
+ def fullName(implicit ctx: Context): Name = fullNameSeparated(".")
+
+ // ----- Tests -------------------------------------------------
+
+ /** Is this denotation a type? */
+ override def isType: Boolean = name.isTypeName
+
+ /** Is this denotation a class? */
+ final def isClass: Boolean = isInstanceOf[ClassDenotation]
+
+ /** Is this denotation a non-trait class? */
+ final def isRealClass(implicit ctx: Context) = isClass && !is(Trait)
+
+ /** Cast to class denotation */
+ final def asClass: ClassDenotation = asInstanceOf[ClassDenotation]
+
+ /** is this symbol the result of an erroneous definition? */
+ def isError: Boolean = false
+
+ /** Make denotation not exist */
+ final def markAbsent(): Unit =
+ myInfo = NoType
+
+ /** Is symbol known to not exist? */
+ final def isAbsent(implicit ctx: Context): Boolean =
+ myInfo == NoType ||
+ (this is (ModuleVal, butNot = Package)) && moduleClass.isAbsent
+
+ /** Is this symbol the root class or its companion object? */
+ final def isRoot: Boolean =
+ (name.toTermName == nme.ROOT || name == nme.ROOTPKG) && (owner eq NoSymbol)
+
+ /** Is this symbol the empty package class or its companion object? */
+ final def isEmptyPackage(implicit ctx: Context): Boolean =
+ name.toTermName == nme.EMPTY_PACKAGE && owner.isRoot
+
+ /** Is this symbol the empty package class or its companion object? */
+ final def isEffectiveRoot(implicit ctx: Context) = isRoot || isEmptyPackage
+
+ /** Is this symbol an anonymous class? */
+ final def isAnonymousClass(implicit ctx: Context): Boolean =
+ isClass && (initial.name startsWith tpnme.ANON_CLASS)
+
+ final def isAnonymousFunction(implicit ctx: Context) =
+ this.symbol.is(Method) && (initial.name startsWith nme.ANON_FUN)
+
+ final def isAnonymousModuleVal(implicit ctx: Context) =
+ this.symbol.is(ModuleVal) && (initial.name startsWith nme.ANON_CLASS)
+
+ /** Is this a companion class method or companion object method?
+ * These methods are generated by Symbols#synthesizeCompanionMethod
+ * and used in SymDenotations#companionClass and
+ * SymDenotations#companionModule .
+ */
+ final def isCompanionMethod(implicit ctx: Context) =
+ name.toTermName == nme.COMPANION_CLASS_METHOD ||
+ name.toTermName == nme.COMPANION_MODULE_METHOD
+
+ /** Is this a syntetic method that represents conversions between representations of a value class
+ * These methods are generated in ExtensionMethods
+ * and used in ElimErasedValueType.
+ */
+ final def isValueClassConvertMethod(implicit ctx: Context) =
+ name.toTermName == nme.U2EVT ||
+ name.toTermName == nme.EVT2U
+
+ /** Is symbol a primitive value class? */
+ def isPrimitiveValueClass(implicit ctx: Context) =
+ maybeOwner == defn.ScalaPackageClass && defn.ScalaValueClasses().contains(symbol)
+
+ /** Is symbol a primitive numeric value class? */
+ def isNumericValueClass(implicit ctx: Context) =
+ maybeOwner == defn.ScalaPackageClass && defn.ScalaNumericValueClasses().contains(symbol)
+
+ /** Is symbol a phantom class for which no runtime representation exists? */
+ def isPhantomClass(implicit ctx: Context) = defn.PhantomClasses contains symbol
+
+ /** Is this symbol a class representing a refinement? These classes
+ * are used only temporarily in Typer and Unpickler as an intermediate
+ * step for creating Refinement types.
+ */
+ final def isRefinementClass(implicit ctx: Context): Boolean =
+ name.decode == tpnme.REFINE_CLASS
+
+ /** Is this symbol a package object or its module class? */
+ def isPackageObject(implicit ctx: Context): Boolean = {
+ val poName = if (isType) nme.PACKAGE_CLS else nme.PACKAGE
+ (name.toTermName == poName) && (owner is Package) && (this is Module)
+ }
+
+ /** Is this symbol an abstract type? */
+ final def isAbstractType(implicit ctx: Context) = isType && (this is Deferred)
+
+ /** Is this symbol an alias type? */
+ final def isAliasType(implicit ctx: Context) = isAbstractOrAliasType && !(this is Deferred)
+
+ /** Is this symbol an abstract or alias type? */
+ final def isAbstractOrAliasType = isType & !isClass
+
+ /** Is this the denotation of a self symbol of some class?
+ * This is the case if one of two conditions holds:
+ * 1. It is the symbol referred to in the selfInfo part of the ClassInfo
+ * which is the type of this symbol's owner.
+ * 2. This symbol is owned by a class, it's selfInfo field refers to a type
+ * (indicating the self definition does not introduce a name), and the
+ * symbol's name is "_".
+ * TODO: Find a more robust way to characterize self symbols, maybe by
+ * spending a Flag on them?
+ */
+ final def isSelfSym(implicit ctx: Context) = owner.infoOrCompleter match {
+ case ClassInfo(_, _, _, _, selfInfo) =>
+ selfInfo == symbol ||
+ selfInfo.isInstanceOf[Type] && name == nme.WILDCARD
+ case _ => false
+ }
+
+ /** Is this definition contained in `boundary`?
+ * Same as `ownersIterator contains boundary` but more efficient.
+ */
+ final def isContainedIn(boundary: Symbol)(implicit ctx: Context): Boolean = {
+ def recur(sym: Symbol): Boolean =
+ if (sym eq boundary) true
+ else if (sym eq NoSymbol) false
+ else if ((sym is PackageClass) && !(boundary is PackageClass)) false
+ else recur(sym.owner)
+ recur(symbol)
+ }
+
+ final def isProperlyContainedIn(boundary: Symbol)(implicit ctx: Context): Boolean =
+ symbol != boundary && isContainedIn(boundary)
+
+ /** Is this denotation static (i.e. with no outer instance)? */
+ final def isStatic(implicit ctx: Context) =
+ (this is JavaStatic) || this.exists && owner.isStaticOwner || this.isRoot
+
+ /** Is this a package class or module class that defines static symbols? */
+ final def isStaticOwner(implicit ctx: Context): Boolean =
+ (this is PackageClass) || (this is ModuleClass) && isStatic
+
+ /** Is this denotation defined in the same scope and compilation unit as that symbol? */
+ final def isCoDefinedWith(that: Symbol)(implicit ctx: Context) =
+ (this.effectiveOwner == that.effectiveOwner) &&
+ ( !(this.effectiveOwner is PackageClass)
+ || this.isAbsent || that.isAbsent
+ || { // check if they are defined in the same file(or a jar)
+ val thisFile = this.symbol.associatedFile
+ val thatFile = that.symbol.associatedFile
+ ( thisFile == null
+ || thatFile == null
+ || thisFile.path == thatFile.path // Cheap possibly wrong check, then expensive normalization
+ || thisFile.canonicalPath == thatFile.canonicalPath
+ )
+ }
+ )
+
+ /** Is this a denotation of a stable term (or an arbitrary type)? */
+ final def isStable(implicit ctx: Context) =
+ isType || is(Stable) || !(is(UnstableValue) || info.isInstanceOf[ExprType])
+
+ /** Is this a "real" method? A real method is a method which is:
+ * - not an accessor
+ * - not a label
+ * - not an anonymous function
+ * - not a companion method
+ */
+ final def isRealMethod(implicit ctx: Context) =
+ this.is(Method, butNot = AccessorOrLabel) &&
+ !isAnonymousFunction &&
+ !isCompanionMethod
+
+ /** Is this a getter? */
+ final def isGetter(implicit ctx: Context) =
+ (this is Accessor) && !originalName.isSetterName && !originalName.isScala2LocalSuffix
+
+ /** Is this a setter? */
+ final def isSetter(implicit ctx: Context) =
+ (this is Accessor) &&
+ originalName.isSetterName &&
+ (!isCompleted || info.firstParamTypes.nonEmpty) // to avoid being fooled by var x_= : Unit = ...
+
+ /** is this a symbol representing an import? */
+ final def isImport = name == nme.IMPORT
+
+ /** is this the constructor of a class? */
+ final def isClassConstructor = name == nme.CONSTRUCTOR
+
+ /** Is this the constructor of a trait? */
+ final def isImplClassConstructor = name == nme.TRAIT_CONSTRUCTOR
+
+ /** Is this the constructor of a trait or a class */
+ final def isConstructor = name.isConstructorName
+
+ /** Is this a local template dummmy? */
+ final def isLocalDummy: Boolean = name.isLocalDummyName
+
+ /** Does this symbol denote the primary constructor of its enclosing class? */
+ final def isPrimaryConstructor(implicit ctx: Context) =
+ isConstructor && owner.primaryConstructor == symbol
+
+ /** Does this symbol denote the static constructor of its enclosing class? */
+ final def isStaticConstructor(implicit ctx: Context) =
+ name.isStaticConstructorName
+
+ /** Is this a subclass of the given class `base`? */
+ def isSubClass(base: Symbol)(implicit ctx: Context) = false
+
+ /** Is this a subclass of `base`,
+ * and is the denoting symbol also different from `Null` or `Nothing`?
+ * @note erroneous classes are assumed to derive from all other classes
+ * and all classes derive from them.
+ */
+ def derivesFrom(base: Symbol)(implicit ctx: Context) = false
+
+ /** Is this symbol a class that extends `AnyVal`? */
+ final def isValueClass(implicit ctx: Context): Boolean = {
+ val di = initial
+ di.isClass &&
+ di.derivesFrom(defn.AnyValClass)(ctx.withPhase(di.validFor.firstPhaseId))
+ // We call derivesFrom at the initial phase both because AnyVal does not exist
+ // after Erasure and to avoid cyclic references caused by forcing denotations
+ }
+
+ /** Is this symbol a class references to which that are supertypes of null? */
+ final def isNullableClass(implicit ctx: Context): Boolean =
+ isClass && !isValueClass && !(this is ModuleClass) && symbol != defn.NothingClass
+
+ /** Is this definition accessible as a member of tree with type `pre`?
+ * @param pre The type of the tree from which the selection is made
+ * @param superAccess Access is via super
+ * Everything is accessible if `pre` is `NoPrefix`.
+ * A symbol with type `NoType` is not accessible for any other prefix.
+ */
+ final def isAccessibleFrom(pre: Type, superAccess: Boolean = false, whyNot: StringBuffer = null)(implicit ctx: Context): Boolean = {
+
+ /** Are we inside definition of `boundary`? */
+ def accessWithin(boundary: Symbol) =
+ ctx.owner.isContainedIn(boundary) &&
+ (!(this is JavaDefined) || // disregard package nesting for Java
+ ctx.owner.enclosingPackageClass == boundary.enclosingPackageClass)
+
+ /** Are we within definition of linked class of `boundary`? */
+ def accessWithinLinked(boundary: Symbol) = {
+ val linked = boundary.linkedClass
+ (linked ne NoSymbol) && accessWithin(linked)
+ }
+
+ /** Is `pre` the same as C.thisThis, where C is exactly the owner of this symbol,
+ * or, if this symbol is protected, a subclass of the owner?
+ */
+ def isCorrectThisType(pre: Type): Boolean = pre match {
+ case pre: ThisType =>
+ (pre.cls eq owner) || (this is Protected) && pre.cls.derivesFrom(owner)
+ case pre: TermRef =>
+ pre.symbol.moduleClass == owner
+ case _ =>
+ false
+ }
+
+ /** Is protected access to target symbol permitted? */
+ def isProtectedAccessOK = {
+ def fail(str: => String): Boolean = {
+ if (whyNot != null) whyNot append str
+ false
+ }
+ val cls = owner.enclosingSubClass
+ if (!cls.exists)
+ fail(
+ i"""
+ | Access to protected $this not permitted because enclosing ${ctx.owner.enclosingClass.showLocated}
+ | is not a subclass of ${owner.showLocated} where target is defined""")
+ else if (
+ !( isType // allow accesses to types from arbitrary subclasses fixes #4737
+ || pre.baseTypeRef(cls).exists // ??? why not use derivesFrom ???
+ || isConstructor
+ || (owner is ModuleClass) // don't perform this check for static members
+ ))
+ fail(
+ i"""
+ | Access to protected ${symbol.show} not permitted because prefix type ${pre.widen.show}
+ | does not conform to ${cls.showLocated} where the access takes place""")
+ else true
+ }
+
+ if (pre eq NoPrefix) true
+ else if (info eq NoType) false
+ else {
+ val boundary = accessBoundary(owner)
+
+ ( boundary.isTerm
+ || boundary.isRoot
+ || (accessWithin(boundary) || accessWithinLinked(boundary)) &&
+ ( !(this is Local)
+ || (owner is ImplClass) // allow private local accesses to impl class members
+ || isCorrectThisType(pre)
+ )
+ || (this is Protected) &&
+ ( superAccess
+ || pre.isInstanceOf[ThisType]
+ || ctx.phase.erasedTypes
+ || isProtectedAccessOK
+ )
+ )
+ }
+ }
+
+ /** Do members of this symbol need translation via asSeenFrom when
+ * accessed via prefix `pre`?
+ */
+ def membersNeedAsSeenFrom(pre: Type)(implicit ctx: Context) =
+ !( this.isTerm
+ || this.isStaticOwner
+ || ctx.erasedTypes
+ || (pre eq NoPrefix) || (pre eq thisType)
+ )
+
+ /** Is this symbol concrete, or that symbol deferred? */
+ def isAsConcrete(that: Symbol)(implicit ctx: Context): Boolean =
+ !(this is Deferred) || (that is Deferred)
+
+ /** Does this symbol have defined or inherited default parameters? */
+ def hasDefaultParams(implicit ctx: Context): Boolean =
+ if (this is HasDefaultParams) true
+ else if (this is NoDefaultParams) false
+ else {
+ val result = allOverriddenSymbols exists (_.hasDefaultParams)
+ setFlag(if (result) InheritedDefaultParams else NoDefaultParams)
+ result
+ }
+
+ /** Symbol is an owner that would be skipped by effectiveOwner. Skipped are
+ * - package objects
+ * - labels
+ * - non-lazy valdefs
+ */
+ def isWeakOwner(implicit ctx: Context): Boolean =
+ isPackageObject ||
+ isTerm && !is(MethodOrLazy, butNot = Label) && !isLocalDummy
+
+ // def isOverridable: Boolean = !!! need to enforce that classes cannot be redefined
+ def isSkolem: Boolean = name == nme.SKOLEM
+
+ def isInlineMethod(implicit ctx: Context): Boolean = is(InlineMethod, butNot = Accessor)
+
+ // ------ access to related symbols ---------------------------------
+
+ /* Modules and module classes are represented as follows:
+ *
+ * object X extends Y { def f() }
+ *
+ * <module> lazy val X: X$ = new X$
+ * <module> class X$ extends Y { this: X.type => def f() }
+ *
+ * During completion, references to moduleClass and sourceModules are stored in
+ * the completers.
+ */
+ /** The class implementing this module, NoSymbol if not applicable. */
+ final def moduleClass(implicit ctx: Context): Symbol = {
+ def notFound = { println(s"missing module class for $name: $myInfo"); NoSymbol }
+ if (this is ModuleVal)
+ myInfo match {
+ case info: TypeRef => info.symbol
+ case ExprType(info: TypeRef) => info.symbol // needed after uncurry, when module terms might be accessor defs
+ case info: LazyType => info.moduleClass
+ case t: MethodType =>
+ t.resultType match {
+ case info: TypeRef => info.symbol
+ case _ => notFound
+ }
+ case _ => notFound
+ }
+ else NoSymbol
+ }
+
+ /** The module implemented by this module class, NoSymbol if not applicable. */
+ final def sourceModule(implicit ctx: Context): Symbol = myInfo match {
+ case ClassInfo(_, _, _, _, selfType) if this is ModuleClass =>
+ selfType match {
+ case selfType: TermRef => selfType.symbol
+ case selfType: Symbol => selfType.info.asInstanceOf[TermRef].symbol
+ }
+ case info: LazyType =>
+ info.sourceModule
+ case _ =>
+ NoSymbol
+ }
+
+ /** The field accessed by this getter or setter, or if it does not exist, the getter */
+ def accessedFieldOrGetter(implicit ctx: Context): Symbol = {
+ val fieldName = if (isSetter) name.asTermName.getterName else name
+ val d = owner.info.decl(fieldName)
+ val field = d.suchThat(!_.is(Method)).symbol
+ def getter = d.suchThat(_.info.isParameterless).symbol
+ field orElse getter
+ }
+
+ /** The field accessed by a getter or setter, or
+ * if it does not exists, the getter of a setter, or
+ * if that does not exist the symbol itself.
+ */
+ def underlyingSymbol(implicit ctx: Context): Symbol =
+ if (is(Accessor)) accessedFieldOrGetter orElse symbol else symbol
+
+ /** The chain of owners of this denotation, starting with the denoting symbol itself */
+ final def ownersIterator(implicit ctx: Context) = new Iterator[Symbol] {
+ private[this] var current = symbol
+ def hasNext = current.exists
+ def next: Symbol = {
+ val result = current
+ current = current.owner
+ result
+ }
+ }
+
+ /** If this is a weak owner, its owner, otherwise the denoting symbol. */
+ final def skipWeakOwner(implicit ctx: Context): Symbol =
+ if (isWeakOwner) owner.skipWeakOwner else symbol
+
+ /** The owner, skipping package objects, labels and non-lazy valdefs. */
+ final def effectiveOwner(implicit ctx: Context) = owner.skipWeakOwner
+
+ /** The class containing this denotation.
+ * If this denotation is already a class, return itself
+ * Definitions flagged with InSuperCall are treated specially.
+ * Their enclosing class is not the lexically enclosing class,
+ * but in turn the enclosing class of the latter. This reflects
+ * the context created by `Context#superCallContext`, `Context#thisCallArgContext`
+ * for these definitions.
+ *
+ * Note, that as packages have ClassSymbols, top level classes will have an `enclosingClass`
+ * with Package flag set.
+ */
+ final def enclosingClass(implicit ctx: Context): Symbol = {
+ def enclClass(sym: Symbol, skip: Boolean): Symbol = {
+ def newSkip = sym.is(InSuperCall) || sym.is(JavaStaticTerm)
+ if (!sym.exists)
+ NoSymbol
+ else if (sym.isClass)
+ if (skip) enclClass(sym.owner, newSkip) else sym
+ else
+ enclClass(sym.owner, skip || newSkip)
+ }
+ enclClass(symbol, false)
+ }
+
+ /** A class that in source code would be lexically enclosing */
+ final def lexicallyEnclosingClass(implicit ctx: Context): Symbol =
+ if (!exists || isClass) symbol else owner.lexicallyEnclosingClass
+
+ /** A symbol is effectively final if it cannot be overridden in a subclass */
+ final def isEffectivelyFinal(implicit ctx: Context): Boolean =
+ is(PrivateOrFinalOrInline) || !owner.isClass || owner.is(ModuleOrFinal) || owner.isAnonymousClass
+
+ /** The class containing this denotation which has the given effective name. */
+ final def enclosingClassNamed(name: Name)(implicit ctx: Context): Symbol = {
+ val cls = enclosingClass
+ if (cls.effectiveName == name || !cls.exists) cls else cls.owner.enclosingClassNamed(name)
+ }
+
+ /** The closest enclosing method containing this definition.
+ * A local dummy owner is mapped to the primary constructor of the class.
+ */
+ final def enclosingMethod(implicit ctx: Context): Symbol =
+ if (this is (Method, butNot = Label)) symbol
+ else if (this.isClass) primaryConstructor
+ else if (this.exists) owner.enclosingMethod
+ else NoSymbol
+
+ /** The top-level class containing this denotation,
+ * except for a toplevel module, where its module class is returned.
+ */
+ final def topLevelClass(implicit ctx: Context): Symbol = {
+ def topLevel(d: SymDenotation): Symbol = {
+ if (d.isEffectiveRoot || (d is PackageClass) || (d.owner is PackageClass)) d.symbol
+ else topLevel(d.owner)
+ }
+ val sym = topLevel(this)
+ if (sym.isClass) sym else sym.moduleClass
+ }
+
+ /** The package class containing this denotation */
+ final def enclosingPackageClass(implicit ctx: Context): Symbol =
+ if (this is PackageClass) symbol else owner.enclosingPackageClass
+
+ /** The module object with the same (term-) name as this class or module class,
+ * and which is also defined in the same scope and compilation unit.
+ * NoSymbol if this module does not exist.
+ */
+ final def companionModule(implicit ctx: Context): Symbol = {
+ if (this.flagsUNSAFE is Flags.Module) this.sourceModule
+ else {
+ val companionMethod = info.decls.denotsNamed(nme.COMPANION_MODULE_METHOD, selectPrivate).first
+ if (companionMethod.exists)
+ companionMethod.info.resultType.classSymbol.sourceModule
+ else
+ NoSymbol
+ }
+ }
+
+
+ /** The class with the same (type-) name as this module or module class,
+ * and which is also defined in the same scope and compilation unit.
+ * NoSymbol if this class does not exist.
+ */
+ final def companionClass(implicit ctx: Context): Symbol = {
+ val companionMethod = info.decls.denotsNamed(nme.COMPANION_CLASS_METHOD, selectPrivate).first
+
+ if (companionMethod.exists)
+ companionMethod.info.resultType.classSymbol
+ else
+ NoSymbol
+ }
+
+ final def scalacLinkedClass(implicit ctx: Context): Symbol =
+ if (this is ModuleClass) companionNamed(effectiveName.toTypeName)
+ else if (this.isClass) companionNamed(effectiveName.moduleClassName).sourceModule.moduleClass
+ else NoSymbol
+
+
+ /** Find companion class symbol with given name, or NoSymbol if none exists.
+ * Three alternative strategies:
+ * 1. If owner is a class, look in its members, otherwise
+ * 2. If current compilation unit has a typed tree,
+ * determine the defining statement sequence and search its trees, otherwise
+ * 3. If context has an enclosing scope which defines this symbol,
+ * lookup its companion in the same scope.
+ */
+ private def companionNamed(name: TypeName)(implicit ctx: Context): Symbol =
+ if (owner.isClass)
+ owner.info.decl(name).suchThat(_.isCoDefinedWith(symbol)).symbol
+ else if (!owner.exists || ctx.compilationUnit == null)
+ NoSymbol
+ else if (!ctx.compilationUnit.tpdTree.isEmpty)
+ tpd.definingStats(symbol).iterator
+ .map(tpd.definedSym)
+ .find(_.name == name)
+ .getOrElse(NoSymbol)
+ else if (ctx.scope == null)
+ NoSymbol
+ else if (ctx.scope.lookup(this.name) == symbol)
+ ctx.scope.lookup(name)
+ else
+ companionNamed(name)(ctx.outersIterator.dropWhile(_.scope eq ctx.scope).next)
+
+ /** If this is a class, the module class of its companion object.
+ * If this is a module class, its companion class.
+ * NoSymbol otherwise.
+ */
+ final def linkedClass(implicit ctx: Context): Symbol =
+ if (this is ModuleClass) companionClass
+ else if (this.isClass) companionModule.moduleClass
+ else NoSymbol
+
+ /** The class that encloses the owner of the current context
+ * and that is a subclass of this class. NoSymbol if no such class exists.
+ */
+ final def enclosingSubClass(implicit ctx: Context) =
+ ctx.owner.ownersIterator.findSymbol(_.isSubClass(symbol))
+
+ /** The non-private symbol whose name and type matches the type of this symbol
+ * in the given class.
+ * @param inClass The class containing the result symbol's definition
+ * @param site The base type from which member types are computed
+ *
+ * inClass <-- find denot.symbol class C { <-- symbol is here
+ *
+ * site: Subtype of both inClass and C
+ */
+ final def matchingDecl(inClass: Symbol, site: Type)(implicit ctx: Context): Symbol = {
+ var denot = inClass.info.nonPrivateDecl(name)
+ if (denot.isTerm) // types of the same name always match
+ denot = denot.matchingDenotation(site, site.memberInfo(symbol))
+ denot.symbol
+ }
+
+ /** The non-private member of `site` whose name and type matches the type of this symbol
+ */
+ final def matchingMember(site: Type)(implicit ctx: Context): Symbol = {
+ var denot = site.nonPrivateMember(name)
+ if (denot.isTerm) // types of the same name always match
+ denot = denot.matchingDenotation(site, site.memberInfo(symbol))
+ denot.symbol
+ }
+
+ /** If false, this symbol cannot possibly participate in an override,
+ * either as overrider or overridee.
+ */
+ final def canMatchInheritedSymbols(implicit ctx: Context): Boolean =
+ maybeOwner.isClass && memberCanMatchInheritedSymbols
+
+ /** If false, this class member cannot possibly participate in an override,
+ * either as overrider or overridee.
+ */
+ final def memberCanMatchInheritedSymbols(implicit ctx: Context): Boolean =
+ !isConstructor && !is(Private)
+
+ /** The symbol, in class `inClass`, that is overridden by this denotation. */
+ final def overriddenSymbol(inClass: ClassSymbol)(implicit ctx: Context): Symbol =
+ if (!canMatchInheritedSymbols && (owner ne inClass)) NoSymbol
+ else matchingDecl(inClass, owner.thisType)
+
+ /** All symbols overriden by this denotation. */
+ final def allOverriddenSymbols(implicit ctx: Context): Iterator[Symbol] =
+ if (!canMatchInheritedSymbols) Iterator.empty
+ else overriddenFromType(owner.info)
+
+ /** Returns all matching symbols defined in parents of the selftype. */
+ final def extendedOverriddenSymbols(implicit ctx: Context): Iterator[Symbol] =
+ if (!canMatchInheritedSymbols) Iterator.empty
+ else overriddenFromType(owner.asClass.classInfo.selfType)
+
+ private def overriddenFromType(tp: Type)(implicit ctx: Context): Iterator[Symbol] =
+ tp.baseClasses.tail.iterator map overriddenSymbol filter (_.exists)
+
+ /** The symbol overriding this symbol in given subclass `ofclazz`.
+ *
+ * @param ofclazz is a subclass of this symbol's owner
+ */
+ final def overridingSymbol(inClass: ClassSymbol)(implicit ctx: Context): Symbol =
+ if (canMatchInheritedSymbols) matchingDecl(inClass, inClass.thisType)
+ else NoSymbol
+
+ /** The symbol accessed by a super in the definition of this symbol when
+ * seen from class `base`. This symbol is always concrete.
+ * pre: `this.owner` is in the base class sequence of `base`.
+ */
+ final def superSymbolIn(base: Symbol)(implicit ctx: Context): Symbol = {
+ def loop(bcs: List[ClassSymbol]): Symbol = bcs match {
+ case bc :: bcs1 =>
+ val sym = matchingDecl(bcs.head, base.thisType)
+ .suchThat(alt => !(alt is Deferred)).symbol
+ if (sym.exists) sym else loop(bcs.tail)
+ case _ =>
+ NoSymbol
+ }
+ loop(base.info.baseClasses.dropWhile(owner != _).tail)
+ }
+
+ /** A member of class `base` is incomplete if
+ * (1) it is declared deferred or
+ * (2) it is abstract override and its super symbol in `base` is
+ * nonexistent or incomplete.
+ */
+ final def isIncompleteIn(base: Symbol)(implicit ctx: Context): Boolean =
+ (this is Deferred) ||
+ (this is AbsOverride) && {
+ val supersym = superSymbolIn(base)
+ supersym == NoSymbol || supersym.isIncompleteIn(base)
+ }
+
+ /** The class or term symbol up to which this symbol is accessible,
+ * or RootClass if it is public. As java protected statics are
+ * otherwise completely inaccessible in scala, they are treated
+ * as public.
+ * @param base The access boundary to assume if this symbol is protected
+ */
+ final def accessBoundary(base: Symbol)(implicit ctx: Context): Symbol = {
+ val fs = flags
+ if (fs is Private) owner
+ else if (fs is StaticProtected) defn.RootClass
+ else if (privateWithin.exists && !ctx.phase.erasedTypes) privateWithin
+ else if (fs is Protected) base
+ else defn.RootClass
+ }
+
+ /** The primary constructor of a class or trait, NoSymbol if not applicable. */
+ def primaryConstructor(implicit ctx: Context): Symbol = NoSymbol
+
+ // ----- type-related ------------------------------------------------
+
+ /** The type parameters of a class symbol, Nil for all other symbols */
+ def typeParams(implicit ctx: Context): List[TypeSymbol] = Nil
+
+ /** The named type parameters declared or inherited by this symbol */
+ def namedTypeParams(implicit ctx: Context): Set[TypeSymbol] = Set()
+
+ /** The type This(cls), where cls is this class, NoPrefix for all other symbols */
+ def thisType(implicit ctx: Context): Type = NoPrefix
+
+ override def typeRef(implicit ctx: Context): TypeRef =
+ TypeRef(owner.thisType, name.asTypeName, this)
+
+ override def termRef(implicit ctx: Context): TermRef =
+ TermRef(owner.thisType, name.asTermName, this)
+
+ override def valRef(implicit ctx: Context): TermRef =
+ TermRef.withSigAndDenot(owner.thisType, name.asTermName, Signature.NotAMethod, this)
+
+ override def termRefWithSig(implicit ctx: Context): TermRef =
+ TermRef.withSigAndDenot(owner.thisType, name.asTermName, signature, this)
+
+ def nonMemberTermRef(implicit ctx: Context): TermRef =
+ TermRef.withFixedSym(owner.thisType, name.asTermName, symbol.asTerm)
+
+ /** The variance of this type parameter or type member as an Int, with
+ * +1 = Covariant, -1 = Contravariant, 0 = Nonvariant, or not a type parameter
+ */
+ final def variance(implicit ctx: Context): Int =
+ if (this is Covariant) 1
+ else if (this is Contravariant) -1
+ else 0
+
+ /** The flags to be used for a type parameter owned by this symbol.
+ * Overridden by ClassDenotation.
+ */
+ def typeParamCreationFlags: FlagSet = TypeParam
+
+ override def toString = {
+ val kindString =
+ if (myFlags is ModuleClass) "module class"
+ else if (isClass) "class"
+ else if (isType) "type"
+ else if (myFlags is Module) "module"
+ else if (myFlags is Method) "method"
+ else "val"
+ s"$kindString $name"
+ }
+
+ // ----- Sanity checks and debugging */
+
+ def debugString = toString + "#" + symbol.id // !!! DEBUG
+
+ def hasSkolems(tp: Type): Boolean = tp match {
+ case tp: SkolemType => true
+ case tp: NamedType => hasSkolems(tp.prefix)
+ case tp: RefinedType => hasSkolems(tp.parent) || hasSkolems(tp.refinedInfo)
+ case tp: RecType => hasSkolems(tp.parent)
+ case tp: PolyType => tp.paramBounds.exists(hasSkolems) || hasSkolems(tp.resType)
+ case tp: MethodType => tp.paramTypes.exists(hasSkolems) || hasSkolems(tp.resType)
+ case tp: ExprType => hasSkolems(tp.resType)
+ case tp: HKApply => hasSkolems(tp.tycon) || tp.args.exists(hasSkolems)
+ case tp: AndOrType => hasSkolems(tp.tp1) || hasSkolems(tp.tp2)
+ case tp: TypeBounds => hasSkolems(tp.lo) || hasSkolems(tp.hi)
+ case tp: AnnotatedType => hasSkolems(tp.tpe)
+ case tp: TypeVar => hasSkolems(tp.inst)
+ case _ => false
+ }
+
+ def assertNoSkolems(tp: Type) =
+ if (!this.isSkolem)
+ assert(!hasSkolems(tp), s"assigning type $tp containing skolems to $this")
+
+ // ----- copies and transforms ----------------------------------------
+
+ protected def newLikeThis(s: Symbol, i: Type): SingleDenotation = new UniqueRefDenotation(s, i, validFor)
+
+ /** Copy this denotation, overriding selective fields */
+ final def copySymDenotation(
+ symbol: Symbol = this.symbol,
+ owner: Symbol = this.owner,
+ name: Name = this.name,
+ initFlags: FlagSet = UndefinedFlags,
+ info: Type = null,
+ privateWithin: Symbol = null,
+ annotations: List[Annotation] = null)(implicit ctx: Context) =
+ { // simulate default parameters, while also passing implicit context ctx to the default values
+ val initFlags1 = (if (initFlags != UndefinedFlags) initFlags else this.flags) &~ Frozen
+ val info1 = if (info != null) info else this.info
+ val privateWithin1 = if (privateWithin != null) privateWithin else this.privateWithin
+ val annotations1 = if (annotations != null) annotations else this.annotations
+ val d = ctx.SymDenotation(symbol, owner, name, initFlags1, info1, privateWithin1)
+ d.annotations = annotations1
+ d
+ }
+
+ override def initial: SymDenotation = super.initial.asSymDenotation
+
+ /** Install this denotation as the result of the given denotation transformer. */
+ override def installAfter(phase: DenotTransformer)(implicit ctx: Context): Unit =
+ super.installAfter(phase)
+
+ /** Apply a transformation `f` to all denotations in this group that start at or after
+ * given phase. Denotations are replaced while keeping the same validity periods.
+ */
+ override def transformAfter(phase: DenotTransformer, f: SymDenotation => SymDenotation)(implicit ctx: Context): Unit =
+ super.transformAfter(phase, f)
+
+ /** If denotation is private, remove the Private flag and expand the name if necessary */
+ def ensureNotPrivate(implicit ctx: Context) =
+ if (is(Private))
+ copySymDenotation(
+ name = expandedName,
+ initFlags = this.flags &~ Private | ExpandedName)
+ else this
+ }
+
+ /** The contents of a class definition during a period
+ */
+ class ClassDenotation private[SymDenotations] (
+ symbol: Symbol,
+ ownerIfExists: Symbol,
+ name: Name,
+ initFlags: FlagSet,
+ initInfo: Type,
+ initPrivateWithin: Symbol,
+ initRunId: RunId)
+ extends SymDenotation(symbol, ownerIfExists, name, initFlags, initInfo, initPrivateWithin) {
+
+ import util.LRUCache
+
+ // ----- denotation fields and accessors ------------------------------
+
+ if (initFlags is (Module, butNot = Package)) assert(name.isModuleClassName, s"module naming inconsistency: $name")
+
+ /** The symbol asserted to have type ClassSymbol */
+ def classSymbol: ClassSymbol = symbol.asInstanceOf[ClassSymbol]
+
+ /** The info asserted to have type ClassInfo */
+ def classInfo(implicit ctx: Context): ClassInfo = info.asInstanceOf[ClassInfo]
+
+ /** TODO: Document why caches are supposedly safe to use */
+ private[this] var myTypeParams: List[TypeSymbol] = _
+
+ private[this] var myNamedTypeParams: Set[TypeSymbol] = _
+
+ /** The type parameters in this class, in the order they appear in the current
+ * scope `decls`. This might be temporarily the incorrect order when
+ * reading Scala2 pickled info. The problem is fixed by `updateTypeParams`
+ * which is called once an unpickled symbol has been completed.
+ */
+ private def typeParamsFromDecls(implicit ctx: Context) =
+ unforcedDecls.filter(sym =>
+ (sym is TypeParam) && sym.owner == symbol).asInstanceOf[List[TypeSymbol]]
+
+ /** The type parameters of this class */
+ override final def typeParams(implicit ctx: Context): List[TypeSymbol] = {
+ if (myTypeParams == null)
+ myTypeParams =
+ if (ctx.erasedTypes || is(Module)) Nil // fast return for modules to avoid scanning package decls
+ else {
+ val di = initial
+ if (this ne di) di.typeParams
+ else infoOrCompleter match {
+ case info: TypeParamsCompleter => info.completerTypeParams(symbol)
+ case _ => typeParamsFromDecls
+ }
+ }
+ myTypeParams
+ }
+
+ /** The named type parameters declared or inherited by this class */
+ override final def namedTypeParams(implicit ctx: Context): Set[TypeSymbol] = {
+ def computeNamedTypeParams: Set[TypeSymbol] =
+ if (ctx.erasedTypes || is(Module)) Set() // fast return for modules to avoid scanning package decls
+ else memberNames(abstractTypeNameFilter).map(name =>
+ info.member(name).symbol.asType).filter(_.is(TypeParam, butNot = ExpandedName)).toSet
+ if (myNamedTypeParams == null) myNamedTypeParams = computeNamedTypeParams
+ myNamedTypeParams
+ }
+
+ override protected[dotc] final def info_=(tp: Type) = {
+ super.info_=(tp)
+ myTypeParams = null // changing the info might change decls, and with it typeParams
+ }
+
+ /** The denotations of all parents in this class. */
+ def classParents(implicit ctx: Context): List[TypeRef] = info match {
+ case classInfo: ClassInfo => classInfo.classParents
+ case _ => Nil
+ }
+
+ /** The symbol of the superclass, NoSymbol if no superclass exists */
+ def superClass(implicit ctx: Context): Symbol = classParents match {
+ case parent :: _ =>
+ val cls = parent.classSymbol
+ if (cls is Trait) NoSymbol else cls
+ case _ =>
+ NoSymbol
+ }
+
+ /** The denotation is fully completed: all attributes are fully defined.
+ * ClassDenotations compiled from source are first completed, then fully completed.
+ * Packages are never fully completed since members can be added at any time.
+ * @see Namer#ClassCompleter
+ */
+ private def isFullyCompleted(implicit ctx: Context): Boolean = {
+ def isFullyCompletedRef(tp: TypeRef) = tp.denot match {
+ case d: ClassDenotation => d.isFullyCompleted
+ case _ => false
+ }
+ def testFullyCompleted =
+ if (classParents.isEmpty) !is(Package) && symbol.eq(defn.AnyClass)
+ else classParents.forall(isFullyCompletedRef)
+ flagsUNSAFE.is(FullyCompleted) ||
+ isCompleted && testFullyCompleted && { setFlag(FullyCompleted); true }
+ }
+
+ // ------ syncing inheritance-related info -----------------------------
+
+ private var firstRunId: RunId = initRunId
+
+ /** invalidate caches influenced by parent classes if one of the parents
+ * is younger than the denotation itself.
+ */
+ override def syncWithParents(implicit ctx: Context): SingleDenotation = {
+ def isYounger(tref: TypeRef) = tref.symbol.denot match {
+ case denot: ClassDenotation =>
+ if (denot.validFor.runId < ctx.runId) denot.current // syncs with its parents in turn
+ val result = denot.firstRunId > this.firstRunId
+ if (result) incremental.println(s"$denot is younger than $this")
+ result
+ case _ => false
+ }
+ val parentIsYounger = (firstRunId < ctx.runId) && {
+ infoOrCompleter match {
+ case cinfo: ClassInfo => cinfo.classParents exists isYounger
+ case _ => false
+ }
+ }
+ if (parentIsYounger) {
+ incremental.println(s"parents of $this are invalid; symbol id = ${symbol.id}, copying ...\n")
+ invalidateInheritedInfo()
+ }
+ firstRunId = ctx.runId
+ this
+ }
+
+ /** Invalidate all caches and fields that depend on base classes and their contents */
+ override def invalidateInheritedInfo(): Unit = {
+ myBaseClasses = null
+ mySuperClassBits = null
+ myMemberFingerPrint = FingerPrint.unknown
+ myMemberCache = null
+ myMemberCachePeriod = Nowhere
+ memberNamesCache = SimpleMap.Empty
+ }
+
+ // ------ class-specific operations -----------------------------------
+
+ private[this] var myThisType: Type = null
+
+ /** The this-type depends on the kind of class:
+ * - for a package class `p`: ThisType(TypeRef(Noprefix, p))
+ * - for a module class `m`: A term ref to m's source module.
+ * - for all other classes `c` with owner `o`: ThisType(TypeRef(o.thisType, c))
+ */
+ override def thisType(implicit ctx: Context): Type = {
+ if (myThisType == null) myThisType = computeThisType
+ myThisType
+ }
+
+ private def computeThisType(implicit ctx: Context): Type =
+ ThisType.raw(
+ TypeRef(if (this is Package) NoPrefix else owner.thisType, symbol.asType))
+/* else {
+ val pre = owner.thisType
+ if (this is Module)
+ if (isMissing(pre)) TermRef(pre, sourceModule.asTerm)
+ else TermRef.withSig(pre, name.sourceModuleName, Signature.NotAMethod)
+ else ThisType.raw(TypeRef(pre, symbol.asType))
+ }
+*/
+ private[this] var myTypeRef: TypeRef = null
+
+ override def typeRef(implicit ctx: Context): TypeRef = {
+ if (myTypeRef == null) myTypeRef = super.typeRef
+ myTypeRef
+ }
+
+ private[this] var myBaseClasses: List[ClassSymbol] = null
+ private[this] var mySuperClassBits: BitSet = null
+
+ /** Invalidate baseTypeRefCache, baseClasses and superClassBits on new run */
+ private def checkBasesUpToDate()(implicit ctx: Context) =
+ if (baseTypeRefValid != ctx.runId) {
+ baseTypeRefCache = new java.util.HashMap[CachedType, Type]
+ myBaseClasses = null
+ mySuperClassBits = null
+ baseTypeRefValid = ctx.runId
+ }
+
+ private def computeBases(implicit ctx: Context): (List[ClassSymbol], BitSet) = {
+ if (myBaseClasses eq Nil) throw CyclicReference(this)
+ myBaseClasses = Nil
+ 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 bcs1added = addBaseClasses(bcs1, to)
+ val id = bc.superId
+ if (seen contains id) bcs1added
+ else {
+ seen += id
+ bc :: bcs1added
+ }
+ case nil =>
+ to
+ }
+ def addParentBaseClasses(ps: List[Type], to: List[ClassSymbol]): List[ClassSymbol] = ps match {
+ case p :: ps1 =>
+ addParentBaseClasses(ps1, addBaseClasses(p.baseClasses, to))
+ case nil =>
+ to
+ }
+ val bcs = classSymbol :: addParentBaseClasses(classParents, Nil)
+ val scbits = seen.toImmutable
+ if (isFullyCompleted) {
+ myBaseClasses = bcs
+ mySuperClassBits = scbits
+ }
+ else myBaseClasses = null
+ (bcs, scbits)
+ }
+
+ /** A bitset that contains the superId's of all base classes */
+ private def superClassBits(implicit ctx: Context): BitSet =
+ if (classParents.isEmpty) BitSet() // can happen when called too early in Namers
+ else {
+ checkBasesUpToDate()
+ if (mySuperClassBits != null) mySuperClassBits else computeBases._2
+ }
+
+ /** The base classes of this class in linearization order,
+ * with the class itself as first element.
+ */
+ def baseClasses(implicit ctx: Context): List[ClassSymbol] =
+ if (classParents.isEmpty) classSymbol :: Nil // can happen when called too early in Namers
+ else {
+ checkBasesUpToDate()
+ if (myBaseClasses != null) myBaseClasses else computeBases._1
+ }
+
+ final override def derivesFrom(base: Symbol)(implicit ctx: Context): Boolean =
+ !isAbsent &&
+ base.isClass &&
+ ( (symbol eq base)
+ || (superClassBits contains base.superId)
+ || (this is Erroneous)
+ || (base is Erroneous)
+ )
+
+ final override def isSubClass(base: Symbol)(implicit ctx: Context) =
+ derivesFrom(base) ||
+ base.isClass && (
+ (symbol eq defn.NothingClass) ||
+ (symbol eq defn.NullClass) && (base ne defn.NothingClass))
+
+ final override def typeParamCreationFlags = ClassTypeParamCreationFlags
+
+ private[this] var myMemberFingerPrint: FingerPrint = FingerPrint.unknown
+
+ private def computeMemberFingerPrint(implicit ctx: Context): FingerPrint = {
+ var fp = FingerPrint()
+ var e = info.decls.lastEntry
+ while (e != null) {
+ fp.include(e.name)
+ e = e.prev
+ }
+ var ps = classParents
+ while (ps.nonEmpty) {
+ val parent = ps.head.typeSymbol
+ parent.denot match {
+ case parentDenot: ClassDenotation =>
+ fp.include(parentDenot.memberFingerPrint)
+ if (parentDenot.isFullyCompleted) parentDenot.setFlag(Frozen)
+ case _ =>
+ }
+ ps = ps.tail
+ }
+ fp
+ }
+
+ /** A bloom filter for the names of all members in this class.
+ * Makes sense only for parent classes, and should definitely
+ * not be used for package classes because cache never
+ * gets invalidated.
+ */
+ def memberFingerPrint(implicit ctx: Context): FingerPrint =
+ if (myMemberFingerPrint != FingerPrint.unknown) myMemberFingerPrint
+ else {
+ val fp = computeMemberFingerPrint
+ if (isFullyCompleted) myMemberFingerPrint = fp
+ fp
+ }
+
+ private[this] var myMemberCache: LRUCache[Name, PreDenotation] = null
+ private[this] var myMemberCachePeriod: Period = Nowhere
+
+ private def memberCache(implicit ctx: Context): LRUCache[Name, PreDenotation] = {
+ if (myMemberCachePeriod != ctx.period) {
+ myMemberCache = new LRUCache
+ myMemberCachePeriod = ctx.period
+ }
+ myMemberCache
+ }
+
+ /** Enter a symbol in current scope, and future scopes of same denotation.
+ * Note: We require that this does not happen after the first time
+ * someone does a findMember on a subclass.
+ * @param scope The scope in which symbol should be entered.
+ * If this is EmptyScope, the scope is `decls`.
+ */
+ def enter(sym: Symbol, scope: Scope = EmptyScope)(implicit ctx: Context): Unit = {
+ val mscope = scope match {
+ case scope: MutableScope =>
+ // if enter gets a scope as an argument,
+ // than this is a scope that will eventually become decls of this symbol.
+ // And this should only happen if this is first time the scope of symbol
+ // is computed, ie symbol yet has no future.
+ assert(this.nextInRun.validFor.code <= this.validFor.code)
+ scope
+ case _ => unforcedDecls.openForMutations
+ }
+ if (this is PackageClass) {
+ val entry = mscope.lookupEntry(sym.name)
+ if (entry != null) {
+ if (entry.sym == sym) return
+ mscope.unlink(entry)
+ entry.sym.denot = sym.denot // to avoid stale symbols
+ }
+ }
+ enterNoReplace(sym, mscope)
+ val nxt = this.nextInRun
+ if (nxt.validFor.code > this.validFor.code) {
+ this.nextInRun.asSymDenotation.asClass.enter(sym)
+ }
+ }
+
+ /** Enter a symbol in given `scope` without potentially replacing the old copy. */
+ def enterNoReplace(sym: Symbol, scope: MutableScope)(implicit ctx: Context): Unit = {
+ def isUsecase = ctx.docCtx.isDefined && sym.name.show.takeRight(4) == "$doc"
+ require(
+ (sym.denot.flagsUNSAFE is Private) ||
+ !(this is Frozen) ||
+ (scope ne this.unforcedDecls) ||
+ sym.hasAnnotation(defn.ScalaStaticAnnot) ||
+ sym.name.isInlineAccessor ||
+ isUsecase)
+
+ scope.enter(sym)
+
+ if (myMemberFingerPrint != FingerPrint.unknown)
+ myMemberFingerPrint.include(sym.name)
+ if (myMemberCache != null)
+ myMemberCache invalidate sym.name
+ }
+
+ /** Replace symbol `prev` (if defined in current class) by symbol `replacement`.
+ * If `prev` is not defined in current class, do nothing.
+ * @pre `prev` and `replacement` have the same name.
+ */
+ def replace(prev: Symbol, replacement: Symbol)(implicit ctx: Context): Unit = {
+ require(!(this is Frozen))
+ unforcedDecls.openForMutations.replace(prev, replacement)
+ if (myMemberCache != null)
+ myMemberCache invalidate replacement.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(!(this is Frozen))
+ info.decls.openForMutations.unlink(sym)
+ myMemberFingerPrint = FingerPrint.unknown
+ if (myMemberCache != null) myMemberCache invalidate sym.name
+ }
+
+ /** Make sure the type parameters of this class appear in the order given
+ * by `typeParams` in the scope of the class. Reorder definitions in scope if necessary.
+ */
+ def ensureTypeParamsInCorrectOrder()(implicit ctx: Context): Unit = {
+ val tparams = typeParams
+ if (!ctx.erasedTypes && !typeParamsFromDecls.corresponds(tparams)(_.name == _.name)) {
+ val decls = info.decls
+ val decls1 = newScope
+ for (tparam <- typeParams) decls1.enter(decls.lookup(tparam.name))
+ for (sym <- decls) if (!tparams.contains(sym)) decls1.enter(sym)
+ info = classInfo.derivedClassInfo(decls = decls1)
+ myTypeParams = null
+ }
+ }
+
+ /** All members of this class that have the given name.
+ * The elements of the returned pre-denotation all
+ * have existing symbols.
+ */
+ final def membersNamed(name: Name)(implicit ctx: Context): PreDenotation = {
+ val privates = info.decls.denotsNamed(name, selectPrivate)
+ privates union nonPrivateMembersNamed(name).filterDisjoint(privates)
+ }
+
+ /** All non-private members of this class that have the given name.
+ * The elements of the returned pre-denotation all
+ * have existing symbols.
+ * @param inherited The method is called on a parent class from computeNPMembersNamed
+ */
+ final def nonPrivateMembersNamed(name: Name, inherited: Boolean = false)(implicit ctx: Context): PreDenotation = {
+ Stats.record("nonPrivateMembersNamed")
+ if (Config.cacheMembersNamed) {
+ var denots: PreDenotation = memberCache lookup name
+ if (denots == null) {
+ denots = computeNPMembersNamed(name, inherited)
+ if (isFullyCompleted) memberCache.enter(name, denots)
+ } else if (Config.checkCacheMembersNamed) {
+ val denots1 = computeNPMembersNamed(name, inherited)
+ assert(denots.exists == denots1.exists, s"cache inconsistency: cached: $denots, computed $denots1, name = $name, owner = $this")
+ }
+ denots
+ } else computeNPMembersNamed(name, inherited)
+ }
+
+ private[core] def computeNPMembersNamed(name: Name, inherited: Boolean)(implicit ctx: Context): PreDenotation = /*>|>*/ Stats.track("computeNPMembersNamed") /*<|<*/ {
+ if (!inherited ||
+ !Config.useFingerPrints ||
+ (memberFingerPrint contains name)) {
+ Stats.record("computeNPMembersNamed after fingerprint")
+ ensureCompleted()
+ val ownDenots = info.decls.denotsNamed(name, selectNonPrivate)
+ if (debugTrace) // DEBUG
+ println(s"$this.member($name), ownDenots = $ownDenots")
+ def collect(denots: PreDenotation, parents: List[TypeRef]): PreDenotation = parents match {
+ case p :: ps =>
+ val denots1 = collect(denots, ps)
+ p.symbol.denot match {
+ case parentd: ClassDenotation =>
+ denots1 union
+ parentd.nonPrivateMembersNamed(name, inherited = true)
+ .mapInherited(ownDenots, denots1, thisType)
+ case _ =>
+ denots1
+ }
+ case nil =>
+ denots
+ }
+ if (name.isConstructorName) ownDenots
+ else collect(ownDenots, classParents)
+ } else NoDenotation
+ }
+
+ override final def findMember(name: Name, pre: Type, excluded: FlagSet)(implicit ctx: Context): Denotation = {
+ val raw = if (excluded is Private) nonPrivateMembersNamed(name) else membersNamed(name)
+ raw.filterExcluded(excluded).asSeenFrom(pre).toDenot(pre)
+ }
+
+ private[this] var baseTypeRefCache: java.util.HashMap[CachedType, Type] = null
+ private[this] var baseTypeRefValid: RunId = NoRunId
+
+ /** Compute tp.baseTypeRef(this) */
+ final def baseTypeRefOf(tp: Type)(implicit ctx: Context): Type = {
+
+ def foldGlb(bt: Type, ps: List[Type]): Type = ps match {
+ case p :: ps1 => foldGlb(bt & baseTypeRefOf(p), ps1)
+ case _ => bt
+ }
+
+ def inCache(tp: Type) = baseTypeRefCache.containsKey(tp)
+
+ /** We cannot cache:
+ * - type variables which are uninstantiated or whose instances can
+ * change, depending on typerstate.
+ * - types where the underlying type is an ErasedValueType, because
+ * this underlying type will change after ElimErasedValueType,
+ * and this changes subtyping relations. As a shortcut, we do not
+ * cache ErasedValueType at all.
+ */
+ def isCachable(tp: Type): Boolean = tp match {
+ case _: TypeErasure.ErasedValueType => false
+ case tp: TypeRef if tp.symbol.isClass => true
+ case tp: TypeVar => tp.inst.exists && inCache(tp.inst)
+ case tp: TypeProxy => inCache(tp.underlying)
+ case tp: AndOrType => inCache(tp.tp1) && inCache(tp.tp2)
+ case _ => true
+ }
+
+ def computeBaseTypeRefOf(tp: Type): Type = {
+ Stats.record("computeBaseTypeOf")
+ if (symbol.isStatic && tp.derivesFrom(symbol))
+ symbol.typeRef
+ else tp match {
+ case tp: TypeRef =>
+ val subcls = tp.symbol
+ if (subcls eq symbol)
+ tp
+ else subcls.denot match {
+ case cdenot: ClassDenotation =>
+ if (cdenot.superClassBits contains symbol.superId) foldGlb(NoType, tp.parents)
+ else NoType
+ case _ =>
+ baseTypeRefOf(tp.superType)
+ }
+ case tp: TypeProxy =>
+ baseTypeRefOf(tp.superType)
+ case AndType(tp1, tp2) =>
+ baseTypeRefOf(tp1) & baseTypeRefOf(tp2)
+ case OrType(tp1, tp2) =>
+ baseTypeRefOf(tp1) | baseTypeRefOf(tp2)
+ case JavaArrayType(_) if symbol == defn.ObjectClass =>
+ this.typeRef
+ case _ =>
+ NoType
+ }
+ }
+
+ /*>|>*/ ctx.debugTraceIndented(s"$tp.baseTypeRef($this)") /*<|<*/ {
+ tp match {
+ case tp: CachedType =>
+ checkBasesUpToDate()
+ var basetp = baseTypeRefCache get tp
+ if (basetp == null) {
+ baseTypeRefCache.put(tp, NoPrefix)
+ basetp = computeBaseTypeRefOf(tp)
+ if (isCachable(tp)) baseTypeRefCache.put(tp, basetp)
+ else baseTypeRefCache.remove(tp)
+ } else if (basetp == NoPrefix) {
+ baseTypeRefCache.put(tp, null)
+ throw CyclicReference(this)
+ }
+ basetp
+ case _ =>
+ computeBaseTypeRefOf(tp)
+ }
+ }
+ }
+
+ private[this] var memberNamesCache: SimpleMap[NameFilter, Set[Name]] = SimpleMap.Empty
+
+ def memberNames(keepOnly: NameFilter)(implicit ctx: Context): Set[Name] = {
+ def computeMemberNames: Set[Name] = {
+ var names = Set[Name]()
+ def maybeAdd(name: Name) = if (keepOnly(thisType, name)) names += name
+ for (p <- classParents)
+ for (name <- p.memberNames(keepOnly, thisType)) maybeAdd(name)
+ val ownSyms =
+ if (keepOnly == implicitFilter)
+ if (this is Package) Iterator.empty
+ else info.decls.iterator filter (_ is Implicit)
+ else info.decls.iterator
+ for (sym <- ownSyms) maybeAdd(sym.name)
+ names
+ }
+ if ((this is PackageClass) || !Config.cacheMemberNames)
+ computeMemberNames // don't cache package member names; they might change
+ else {
+ val cached = memberNamesCache(keepOnly)
+ if (cached != null) cached
+ else {
+ val names = computeMemberNames
+ if (isFullyCompleted) {
+ setFlag(Frozen)
+ memberNamesCache = memberNamesCache.updated(keepOnly, names)
+ }
+ names
+ }
+ }
+ }
+
+ private[this] var fullNameCache: SimpleMap[String, Name] = SimpleMap.Empty
+ override final def fullNameSeparated(separator: String)(implicit ctx: Context): Name = {
+ val cached = fullNameCache(separator)
+ if (cached != null) cached
+ else {
+ val fn = super.fullNameSeparated(separator)
+ fullNameCache = fullNameCache.updated(separator, fn)
+ fn
+ }
+ }
+
+ // to avoid overloading ambiguities
+ override def fullName(implicit ctx: Context): Name = super.fullName
+
+ override def primaryConstructor(implicit ctx: Context): Symbol = {
+ def constrNamed(cname: TermName) = info.decls.denotsNamed(cname).last.symbol
+ // denotsNamed returns Symbols in reverse order of occurrence
+ if (this.is(ImplClass)) constrNamed(nme.TRAIT_CONSTRUCTOR) // ignore normal constructor
+ else
+ constrNamed(nme.CONSTRUCTOR).orElse(constrNamed(nme.TRAIT_CONSTRUCTOR))
+ }
+
+ /** The parameter accessors of this class. Term and type accessors,
+ * getters and setters are all returned int his list
+ */
+ def paramAccessors(implicit ctx: Context): List[Symbol] =
+ unforcedDecls.filter(_ is ParamAccessor).toList
+
+ /** If this class has the same `decls` scope reference in `phase` and
+ * `phase.next`, install a new denotation with a cloned scope in `phase.next`.
+ */
+ def ensureFreshScopeAfter(phase: DenotTransformer)(implicit ctx: Context): Unit =
+ if (ctx.phaseId != phase.next.id) ensureFreshScopeAfter(phase)(ctx.withPhase(phase.next))
+ else {
+ val prevCtx = ctx.withPhase(phase)
+ val ClassInfo(pre, _, ps, decls, selfInfo) = classInfo
+ if (classInfo(prevCtx).decls eq decls)
+ copySymDenotation(info = ClassInfo(pre, classSymbol, ps, decls.cloneScope, selfInfo))
+ .installAfter(phase)
+ }
+ }
+
+ /** The denotation of a package class.
+ * It overrides ClassDenotation to take account of package objects when looking for members
+ */
+ class PackageClassDenotation private[SymDenotations] (
+ symbol: Symbol,
+ ownerIfExists: Symbol,
+ name: Name,
+ initFlags: FlagSet,
+ initInfo: Type,
+ initPrivateWithin: Symbol,
+ initRunId: RunId)
+ extends ClassDenotation(symbol, ownerIfExists, name, initFlags, initInfo, initPrivateWithin, initRunId) {
+
+ private[this] var packageObjCache: SymDenotation = _
+ private[this] var packageObjRunId: RunId = NoRunId
+
+ /** The package object in this class, of one exists */
+ def packageObj(implicit ctx: Context): SymDenotation = {
+ if (packageObjRunId != ctx.runId) {
+ packageObjRunId = ctx.runId
+ packageObjCache = NoDenotation // break cycle in case we are looking for package object itself
+ packageObjCache = findMember(nme.PACKAGE, thisType, EmptyFlags).asSymDenotation
+ }
+ packageObjCache
+ }
+
+ /** Look first for members in package; if none are found look in package object */
+ override def computeNPMembersNamed(name: Name, inherited: Boolean)(implicit ctx: Context): PreDenotation = {
+ val denots = super.computeNPMembersNamed(name, inherited)
+ if (denots.exists) denots
+ else packageObj.moduleClass.denot match {
+ case pcls: ClassDenotation => pcls.computeNPMembersNamed(name, inherited)
+ case _ => denots
+ }
+ }
+
+ /** The union of the member names of the package and the package object */
+ override def memberNames(keepOnly: NameFilter)(implicit ctx: Context): Set[Name] = {
+ val ownNames = super.memberNames(keepOnly)
+ packageObj.moduleClass.denot match {
+ case pcls: ClassDenotation => ownNames union pcls.memberNames(keepOnly)
+ case _ => ownNames
+ }
+ }
+ }
+
+ class NoDenotation extends SymDenotation(
+ NoSymbol, NoSymbol, "<none>".toTermName, Permanent, NoType) {
+ override def exists = false
+ override def isTerm = false
+ override def isType = false
+ override def owner: Symbol = throw new AssertionError("NoDenotation.owner")
+ override def computeAsSeenFrom(pre: Type)(implicit ctx: Context): SingleDenotation = this
+ override def mapInfo(f: Type => Type)(implicit ctx: Context): SingleDenotation = this
+ validFor = Period.allInRun(NoRunId) // will be brought forward automatically
+ }
+
+ @sharable val NoDenotation = new NoDenotation
+
+ // ---- Completion --------------------------------------------------------
+
+ /** Instances of LazyType are carried by uncompleted symbols.
+ * Note: LazyTypes double up as (constant) functions from Symbol and
+ * from (TermSymbol, ClassSymbol) to LazyType. That way lazy types can be
+ * directly passed to symbol creation methods in Symbols that demand instances
+ * of these function types.
+ */
+ abstract class LazyType extends UncachedGroundType
+ with (Symbol => LazyType)
+ with ((TermSymbol, ClassSymbol) => LazyType) { self =>
+
+ /** Sets all missing fields of given denotation */
+ def complete(denot: SymDenotation)(implicit ctx: Context): Unit
+
+ def apply(sym: Symbol) = this
+ def apply(module: TermSymbol, modcls: ClassSymbol) = this
+
+ private var myDecls: Scope = EmptyScope
+ private var mySourceModuleFn: Context => Symbol = NoSymbolFn
+ private var myModuleClassFn: Context => Symbol = NoSymbolFn
+
+ /** A proxy to this lazy type that keeps the complete operation
+ * but provides fresh slots for scope/sourceModule/moduleClass
+ */
+ def proxy: LazyType = new LazyType {
+ override def complete(denot: SymDenotation)(implicit ctx: Context) = self.complete(denot)
+ }
+
+ def decls: Scope = myDecls
+ def sourceModule(implicit ctx: Context): Symbol = mySourceModuleFn(ctx)
+ def moduleClass(implicit ctx: Context): Symbol = myModuleClassFn(ctx)
+
+ def withDecls(decls: Scope): this.type = { myDecls = decls; this }
+ def withSourceModule(sourceModuleFn: Context => Symbol): this.type = { mySourceModuleFn = sourceModuleFn; this }
+ def withModuleClass(moduleClassFn: Context => Symbol): this.type = { myModuleClassFn = moduleClassFn; this }
+ }
+
+ /** A subclass of LazyTypes where type parameters can be completed independently of
+ * the info.
+ */
+ trait TypeParamsCompleter extends LazyType {
+ /** The type parameters computed by the completer before completion has finished */
+ def completerTypeParams(sym: Symbol)(implicit ctx: Context): List[TypeSymbol]
+ }
+
+ val NoSymbolFn = (ctx: Context) => NoSymbol
+
+ /** A missing completer */
+ @sharable class NoCompleter extends LazyType {
+ def complete(denot: SymDenotation)(implicit ctx: Context): Unit = unsupported("complete")
+ }
+
+ object NoCompleter extends NoCompleter
+
+ /** A lazy type for modules that points to the module class.
+ * Needed so that `moduleClass` works before completion.
+ * Completion of modules is always completion of the underlying
+ * module class, followed by copying the relevant fields to the module.
+ */
+ class ModuleCompleter(_moduleClass: ClassSymbol) extends LazyType {
+ override def moduleClass(implicit ctx: Context) = _moduleClass
+ def complete(denot: SymDenotation)(implicit ctx: Context): Unit = {
+ val from = moduleClass.denot.asClass
+ denot.setFlag(from.flags.toTermFlags & RetainedModuleValFlags)
+ denot.annotations = from.annotations filter (_.appliesToModule)
+ // !!! ^^^ needs to be revised later. The problem is that annotations might
+ // only apply to the module but not to the module class. The right solution
+ // is to have the module class completer set the annotations of both the
+ // class and the module.
+ denot.info = moduleClass.typeRef
+ denot.privateWithin = from.privateWithin
+ }
+ }
+
+ /** A completer for missing references */
+ class StubInfo() extends LazyType {
+
+ def initializeToDefaults(denot: SymDenotation)(implicit ctx: Context) = {
+ denot.info = denot match {
+ case denot: ClassDenotation =>
+ ClassInfo(denot.owner.thisType, denot.classSymbol, Nil, EmptyScope)
+ case _ =>
+ ErrorType
+ }
+ denot.privateWithin = NoSymbol
+ }
+
+ def complete(denot: SymDenotation)(implicit ctx: Context): Unit = {
+ val sym = denot.symbol
+ val file = sym.associatedFile
+ val (location, src) =
+ if (file != null) (s" in $file", file.toString)
+ else ("", "the signature")
+ val name = ctx.fresh.setSetting(ctx.settings.debugNames, true).nameString(denot.name)
+ ctx.error(
+ i"""bad symbolic reference. A signature$location
+ |refers to $name in ${denot.owner.showKind} ${denot.owner.showFullName} which is not available.
+ |It may be completely missing from the current classpath, or the version on
+ |the classpath might be incompatible with the version used when compiling $src.""")
+ if (ctx.debug) throw new Error()
+ initializeToDefaults(denot)
+ }
+ }
+
+ // ---- Fingerprints -----------------------------------------------------
+
+ /** A fingerprint is a bitset that acts as a bloom filter for sets
+ * of names.
+ */
+ class FingerPrint(val bits: Array[Long]) extends AnyVal {
+ import FingerPrint._
+
+ /** Include some bits of name's hashcode in set */
+ def include(name: Name): Unit = {
+ val hash = name.hashCode & Mask
+ bits(hash >> WordSizeLog) |= (1L << hash)
+ }
+
+ /** Include all bits of `that` fingerprint in set */
+ def include(that: FingerPrint): Unit =
+ for (i <- 0 until NumWords) bits(i) |= that.bits(i)
+
+ /** Does set contain hash bits of given name? */
+ def contains(name: Name): Boolean = {
+ val hash = name.hashCode & Mask
+ (bits(hash >> WordSizeLog) & (1L << hash)) != 0
+ }
+ }
+
+ object FingerPrint {
+ def apply() = new FingerPrint(new Array[Long](NumWords))
+ val unknown = new FingerPrint(null)
+ private final val WordSizeLog = 6
+ private final val NumWords = 32
+ private final val NumBits = NumWords << WordSizeLog
+ private final val Mask = NumBits - 1
+ }
+
+ private val AccessorOrLabel = Accessor | Label
+
+ @sharable private var indent = 0 // for completions printing
+}