Skip to content

Commit 9f80d16

Browse files
authored
Merge pull request #9747 from dotty-staging/cache-iscopes
Cache more implicit scopes
2 parents b9fa8cb + 3f873ec commit 9f80d16

File tree

1 file changed

+26
-22
lines changed

1 file changed

+26
-22
lines changed

compiler/src/dotty/tools/dotc/typer/Implicits.scala

Lines changed: 26 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import Trees._
2828
import transform.SymUtils._
2929
import transform.TypeUtils._
3030
import Hashable._
31-
import util.{SourceFile, NoSource, EqHashMap}
31+
import util.{SourceFile, NoSource, EqHashMap, Stats}
3232
import config.{Config, Feature}
3333
import Feature.migrateTo3
3434
import config.Printers.{implicits, implicitsDetailed}
@@ -228,6 +228,7 @@ object Implicits:
228228
if (pt.isInstanceOf[ViewProto]) adjustSingletonArg(ref)
229229
else ref
230230
val refNorm = normalize(refAdjusted, pt)
231+
Stats.record("eligible check matches")
231232
if (!NoViewsAllowed.isCompatible(refNorm, ptNorm))
232233
ckind = Candidate.None
233234
}
@@ -314,20 +315,19 @@ object Implicits:
314315

315316
/** The implicit references that are eligible for type `tp`. */
316317
def eligible(tp: Type): List[Candidate] =
317-
if (tp.hash == NotCached) computeEligible(tp)
318+
if (tp.hash == NotCached)
319+
Stats.record(i"compute eligible not cached ${tp.getClass}")
320+
Stats.record(i"compute eligible not cached")
321+
computeEligible(tp)
318322
else {
319323
val eligibles = eligibleCache.lookup(tp)
320324
if (eligibles != null) {
321-
def elided(ci: ContextualImplicits): Int = {
322-
val n = ci.refs.length
323-
if (ci.isOuterMost) n
324-
else n + elided(ci.outerImplicits)
325-
}
326-
if (monitored) record(s"elided eligible refs", elided(this))
325+
Stats.record("cached eligible")
327326
eligibles
328327
}
329328
else if (irefCtx eq NoContext) Nil
330329
else {
330+
Stats.record(i"compute eligible cached")
331331
val result = computeEligible(tp)
332332
eligibleCache(tp) = result
333333
result
@@ -507,7 +507,7 @@ import Implicits._
507507
trait ImplicitRunInfo:
508508
self: Run =>
509509

510-
private val implicitScopeCache = mutable.AnyRefMap[Type, OfTypeImplicits]()
510+
private val implicitScopeCache = util.EqHashMap[Type, OfTypeImplicits]()
511511

512512
private def isExcluded(sym: Symbol) =
513513
if migrateTo3 then false else sym.is(Package) || sym.isPackageObject
@@ -573,10 +573,10 @@ trait ImplicitRunInfo:
573573
val companions = new TermRefSet
574574

575575
def iscopeRefs(t: Type): TermRefSet =
576-
implicitScopeCache.get(t) match
577-
case Some(is) =>
576+
implicitScopeCache.lookup(t) match
577+
case is: OfTypeImplicits =>
578578
is.companionRefs
579-
case None =>
579+
case null =>
580580
if seen.contains(t) then
581581
incomplete += tp // all references for `t` will be accounted for in `seen` so we return `EmptySet`.
582582
TermRefSet.empty // on the other hand, the refs of `tp` are now inaccurate, so `tp` is marked incomplete.
@@ -591,10 +591,10 @@ trait ImplicitRunInfo:
591591
if companion.exists && !companion.isAbsent() then
592592
companions += TermRef(pre, companion)
593593

594-
def addCompanions(t: Type) = implicitScopeCache.get(t) match
595-
case Some(iscope) =>
594+
def addCompanions(t: Type) = implicitScopeCache.lookup(t) match
595+
case iscope: OfTypeImplicits =>
596596
companions ++= iscope.companionRefs
597-
case None => t match
597+
case null => t match
598598
case t: TypeRef =>
599599
val sym = t.symbol
600600
val pre = t.prefix
@@ -634,7 +634,7 @@ trait ImplicitRunInfo:
634634
val companions = collectCompanions(tp, parts)
635635
val result = OfTypeImplicits(tp, companions)(runContext)
636636
if Config.cacheImplicitScopes
637-
&& tp.hash != NotCached
637+
&& tp.hash != NotCached
638638
&& !provisional
639639
&& (tp eq rootTp) // first type traversed is always cached
640640
|| !incomplete.contains(tp) // other types are cached if they are not incomplete
@@ -681,9 +681,11 @@ trait ImplicitRunInfo:
681681
* - If `T` is some other type, S includes the implicit scopes of all anchors of `T`.
682682
*/
683683
def implicitScope(tp: Type)(using Context): OfTypeImplicits =
684-
implicitScopeCache.get(tp) match
685-
case Some(is) => is
686-
case None =>
684+
implicitScopeCache.lookup(tp) match
685+
case is: OfTypeImplicits =>
686+
record("implicitScope cache hit")
687+
is
688+
case null =>
687689
record(i"implicitScope")
688690
val liftToAnchors = new TypeMap:
689691
override def stopAtStatic = true
@@ -713,9 +715,11 @@ trait ImplicitRunInfo:
713715
record(i"implicitScope unlifted")
714716
computeIScope(tp)
715717
else
716-
record(i"implicitScope lifted")
718+
record("implicitScope lifted")
717719
val liftedIScope = implicitScopeCache.getOrElse(liftedTp, computeIScope(liftedTp))
718-
OfTypeImplicits(tp, liftedIScope.companionRefs)(runContext)
720+
val result = OfTypeImplicits(tp, liftedIScope.companionRefs)(runContext)
721+
implicitScopeCache(tp) = result
722+
result
719723
end implicitScope
720724

721725
protected def reset(): Unit =
@@ -1358,7 +1362,7 @@ trait Implicits:
13581362
def checkDivergence(cand: Candidate): Boolean =
13591363
// For full details of the algorithm see the SIP:
13601364
// https://docs.scala-lang.org/sips/byname-implicits.html
1361-
util.Stats.record("checkDivergence")
1365+
Stats.record("checkDivergence")
13621366

13631367
// Unless we are able to tie a recursive knot, we report divergence if there is an
13641368
// open implicit using the same candidate implicit definition which has a type which

0 commit comments

Comments
 (0)