diff options
author | Felix Mulder <felix.mulder@gmail.com> | 2016-11-02 11:08:28 +0100 |
---|---|---|
committer | Guillaume Martres <smarter@ubuntu.com> | 2016-11-22 01:35:07 +0100 |
commit | 8a61ff432543a29234193cd1f7c14abd3f3d31a0 (patch) | |
tree | a8147561d307af862c295cfc8100d271063bb0dd /compiler/src/dotty/tools/dotc/core/SymDenotations.scala | |
parent | 6a455fe6da5ff9c741d91279a2dc6fe2fb1b472f (diff) | |
download | dotty-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.scala | 2004 |
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 +} |