aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2014-06-20 15:04:03 +0200
committerMartin Odersky <odersky@gmail.com>2014-06-20 15:04:19 +0200
commitb3364db33ff2ee2d57b4d0eaed03632099244f63 (patch)
treecfc94722c01bf6a7ddb3eff5411149e8a40235e1 /src/dotty/tools/dotc
parent7cf6202ea94c016ffc2d2528ad8add186e9f3827 (diff)
downloaddotty-b3364db33ff2ee2d57b4d0eaed03632099244f63.tar.gz
dotty-b3364db33ff2ee2d57b4d0eaed03632099244f63.tar.bz2
dotty-b3364db33ff2ee2d57b4d0eaed03632099244f63.zip
Avoid caching values that depend on typevar state.
TypeVars flip from the initial state, where underlying == origin to the final state where underlying == inst. This flip can invalidate information that depends on the underlying type of a TypeVar. Since we do not know when the flip occurs, we need to avoid keeping any such information in a cache. The commit makes three caches depend on a new value: typerState.ephemeral. The value is set to `true` each time we follow the underlying type of a TypeVar, and this disables cached information to be retained. A test case for this commit is t2693.scala. This test passes typechecking with the previous commit, but fails in -Ycheck:front because of stale cache info in an "#Apply" typeref. The present commit fixes that.
Diffstat (limited to 'src/dotty/tools/dotc')
-rw-r--r--src/dotty/tools/dotc/core/TyperState.scala12
-rw-r--r--src/dotty/tools/dotc/core/Types.scala48
-rw-r--r--src/dotty/tools/dotc/typer/Implicits.scala33
3 files changed, 66 insertions, 27 deletions
diff --git a/src/dotty/tools/dotc/core/TyperState.scala b/src/dotty/tools/dotc/core/TyperState.scala
index 8c742edab..fd8a534d4 100644
--- a/src/dotty/tools/dotc/core/TyperState.scala
+++ b/src/dotty/tools/dotc/core/TyperState.scala
@@ -23,6 +23,10 @@ class TyperState(r: Reporter) extends DotClass with Showable {
/** The uninstantiated variables */
def uninstVars = constraint.uninstVars
+ /** The ephemeral flag */
+ def ephemeral: Boolean = false
+ def ephemeral_=(x: Boolean): Unit = ()
+
/** Gives for each instantiated type var that does not yet have its `inst` field
* set, the instance value stored in the constraint. Storing instances in constraints
* is done only in a temporary way for contexts that may be retracted
@@ -76,6 +80,12 @@ extends TyperState(r) {
override def constraint = myConstraint
override def constraint_=(c: Constraint) = myConstraint = c
+ private var myEphemeral: Boolean = previous.ephemeral
+
+ override def ephemeral = myEphemeral
+ override def ephemeral_=(x: Boolean): Unit = { myEphemeral = x }
+
+
override def fresh(isCommittable: Boolean): TyperState =
new MutableTyperState(this, new StoreReporter, isCommittable)
@@ -96,11 +106,11 @@ extends TyperState(r) {
val targetState = ctx.typerState
assert(isCommittable)
targetState.constraint = constraint
-
constraint foreachTypeVar { tvar =>
if (tvar.owningState eq this)
tvar.owningState = targetState
}
+ targetState.ephemeral = ephemeral
targetState.gc()
reporter.flush()
}
diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala
index f1cdfe54b..f3e10c5b0 100644
--- a/src/dotty/tools/dotc/core/Types.scala
+++ b/src/dotty/tools/dotc/core/Types.scala
@@ -1075,24 +1075,32 @@ object Types {
/** A second fallback to recompute the denotation if necessary */
private def computeDenot(implicit ctx: Context): Denotation = {
- val d = lastDenotation match {
- case null =>
- val sym = lastSymbol
- if (sym == null) loadDenot else denotOfSym(sym)
- case d: SymDenotation =>
- if (d.validFor.runId == ctx.runId || ctx.stillValid(d)) d.current
- else {
- val newd = loadDenot
- if (newd.exists) newd else d.staleSymbolError
- }
- case d =>
- if (d.validFor.runId == ctx.period.runId) d.current
- else loadDenot
+ val savedEphemeral = ctx.typerState.ephemeral
+ ctx.typerState.ephemeral = false
+ try {
+ val d = lastDenotation match {
+ case null =>
+ val sym = lastSymbol
+ if (sym == null) loadDenot else denotOfSym(sym)
+ case d: SymDenotation =>
+ if (d.validFor.runId == ctx.runId || ctx.stillValid(d)) d.current
+ else {
+ val newd = loadDenot
+ if (newd.exists) newd else d.staleSymbolError
+ }
+ case d =>
+ if (d.validFor.runId == ctx.period.runId) d.current
+ else loadDenot
+ }
+ if (ctx.typerState.ephemeral) record("ephemeral cache miss: loadDenot")
+ else {
+ lastDenotation = d
+ lastSymbol = d.symbol
+ checkedPeriod = ctx.period
+ }
+ d
}
- lastDenotation = d
- lastSymbol = d.symbol
- checkedPeriod = ctx.period
- d
+ finally ctx.typerState.ephemeral |= savedEphemeral
}
private def denotOfSym(sym: Symbol)(implicit ctx: Context): Denotation = {
@@ -1974,7 +1982,11 @@ object Types {
/** If the variable is instantiated, its instance, otherwise its origin */
override def underlying(implicit ctx: Context): Type = {
val inst = instanceOpt
- if (inst.exists) inst else origin
+ if (inst.exists) inst
+ else {
+ ctx.typerState.ephemeral = true
+ origin
+ }
}
override def computeHash: Int = identityHash
diff --git a/src/dotty/tools/dotc/typer/Implicits.scala b/src/dotty/tools/dotc/typer/Implicits.scala
index 86d513fff..da1492d61 100644
--- a/src/dotty/tools/dotc/typer/Implicits.scala
+++ b/src/dotty/tools/dotc/typer/Implicits.scala
@@ -142,9 +142,15 @@ object Implicits {
if (monitored) record(s"elided eligible refs", elided(this))
eligibles
case None =>
- val eligibles = computeEligible(tp)
- eligibleCache(tp) = eligibles
- eligibles
+ val savedEphemeral = ctx.typerState.ephemeral
+ ctx.typerState.ephemeral = false
+ try {
+ val result = computeEligible(tp)
+ if (ctx.typerState.ephemeral) record("ephemeral cache miss: eligible")
+ else eligibleCache(tp) = result
+ result
+ }
+ finally ctx.typerState.ephemeral |= savedEphemeral
}
}
@@ -334,11 +340,22 @@ trait ImplicitRunInfo { self: RunInfo =>
def iscope(tp: Type, isLifted: Boolean = false): OfTypeImplicits =
if (tp.hash == NotCached || !Config.cacheImplicitScopes)
ofTypeImplicits(collectCompanions(tp))
- else implicitScopeCache.getOrElseUpdate(tp, {
- val liftedTp = if (isLifted) tp else liftToClasses(tp)
- if (liftedTp ne tp) iscope(liftedTp, isLifted = true)
- else ofTypeImplicits(collectCompanions(tp))
- })
+ else implicitScopeCache get tp match {
+ case Some(is) => is
+ case None =>
+ val savedEphemeral = ctx.typerState.ephemeral
+ ctx.typerState.ephemeral = false
+ try {
+ val liftedTp = if (isLifted) tp else liftToClasses(tp)
+ val result =
+ if (liftedTp ne tp) iscope(liftedTp, isLifted = true)
+ else ofTypeImplicits(collectCompanions(tp))
+ if (ctx.typerState.ephemeral) record("ephemeral cache miss: implicitScope")
+ else implicitScopeCache(tp) = result
+ result
+ }
+ finally ctx.typerState.ephemeral |= savedEphemeral
+ }
iscope(tp)
}