Skip to content

Commit 3d15ba0

Browse files
committed
Merge pull request scala#4774 from retronym/ticket/9498
SI-9498 Avoid caching bug with pattern type variables
2 parents d770340 + 8c94821 commit 3d15ba0

File tree

5 files changed

+88
-21
lines changed

5 files changed

+88
-21
lines changed

src/compiler/scala/tools/nsc/typechecker/Infer.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1207,6 +1207,7 @@ trait Infer extends Checkable {
12071207
}
12081208
}
12091209
tvars foreach instantiateTypeVar
1210+
invalidateTreeTpeCaches(tree0, tvars.map(_.origin.typeSymbol))
12101211
}
12111212
/* If the scrutinee has free type parameters but the pattern does not,
12121213
* we have to flip the arguments so the expected type is treated as more

src/compiler/scala/tools/nsc/typechecker/Namers.scala

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -163,13 +163,9 @@ trait Namers extends MethodSynthesis {
163163
def updatePosFlags(sym: Symbol, pos: Position, flags: Long): Symbol = {
164164
debuglog("[overwrite] " + sym)
165165
val newFlags = (sym.flags & LOCKED) | flags
166-
sym.rawInfo match {
167-
case tr: TypeRef =>
168-
// !!! needed for: pos/t5954d; the uniques type cache will happily serve up the same TypeRef
169-
// over this mutated symbol, and we witness a stale cache for `parents`.
170-
tr.invalidateCaches()
171-
case _ =>
172-
}
166+
// !!! needed for: pos/t5954d; the uniques type cache will happily serve up the same TypeRef
167+
// over this mutated symbol, and we witness a stale cache for `parents`.
168+
invalidateCaches(sym.rawInfo, sym :: sym.moduleClass :: Nil)
173169
sym reset NoType setFlag newFlags setPos pos
174170
sym.moduleClass andAlso (updatePosFlags(_, pos, moduleClassFlags(flags)))
175171

src/reflect/scala/reflect/internal/Trees.scala

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1617,21 +1617,9 @@ trait Trees extends api.Trees {
16171617
}
16181618
def apply[T <: Tree](tree: T): T = {
16191619
val tree1 = transform(tree)
1620-
invalidateSingleTypeCaches(tree1)
1620+
invalidateTreeTpeCaches(tree1, mutatedSymbols)
16211621
tree1.asInstanceOf[T]
16221622
}
1623-
private def invalidateSingleTypeCaches(tree: Tree): Unit = {
1624-
if (mutatedSymbols.nonEmpty)
1625-
for (t <- tree if t.tpe != null)
1626-
for (tp <- t.tpe) {
1627-
tp match {
1628-
case s: SingleType if mutatedSymbols contains s.sym =>
1629-
s.underlyingPeriod = NoPeriod
1630-
s.underlyingCache = NoType
1631-
case _ =>
1632-
}
1633-
}
1634-
}
16351623
override def toString() = "TreeSymSubstituter/" + substituterString("Symbol", "Symbol", from, to)
16361624
}
16371625

src/reflect/scala/reflect/internal/Types.scala

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1214,6 +1214,10 @@ trait Types
12141214

12151215
private[reflect] var underlyingCache: Type = NoType
12161216
private[reflect] var underlyingPeriod = NoPeriod
1217+
private[Types] def invalidateSingleTypeCaches(): Unit = {
1218+
underlyingCache = NoType
1219+
underlyingPeriod = NoPeriod
1220+
}
12171221
override def underlying: Type = {
12181222
val cache = underlyingCache
12191223
if (underlyingPeriod == currentPeriod && cache != null) cache
@@ -1354,6 +1358,12 @@ trait Types
13541358
private[reflect] var baseTypeSeqPeriod = NoPeriod
13551359
private[reflect] var baseClassesCache: List[Symbol] = _
13561360
private[reflect] var baseClassesPeriod = NoPeriod
1361+
private[Types] def invalidatedCompoundTypeCaches() {
1362+
baseTypeSeqCache = null
1363+
baseTypeSeqPeriod = NoPeriod
1364+
baseClassesCache = null
1365+
baseClassesPeriod = NoPeriod
1366+
}
13571367

13581368
override def baseTypeSeq: BaseTypeSeq = {
13591369
val cached = baseTypeSeqCache
@@ -1912,6 +1922,9 @@ trait Types
19121922

19131923
narrowedCache
19141924
}
1925+
private[Types] def invalidateModuleTypeRefCaches(): Unit = {
1926+
narrowedCache = null
1927+
}
19151928
override protected def finishPrefix(rest: String) = objectPrefix + rest
19161929
override def directObjectString = super.safeToString
19171930
override def toLongString = toString
@@ -1991,6 +2004,10 @@ trait Types
19912004
*/
19922005
private var relativeInfoCache: Type = _
19932006
private var relativeInfoPeriod: Period = NoPeriod
2007+
private[Types] def invalidateNonClassTypeRefCaches(): Unit = {
2008+
relativeInfoCache = NoType
2009+
relativeInfoPeriod = NoPeriod
2010+
}
19942011

