Skip to content

Commit 5a0cbb9

Browse files
authored
Merge pull request #9648 from dotty-staging/private-member-caching
Cache also private members
2 parents 5ee8777 + 9e4dbe8 commit 5a0cbb9

File tree

8 files changed

+77
-83
lines changed

8 files changed

+77
-83
lines changed

compiler/src/dotty/tools/dotc/core/Denotations.scala

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -982,7 +982,7 @@ object Denotations {
982982
final def first: SingleDenotation = this
983983
final def last: SingleDenotation = this
984984

985-
final def matches(other: SingleDenotation)(using Context): Boolean =
985+
def matches(other: SingleDenotation)(using Context): Boolean =
986986
val d = signature.matchDegree(other.signature)
987987

988988
d match
@@ -1013,16 +1013,21 @@ object Denotations {
10131013
end matches
10141014

10151015
def mapInherited(ownDenots: PreDenotation, prevDenots: PreDenotation, pre: Type)(using Context): SingleDenotation =
1016-
if (hasUniqueSym && prevDenots.containsSym(symbol)) NoDenotation
1017-
else if (isType) filterDisjoint(ownDenots).asSeenFrom(pre)
1016+
if hasUniqueSym && prevDenots.containsSym(symbol) then NoDenotation
1017+
else if isType then filterDisjoint(ownDenots).asSeenFrom(pre)
10181018
else asSeenFrom(pre).filterDisjoint(ownDenots)
10191019

1020-
final def filterWithPredicate(p: SingleDenotation => Boolean): SingleDenotation =
1020+
def filterWithPredicate(p: SingleDenotation => Boolean): SingleDenotation =
10211021
if (p(this)) this else NoDenotation
1022-
final def filterDisjoint(denots: PreDenotation)(using Context): SingleDenotation =
1022+
def filterDisjoint(denots: PreDenotation)(using Context): SingleDenotation =
10231023
if (denots.exists && denots.matches(this)) NoDenotation else this
10241024
def filterWithFlags(required: FlagSet, excluded: FlagSet)(using Context): SingleDenotation =
1025-
if (required.isEmpty && excluded.isEmpty || compatibleWith(required, excluded)) this else NoDenotation
1025+
def symd: SymDenotation = this match
1026+
case symd: SymDenotation => symd
1027+
case _ => symbol.denot
1028+
if !required.isEmpty && !symd.isAllOf(required)
1029+
|| !excluded.isEmpty && symd.isOneOf(excluded) then NoDenotation
1030+
else this
10261031
def aggregate[T](f: SingleDenotation => T, g: (T, T) => T): T = f(this)
10271032

10281033
type AsSeenFromResult = SingleDenotation
@@ -1056,16 +1061,6 @@ object Denotations {
10561061
if (!owner.membersNeedAsSeenFrom(pre) || symbol.is(NonMember)) this
10571062
else derived(symbol.info)
10581063
}
1059-
1060-
/** Does this denotation have all the `required` flags but none of the `excluded` flags?
1061-
*/
1062-
private def compatibleWith(required: FlagSet, excluded: FlagSet)(using Context): Boolean = {
1063-
val symd: SymDenotation = this match {
1064-
case symd: SymDenotation => symd
1065-
case _ => symbol.denot
1066-
}
1067-
symd.isAllOf(required) && !symd.isOneOf(excluded)
1068-
}
10691064
}
10701065

10711066
abstract class NonSymSingleDenotation(symbol: Symbol, initInfo: Type, override val prefix: Type) extends SingleDenotation(symbol, initInfo) {

compiler/src/dotty/tools/dotc/core/Scopes.scala

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -148,12 +148,11 @@ object Scopes {
148148
* Symbols occur in the result in reverse order relative to their occurrence
149149
* in `this.toList`.
150150
*/
151-
final def denotsNamed(name: Name, select: SymDenotation => Boolean = selectAll)(using Context): PreDenotation = {
151+
final def denotsNamed(name: Name)(using Context): PreDenotation = {
152152
var syms: PreDenotation = NoDenotation
153153
var e = lookupEntry(name)
154154
while (e != null) {
155-
val d = e.sym.denot
156-
if (select(d)) syms = syms union d
155+
syms = syms union e.sym.denot
157156
e = lookupNextEntry(e)
158157
}
159158
syms
@@ -458,10 +457,6 @@ object Scopes {
458457
*/
459458
def scopeTransform(owner: Symbol)(op: => MutableScope): MutableScope = op
460459

461-
val selectAll: SymDenotation => Boolean = alwaysTrue
462-
val selectPrivate: SymDenotation => Boolean = d => (d.flagsUNSAFE is Flags.Private)
463-
val selectNonPrivate: SymDenotation => Boolean = d => !(d.flagsUNSAFE is Flags.Private)
464-
465460
/** The empty scope (immutable).
466461
*/
467462
object EmptyScope extends Scope {

compiler/src/dotty/tools/dotc/core/SymDenotations.scala

Lines changed: 59 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1855,61 +1855,53 @@ object SymDenotations {
18551855
* The elements of the returned pre-denotation all
18561856
* have existing symbols.
18571857
*/
1858-
final def membersNamed(name: Name)(using Context): PreDenotation = {
1859-
val privates = info.decls.denotsNamed(name, selectPrivate)
1860-
privates union nonPrivateMembersNamed(name).filterDisjoint(privates)
1861-
}
1862-
1863-
/** All non-private members of this class that have the given name.
1864-
* The elements of the returned pre-denotation all
1865-
* have existing symbols.
1866-
* @param inherited The method is called on a parent class from computeNPMembersNamed
1867-
*/
1868-
final def nonPrivateMembersNamed(name: Name)(using Context): PreDenotation = {
1869-
Stats.record("nonPrivateMembersNamed")
1870-
if (Config.cacheMembersNamed) {
1858+
final def membersNamed(name: Name)(using Context): PreDenotation =
1859+
Stats.record("membersNamed")
1860+
if Config.cacheMembersNamed then
18711861
var denots: PreDenotation = memberCache.lookup(name)
1872-
if (denots == null) {
1873-
denots = computeNPMembersNamed(name)
1862+
if denots == null then
1863+
denots = computeMembersNamed(name)
18741864
memberCache.enter(name, denots)
1875-
}
1876-
else if (Config.checkCacheMembersNamed) {
1877-
val denots1 = computeNPMembersNamed(name)
1865+
else if Config.checkCacheMembersNamed then
1866+
val denots1 = computeMembersNamed(name)
18781867
assert(denots.exists == denots1.exists, s"cache inconsistency: cached: $denots, computed $denots1, name = $name, owner = $this")
1879-
}
18801868
denots
1881-
}
1882-
else computeNPMembersNamed(name)
1883-
}
1869+
else computeMembersNamed(name)
1870+
18841871

1885-
private[core] def computeNPMembersNamed(name: Name)(using Context): PreDenotation = {
1886-
Stats.record("computeNPMembersNamed after fingerprint")
1887-
ensureCompleted()
1888-
val ownDenots = info.decls.denotsNamed(name, selectNonPrivate)
1889-
if (debugTrace) // DEBUG
1872+
/** All non-private members of this class that have the given name.
1873+
* The elements of the returned pre-denotation all have existing symbols.
1874+
*/
1875+
final def nonPrivateMembersNamed(name: Name)(using Context): PreDenotation =
1876+
val mbr = membersNamed(name)
1877+
val nonPrivate = mbr.filterWithFlags(EmptyFlags, Private)
1878+
if nonPrivate eq mbr then mbr
1879+
else addInherited(name, nonPrivate)
1880+
1881+
private[core] def computeMembersNamed(name: Name)(using Context): PreDenotation =
1882+
Stats.record("computeMembersNamed")
1883+
val ownDenots = info.decls.denotsNamed(name)
1884+
if debugTrace then
18901885
println(s"$this.member($name), ownDenots = $ownDenots")
1891-
def collect(denots: PreDenotation, parents: List[Type]): PreDenotation = parents match {
1886+
addInherited(name, ownDenots)
1887+
1888+
private def addInherited(name: Name, ownDenots: PreDenotation)(using Context): PreDenotation =
1889+
def collect(denots: PreDenotation, parents: List[Type]): PreDenotation = parents match
18921890
case p :: ps =>
18931891
val denots1 = collect(denots, ps)
1894-
p.classSymbol.denot match {
1892+
p.classSymbol.denot match
18951893
case parentd: ClassDenotation =>
1896-
denots1.union(
1897-
parentd.nonPrivateMembersNamed(name)
1898-
.mapInherited(ownDenots, denots1, thisType))
1894+
val inherited = parentd.nonPrivateMembersNamed(name)
1895+
denots1.union(inherited.mapInherited(ownDenots, denots1, thisType))
18991896
case _ =>
19001897
denots1
1901-
}
1902-
case nil =>
1903-
denots
1904-
}
1905-
if (name.isConstructorName) ownDenots
1898+
case nil => denots
1899+
if name.isConstructorName then ownDenots
19061900
else collect(ownDenots, classParents)
1907-
}
19081901

1909-
override final def findMember(name: Name, pre: Type, required: FlagSet, excluded: FlagSet)(using Context): Denotation = {
1910-
val raw = if (excluded.is(Private)) nonPrivateMembersNamed(name) else membersNamed(name)
1902+
override final def findMember(name: Name, pre: Type, required: FlagSet, excluded: FlagSet)(using Context): Denotation =
1903+
val raw = if excluded.is(Private) then nonPrivateMembersNamed(name) else membersNamed(name)
19111904
raw.filterWithFlags(required, excluded).asSeenFrom(pre).toDenot(pre)
1912-
}
19131905

19141906
/** Compute tp.baseType(this) */
19151907
final def baseTypeOf(tp: Type)(using Context): Type = {
@@ -2213,25 +2205,24 @@ object SymDenotations {
22132205
* object that hides a class or object in the scala package of the same name, because
22142206
* the behavior would then be unintuitive for such members.
22152207
*/
2216-
override def computeNPMembersNamed(name: Name)(using Context): PreDenotation = {
2217-
def recur(pobjs: List[ClassDenotation], acc: PreDenotation): PreDenotation = pobjs match {
2208+
override def computeMembersNamed(name: Name)(using Context): PreDenotation =
2209+
2210+
def recur(pobjs: List[ClassDenotation], acc: PreDenotation): PreDenotation = pobjs match
22182211
case pcls :: pobjs1 =>
22192212
if (pcls.isCompleting) recur(pobjs1, acc)
2220-
else {
2221-
val pmembers = pcls.computeNPMembersNamed(name).filterWithPredicate { d =>
2213+
else
2214+
val pobjMembers = pcls.nonPrivateMembersNamed(name).filterWithPredicate { d =>
22222215
// Drop members of `Any` and `Object`
22232216
val owner = d.symbol.maybeOwner
22242217
(owner ne defn.AnyClass) && (owner ne defn.ObjectClass)
22252218
}
2226-
recur(pobjs1, acc.union(pmembers))
2227-
}
2219+
recur(pobjs1, acc.union(pobjMembers))
22282220
case nil =>
2229-
val directMembers = super.computeNPMembersNamed(name)
2221+
val directMembers = super.computeMembersNamed(name)
22302222
if !acc.exists then directMembers
22312223
else acc.union(directMembers.filterWithPredicate(!_.symbol.isAbsent())) match
22322224
case d: DenotUnion => dropStale(d)
22332225
case d => d
2234-
}
22352226

22362227
def dropStale(multi: DenotUnion): PreDenotation =
22372228
val compiledNow = multi.filterWithPredicate(d =>
@@ -2273,13 +2264,12 @@ object SymDenotations {
22732264
multi.filterWithPredicate(_.symbol.associatedFile == chosen)
22742265
end dropStale
22752266

2276-
if (symbol `eq` defn.ScalaPackageClass) {
2277-
val denots = super.computeNPMembersNamed(name)
2278-
if (denots.exists || name == nme.CONSTRUCTOR) denots
2267+
if symbol eq defn.ScalaPackageClass then
2268+
val denots = super.computeMembersNamed(name)
2269+
if denots.exists || name == nme.CONSTRUCTOR then denots
22792270
else recur(packageObjs, NoDenotation)
2280-
}
22812271
else recur(packageObjs, NoDenotation)
2282-
}
2272+
end computeMembersNamed
22832273

22842274
/** The union of the member names of the package and the package object */
22852275
override def memberNames(keepOnly: NameFilter)(implicit onBehalf: MemberNames, ctx: Context): Set[Name] = {
@@ -2325,6 +2315,13 @@ object SymDenotations {
23252315
override def owner: Symbol = throw new AssertionError("NoDenotation.owner")
23262316
override def computeAsSeenFrom(pre: Type)(using Context): SingleDenotation = this
23272317
override def mapInfo(f: Type => Type)(using Context): SingleDenotation = this
2318+
2319+
override def matches(other: SingleDenotation)(using Context): Boolean = false
2320+
override def mapInherited(ownDenots: PreDenotation, prevDenots: PreDenotation, pre: Type)(using Context): SingleDenotation = this
2321+
override def filterWithPredicate(p: SingleDenotation => Boolean): SingleDenotation = this
2322+
override def filterDisjoint(denots: PreDenotation)(using Context): SingleDenotation = this
2323+
override def filterWithFlags(required: FlagSet, excluded: FlagSet)(using Context): SingleDenotation = this
2324+
23282325
NoSymbol.denot = this
23292326
validFor = Period.allInRun(NoRunId)
23302327
}
@@ -2448,6 +2445,8 @@ object SymDenotations {
24482445
def apply(module: TermSymbol, modcls: ClassSymbol): LazyType = this
24492446

24502447
private var myDecls: Scope = EmptyScope
2448+
private var mySourceModule: Symbol = null
2449+
private var myModuleClass: Symbol = null
24512450
private var mySourceModuleFn: Context ?=> Symbol = LazyType.NoSymbolFn
24522451
private var myModuleClassFn: Context ?=> Symbol = LazyType.NoSymbolFn
24532452

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

24592458
def decls: Scope = myDecls
2460-
def sourceModule(using Context): Symbol = mySourceModuleFn
2461-
def moduleClass(using Context): Symbol = myModuleClassFn
2459+
def sourceModule(using Context): Symbol =
2460+
if mySourceModule == null then mySourceModule = mySourceModuleFn
2461+
mySourceModule
2462+
def moduleClass(using Context): Symbol =
2463+
if myModuleClass == null then myModuleClass = myModuleClassFn
2464+
myModuleClass
24622465

24632466
def withDecls(decls: Scope): this.type = { myDecls = decls; this }
24642467
def withSourceModule(sourceModuleFn: Context ?=> Symbol): this.type = { mySourceModuleFn = sourceModuleFn; this }

compiler/src/dotty/tools/dotc/transform/Instrumentation.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ class Instrumentation extends MiniPhase { thisPhase =>
3131
private val namesOfInterest = List(
3232
"::", "+=", "toString", "newArray", "box", "toCharArray",
3333
"map", "flatMap", "filter", "withFilter", "collect", "foldLeft", "foldRight", "take",
34-
"reverse", "mapConserve", "mapconserve", "filterConserve", "zip")
34+
"reverse", "mapConserve", "mapconserve", "filterConserve", "zip",
35+
"denotsNamed", "lookup", "lookupEntry", "lookupAll", "toList")
3536
private var namesToRecord: Set[Name] = _
3637

3738
private var consName: TermName = _

compiler/src/dotty/tools/dotc/util/HashTable.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,5 +138,5 @@ class HashTable[Key >: Null <: AnyRef, Value >: Null <: AnyRef]
138138
yield (keyAt(idx), valueAt(idx))
139139

140140
override def toString: String =
141-
iterator.map((k, v) => s"$k -> $v").mkString("LinearTable(", ", ", ")")
141+
iterator.map((k, v) => s"$k -> $v").mkString("HashTable(", ", ", ")")
142142
end HashTable

tests/neg/i3253.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import Test.test
22

3-
object Test {
3+
class A:
44
def test = " " * 10 // error
5-
}
5+
object Test extends A
File renamed without changes.
File renamed without changes.

0 commit comments

Comments
 (0)