Skip to content
27 changes: 11 additions & 16 deletions compiler/src/dotty/tools/dotc/core/Denotations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -982,7 +982,7 @@ object Denotations {
final def first: SingleDenotation = this
final def last: SingleDenotation = this

final def matches(other: SingleDenotation)(using Context): Boolean =
def matches(other: SingleDenotation)(using Context): Boolean =
val d = signature.matchDegree(other.signature)

d match
Expand Down Expand Up @@ -1013,16 +1013,21 @@ object Denotations {
end matches

def mapInherited(ownDenots: PreDenotation, prevDenots: PreDenotation, pre: Type)(using Context): SingleDenotation =
if (hasUniqueSym && prevDenots.containsSym(symbol)) NoDenotation
else if (isType) filterDisjoint(ownDenots).asSeenFrom(pre)
if hasUniqueSym && prevDenots.containsSym(symbol) then NoDenotation
else if isType then filterDisjoint(ownDenots).asSeenFrom(pre)
else asSeenFrom(pre).filterDisjoint(ownDenots)

final def filterWithPredicate(p: SingleDenotation => Boolean): SingleDenotation =
def filterWithPredicate(p: SingleDenotation => Boolean): SingleDenotation =
if (p(this)) this else NoDenotation
final def filterDisjoint(denots: PreDenotation)(using Context): SingleDenotation =
def filterDisjoint(denots: PreDenotation)(using Context): SingleDenotation =
if (denots.exists && denots.matches(this)) NoDenotation else this
def filterWithFlags(required: FlagSet, excluded: FlagSet)(using Context): SingleDenotation =
if (required.isEmpty && excluded.isEmpty || compatibleWith(required, excluded)) this else NoDenotation
def symd: SymDenotation = this match
case symd: SymDenotation => symd
case _ => symbol.denot
if !required.isEmpty && !symd.isAllOf(required)
|| !excluded.isEmpty && symd.isOneOf(excluded) then NoDenotation
else this
def aggregate[T](f: SingleDenotation => T, g: (T, T) => T): T = f(this)

type AsSeenFromResult = SingleDenotation
Expand Down Expand Up @@ -1056,16 +1061,6 @@ object Denotations {
if (!owner.membersNeedAsSeenFrom(pre) || symbol.is(NonMember)) this
else derived(symbol.info)
}

/** Does this denotation have all the `required` flags but none of the `excluded` flags?
*/
private def compatibleWith(required: FlagSet, excluded: FlagSet)(using Context): Boolean = {
val symd: SymDenotation = this match {
case symd: SymDenotation => symd
case _ => symbol.denot
}
symd.isAllOf(required) && !symd.isOneOf(excluded)
}
}

abstract class NonSymSingleDenotation(symbol: Symbol, initInfo: Type, override val prefix: Type) extends SingleDenotation(symbol, initInfo) {
Expand Down
9 changes: 2 additions & 7 deletions compiler/src/dotty/tools/dotc/core/Scopes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -148,12 +148,11 @@ object Scopes {
* Symbols occur in the result in reverse order relative to their occurrence
* in `this.toList`.
*/
final def denotsNamed(name: Name, select: SymDenotation => Boolean = selectAll)(using Context): PreDenotation = {
final def denotsNamed(name: Name)(using Context): PreDenotation = {
var syms: PreDenotation = NoDenotation
var e = lookupEntry(name)
while (e != null) {
val d = e.sym.denot
if (select(d)) syms = syms union d
syms = syms union e.sym.denot
e = lookupNextEntry(e)
}
syms
Expand Down Expand Up @@ -458,10 +457,6 @@ object Scopes {
*/
def scopeTransform(owner: Symbol)(op: => MutableScope): MutableScope = op

val selectAll: SymDenotation => Boolean = alwaysTrue
val selectPrivate: SymDenotation => Boolean = d => (d.flagsUNSAFE is Flags.Private)
val selectNonPrivate: SymDenotation => Boolean = d => !(d.flagsUNSAFE is Flags.Private)

/** The empty scope (immutable).
*/
object EmptyScope extends Scope {
Expand Down
125 changes: 64 additions & 61 deletions compiler/src/dotty/tools/dotc/core/SymDenotations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1564,14 +1564,14 @@ object SymDenotations {
initPrivateWithin: Symbol)
extends SymDenotation(symbol, maybeOwner, name, initFlags, initInfo, initPrivateWithin) {

import util.LRUCache
import util.HashTable

// ----- caches -------------------------------------------------------

private var myTypeParams: List[TypeSymbol] = null
private var fullNameCache: SimpleIdentityMap[QualifiedNameKind, Name] = SimpleIdentityMap.Empty

private var myMemberCache: LRUCache[Name, PreDenotation] = null
private var myMemberCache: HashTable[Name, PreDenotation] = null
private var myMemberCachePeriod: Period = Nowhere

/** A cache from types T to baseType(T, C) */
Expand All @@ -1582,9 +1582,9 @@ object SymDenotations {
private var baseDataCache: BaseData = BaseData.None
private var memberNamesCache: MemberNames = MemberNames.None

private def memberCache(using Context): LRUCache[Name, PreDenotation] = {
private def memberCache(using Context): HashTable[Name, PreDenotation] = {
if (myMemberCachePeriod != ctx.period) {
myMemberCache = new LRUCache
myMemberCache = HashTable()
myMemberCachePeriod = ctx.period
}
myMemberCache
Expand Down Expand Up @@ -1855,61 +1855,53 @@ object SymDenotations {
* The elements of the returned pre-denotation all
* have existing symbols.
*/
final def membersNamed(name: Name)(using 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)(using Context): PreDenotation = {
Stats.record("nonPrivateMembersNamed")
if (Config.cacheMembersNamed) {
var denots: PreDenotation = memberCache lookup name
if (denots == null) {
denots = computeNPMembersNamed(name)
final def membersNamed(name: Name)(using Context): PreDenotation =
Stats.record("membersNamed")
if Config.cacheMembersNamed then
var denots: PreDenotation = memberCache.lookup(name)
if denots == null then
denots = computeMembersNamed(name)
memberCache.enter(name, denots)
}
else if (Config.checkCacheMembersNamed) {
val denots1 = computeNPMembersNamed(name)
else if Config.checkCacheMembersNamed then
val denots1 = computeMembersNamed(name)
assert(denots.exists == denots1.exists, s"cache inconsistency: cached: $denots, computed $denots1, name = $name, owner = $this")
}
denots
}
else computeNPMembersNamed(name)
}
else computeMembersNamed(name)


private[core] def computeNPMembersNamed(name: Name)(using Context): PreDenotation = {
Stats.record("computeNPMembersNamed after fingerprint")
ensureCompleted()
val ownDenots = info.decls.denotsNamed(name, selectNonPrivate)
if (debugTrace) // DEBUG
/** All non-private members of this class that have the given name.
* The elements of the returned pre-denotation all have existing symbols.
*/
final def nonPrivateMembersNamed(name: Name)(using Context): PreDenotation =
val mbr = membersNamed(name)
val nonPrivate = mbr.filterWithFlags(EmptyFlags, Private)
if nonPrivate eq mbr then mbr
else addInherited(name, nonPrivate)

private[core] def computeMembersNamed(name: Name)(using Context): PreDenotation =
Stats.record("computeMembersNamed")
val ownDenots = info.decls.denotsNamed(name)
if debugTrace then
println(s"$this.member($name), ownDenots = $ownDenots")
def collect(denots: PreDenotation, parents: List[Type]): PreDenotation = parents match {
addInherited(name, ownDenots)

private def addInherited(name: Name, ownDenots: PreDenotation)(using Context): PreDenotation =
def collect(denots: PreDenotation, parents: List[Type]): PreDenotation = parents match
case p :: ps =>
val denots1 = collect(denots, ps)
p.classSymbol.denot match {
p.classSymbol.denot match
case parentd: ClassDenotation =>
denots1.union(
parentd.nonPrivateMembersNamed(name)
.mapInherited(ownDenots, denots1, thisType))
val inherited = parentd.nonPrivateMembersNamed(name)
denots1.union(inherited.mapInherited(ownDenots, denots1, thisType))
case _ =>
denots1
}
case nil =>
denots
}
if (name.isConstructorName) ownDenots
case nil => denots
if name.isConstructorName then ownDenots
else collect(ownDenots, classParents)
}

override final def findMember(name: Name, pre: Type, required: FlagSet, excluded: FlagSet)(using Context): Denotation = {
val raw = if (excluded.is(Private)) nonPrivateMembersNamed(name) else membersNamed(name)
override final def findMember(name: Name, pre: Type, required: FlagSet, excluded: FlagSet)(using Context): Denotation =
val raw = if excluded.is(Private) then nonPrivateMembersNamed(name) else membersNamed(name)
raw.filterWithFlags(required, excluded).asSeenFrom(pre).toDenot(pre)
}

/** Compute tp.baseType(this) */
final def baseTypeOf(tp: Type)(using Context): Type = {
Expand Down Expand Up @@ -2213,25 +2205,24 @@ object SymDenotations {
* object that hides a class or object in the scala package of the same name, because
* the behavior would then be unintuitive for such members.
*/
override def computeNPMembersNamed(name: Name)(using Context): PreDenotation = {
def recur(pobjs: List[ClassDenotation], acc: PreDenotation): PreDenotation = pobjs match {
override def computeMembersNamed(name: Name)(using Context): PreDenotation =

def recur(pobjs: List[ClassDenotation], acc: PreDenotation): PreDenotation = pobjs match
case pcls :: pobjs1 =>
if (pcls.isCompleting) recur(pobjs1, acc)
else {
val pmembers = pcls.computeNPMembersNamed(name).filterWithPredicate { d =>
else
val pobjMembers = pcls.nonPrivateMembersNamed(name).filterWithPredicate { d =>
// Drop members of `Any` and `Object`
val owner = d.symbol.maybeOwner
(owner ne defn.AnyClass) && (owner ne defn.ObjectClass)
}
recur(pobjs1, acc.union(pmembers))
}
recur(pobjs1, acc.union(pobjMembers))
case nil =>
val directMembers = super.computeNPMembersNamed(name)
val directMembers = super.computeMembersNamed(name)
if !acc.exists then directMembers
else acc.union(directMembers.filterWithPredicate(!_.symbol.isAbsent())) match
case d: DenotUnion => dropStale(d)
case d => d
}

def dropStale(multi: DenotUnion): PreDenotation =
val compiledNow = multi.filterWithPredicate(d =>
Expand Down Expand Up @@ -2273,13 +2264,12 @@ object SymDenotations {
multi.filterWithPredicate(_.symbol.associatedFile == chosen)
end dropStale

if (symbol `eq` defn.ScalaPackageClass) {
val denots = super.computeNPMembersNamed(name)
if (denots.exists || name == nme.CONSTRUCTOR) denots
if symbol eq defn.ScalaPackageClass then
val denots = super.computeMembersNamed(name)
if denots.exists || name == nme.CONSTRUCTOR then denots
else recur(packageObjs, NoDenotation)
}
else recur(packageObjs, NoDenotation)
}
end computeMembersNamed

/** The union of the member names of the package and the package object */
override def memberNames(keepOnly: NameFilter)(implicit onBehalf: MemberNames, ctx: Context): Set[Name] = {
Expand Down Expand Up @@ -2325,6 +2315,13 @@ object SymDenotations {
override def owner: Symbol = throw new AssertionError("NoDenotation.owner")
override def computeAsSeenFrom(pre: Type)(using Context): SingleDenotation = this
override def mapInfo(f: Type => Type)(using Context): SingleDenotation = this

override def matches(other: SingleDenotation)(using Context): Boolean = false
override def mapInherited(ownDenots: PreDenotation, prevDenots: PreDenotation, pre: Type)(using Context): SingleDenotation = this
override def filterWithPredicate(p: SingleDenotation => Boolean): SingleDenotation = this
override def filterDisjoint(denots: PreDenotation)(using Context): SingleDenotation = this
override def filterWithFlags(required: FlagSet, excluded: FlagSet)(using Context): SingleDenotation = this

NoSymbol.denot = this
validFor = Period.allInRun(NoRunId)
}
Expand Down Expand Up @@ -2448,6 +2445,8 @@ object SymDenotations {
def apply(module: TermSymbol, modcls: ClassSymbol): LazyType = this

private var myDecls: Scope = EmptyScope
private var mySourceModule: Symbol = null
private var myModuleClass: Symbol = null
private var mySourceModuleFn: Context ?=> Symbol = LazyType.NoSymbolFn
private var myModuleClassFn: Context ?=> Symbol = LazyType.NoSymbolFn

Expand All @@ -2457,8 +2456,12 @@ object SymDenotations {
else sym.info.typeParams

def decls: Scope = myDecls
def sourceModule(using Context): Symbol = mySourceModuleFn
def moduleClass(using Context): Symbol = myModuleClassFn
def sourceModule(using Context): Symbol =
if mySourceModule == null then mySourceModule = mySourceModuleFn
mySourceModule
def moduleClass(using Context): Symbol =
if myModuleClass == null then myModuleClass = myModuleClassFn
myModuleClass

def withDecls(decls: Scope): this.type = { myDecls = decls; this }
def withSourceModule(sourceModuleFn: Context ?=> Symbol): this.type = { mySourceModuleFn = sourceModuleFn; this }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ class Instrumentation extends MiniPhase { thisPhase =>
private val namesOfInterest = List(
"::", "+=", "toString", "newArray", "box", "toCharArray",
"map", "flatMap", "filter", "withFilter", "collect", "foldLeft", "foldRight", "take",
"reverse", "mapConserve", "mapconserve", "filterConserve", "zip")
"reverse", "mapConserve", "mapconserve", "filterConserve", "zip",
"denotsNamed", "lookup", "lookupEntry", "lookupAll", "toList")
private var namesToRecord: Set[Name] = _

private var consName: TermName = _
Expand Down
Loading