19952012
private[Types] def relativeInfo = /*trace(s"relativeInfo(${safeToString}})")*/{
19962013
if (relativeInfoPeriod != currentPeriod) {
@@ -2123,6 +2140,10 @@ trait Types
21232140
}
21242141
thisInfoCache
21252142
}
2143+
private[Types] def invalidateAbstractTypeRefCaches(): Unit = {
2144+
symInfoCache = null
2145+
thisInfoCache = null
2146+
}
21262147
override def bounds = thisInfo.bounds
21272148
override protected[Types] def baseTypeSeqImpl: BaseTypeSeq = transform(bounds.hi).baseTypeSeq prepend this
21282149
override def kind = "AbstractTypeRef"
@@ -2142,9 +2163,12 @@ trait Types
21422163
trivial = fromBoolean(!sym.isTypeParameter && pre.isTrivial && areTrivialTypes(args))
21432164
toBoolean(trivial)
21442165
}
2145-
private[scala] def invalidateCaches(): Unit = {
2166+
private[Types] def invalidateTypeRefCaches(): Unit = {
2167+
parentsCache = null
21462168
parentsPeriod = NoPeriod
2169+
baseTypeSeqCache = null
21472170
baseTypeSeqPeriod = NoPeriod
2171+
normalized = null
21482172
}
21492173
private[reflect] var parentsCache: List[Type] = _
21502174
private[reflect] var parentsPeriod = NoPeriod
@@ -4569,6 +4593,39 @@ trait Types
45694593
if (!phase.erasedTypes && tp.typeSymbol == ObjectClass) AnyTpe
45704594
else tp
45714595

4596+
def invalidateTreeTpeCaches(tree: Tree, updatedSyms: List[Symbol]) = if (updatedSyms.nonEmpty)
4597+
for (t <- tree if t.tpe != null)
4598+
for (tp <- t.tpe) {
4599+
invalidateCaches(tp, updatedSyms)
4600+
}
4601+
4602+
def invalidateCaches(t: Type, updatedSyms: List[Symbol]) = {
4603+
t match {
4604+
case st: SingleType if updatedSyms.contains(st.sym) => st.invalidateSingleTypeCaches()
4605+
case _ =>
4606+
}
4607+
t match {
4608+
case tr: NonClassTypeRef if updatedSyms.contains(tr.sym) => tr.invalidateNonClassTypeRefCaches()
4609+
case _ =>
4610+
}
4611+
t match {
4612+
case tr: AbstractTypeRef if updatedSyms.contains(tr.sym) => tr.invalidateAbstractTypeRefCaches()
4613+
case _ =>
4614+
}
4615+
t match {
4616+
case tr: TypeRef if updatedSyms.contains(tr.sym) => tr.invalidateTypeRefCaches()
4617+
case _ =>
4618+
}
4619+
t match {
4620+
case tr: ModuleTypeRef if updatedSyms.contains(tr.sym) => tr.invalidateModuleTypeRefCaches()
4621+
case _ =>
4622+
}
4623+
t match {
4624+
case ct: CompoundType if ct.baseClasses.exists(updatedSyms.contains) => ct.invalidatedCompoundTypeCaches()
4625+
case _ =>
4626+
}
4627+
}
4628+
45724629
val shorthands = Set(
45734630
"scala.collection.immutable.List",
45744631
"scala.collection.immutable.Nil",

test/files/pos/t9498.scala

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
trait Inv[A] { def head: A }
2+
trait Cov[+A] { def head: A }
3+
4+
class Test {
5+
def inv(i: Inv[Inv[String]]) = i match {
6+
case l: Inv[a] =>
7+
val x: a = l.head
8+
x.head: String // okay
9+
}
10+
11+
def cov(c: Cov[Cov[String]]) = c match {
12+
case l: Cov[a] =>
13+
val x: a = l.head
14+
x.head: String // was: found A, required String
15+
}
16+
17+
def cov1(c: Cov[Cov[String]]) = c match {
18+
case l: Cov[a] => l.head.head
19+
}
20+
cov1(null): String // was: found A, required String
21+
22+
def cov3(c: Cov[Cov[String]]): String = c match {
23+
case l: Cov[a] => val l1: l.type = l; l1.head.head
24+
}
25+
}

0 commit comments

Comments
 (0)