Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 21 additions & 1 deletion compiler/src/dotty/tools/dotc/core/Contexts.scala
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import Uniques.*
import ast.Trees.*
import Flags.ParamAccessor
import ast.untpd
import util.{NoSource, SimpleIdentityMap, SourceFile, HashSet, WrappedSourceFile}
import util.{NoSource, SimpleIdentityMap, SourceFile, HashSet, WrappedSourceFile, HashMap}
import typer.{Implicits, ImportInfo, SearchHistory, SearchRoot, TypeAssigner, Typer, Nullables}
import inlines.Inliner
import Nullables.*
Expand Down Expand Up @@ -125,6 +125,18 @@ object Contexts {
* of all class fields of type context; allow them only in allowlisted
* classes (which should be short-lived).
*/

/** Identity-based key for the per-context `asSeenFrom` cache. */
private[dotc] final class AsfKey(val tp: Type, val pre: Type, val cls: Symbol):
override def hashCode: Int =
((System.identityHashCode(tp) * 31
+ System.identityHashCode(pre)) * 31
+ System.identityHashCode(cls))
override def equals(other: Any): Boolean = other match
case that: AsfKey =>
(tp eq that.tp) && (pre eq that.pre) && (cls eq that.cls)
case _ => false

abstract class Context(val base: ContextBase) { thiscontext =>

protected given Context = this
Expand Down Expand Up @@ -275,6 +287,13 @@ object Contexts {
None
)

/** Cache for `TypeOps.asSeenFrom` results computed in this context. */
private var asSeenFromCacheMap: HashMap[AsfKey, Type] | Null = null
private[dotc] def asSeenFromCache: HashMap[AsfKey, Type] =
if asSeenFromCacheMap == null then
asSeenFromCacheMap = HashMap()
asSeenFromCacheMap.nn

private var related: SimpleIdentityMap[Phase | SourceFile, Context] | Null = null

private def lookup(key: Phase | SourceFile): Context | Null =
Expand Down Expand Up @@ -551,6 +570,7 @@ object Contexts {
protected def resetCaches(): Unit =
implicitsCache = null
related = null
asSeenFromCacheMap = null

/** Reuse this context as a fresh context nested inside `outer`
* But keep the typerstate, this one has to be set explicitly if needed.
Expand Down
11 changes: 10 additions & 1 deletion compiler/src/dotty/tools/dotc/core/TypeOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,16 @@ object TypeOps:
case _ =>
}

new AsSeenFromMap(pre, cls).apply(tp)
if tp.isProvisional || pre.isProvisional then
new AsSeenFromMap(pre, cls).apply(tp)
else
var hit = true
val res = ctx.asSeenFromCache.getOrElseUpdate(AsfKey(tp, pre, cls), {
hit = false
new AsSeenFromMap(pre, cls).apply(tp)
})
Stats.record(if hit then "asSeenFrom cache hit" else "asSeenFrom cache miss")
res
}

/** The TypeMap handling the asSeenFrom */
Expand Down
Loading