diff options
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Infer.scala | 1 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Namers.scala | 10 | ||||
-rw-r--r-- | src/reflect/scala/reflect/internal/Trees.scala | 14 | ||||
-rw-r--r-- | src/reflect/scala/reflect/internal/Types.scala | 59 | ||||
-rw-r--r-- | test/files/pos/t9498.scala | 25 |
5 files changed, 88 insertions, 21 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index a5fdbb5148..684cf788a4 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -1207,6 +1207,7 @@ trait Infer extends Checkable { } } tvars foreach instantiateTypeVar + invalidateTreeTpeCaches(tree0, tvars.map(_.origin.typeSymbol)) } /* If the scrutinee has free type parameters but the pattern does not, * we have to flip the arguments so the expected type is treated as more diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index 254cb7111c..ba095c808e 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -163,13 +163,9 @@ trait Namers extends MethodSynthesis { def updatePosFlags(sym: Symbol, pos: Position, flags: Long): Symbol = { debuglog("[overwrite] " + sym) val newFlags = (sym.flags & LOCKED) | flags - sym.rawInfo match { - case tr: TypeRef => - // !!! needed for: pos/t5954d; the uniques type cache will happily serve up the same TypeRef - // over this mutated symbol, and we witness a stale cache for `parents`. - tr.invalidateCaches() - case _ => - } + // !!! needed for: pos/t5954d; the uniques type cache will happily serve up the same TypeRef + // over this mutated symbol, and we witness a stale cache for `parents`. + invalidateCaches(sym.rawInfo, sym :: sym.moduleClass :: Nil) sym reset NoType setFlag newFlags setPos pos sym.moduleClass andAlso (updatePosFlags(_, pos, moduleClassFlags(flags))) diff --git a/src/reflect/scala/reflect/internal/Trees.scala b/src/reflect/scala/reflect/internal/Trees.scala index bbd9df05d2..49554d6d0f 100644 --- a/src/reflect/scala/reflect/internal/Trees.scala +++ b/src/reflect/scala/reflect/internal/Trees.scala @@ -1617,21 +1617,9 @@ trait Trees extends api.Trees { } def apply[T <: Tree](tree: T): T = { val tree1 = transform(tree) - invalidateSingleTypeCaches(tree1) + invalidateTreeTpeCaches(tree1, mutatedSymbols) tree1.asInstanceOf[T] } - private def invalidateSingleTypeCaches(tree: Tree): Unit = { - if (mutatedSymbols.nonEmpty) - for (t <- tree if t.tpe != null) - for (tp <- t.tpe) { - tp match { - case s: SingleType if mutatedSymbols contains s.sym => - s.underlyingPeriod = NoPeriod - s.underlyingCache = NoType - case _ => - } - } - } override def toString() = "TreeSymSubstituter/" + substituterString("Symbol", "Symbol", from, to) } diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala index 2ae95c98e5..33592bbd86 100644 --- a/src/reflect/scala/reflect/internal/Types.scala +++ b/src/reflect/scala/reflect/internal/Types.scala @@ -1214,6 +1214,10 @@ trait Types private[reflect] var underlyingCache: Type = NoType private[reflect] var underlyingPeriod = NoPeriod + private[Types] def invalidateSingleTypeCaches(): Unit = { + underlyingCache = NoType + underlyingPeriod = NoPeriod + } override def underlying: Type = { val cache = underlyingCache if (underlyingPeriod == currentPeriod && cache != null) cache @@ -1354,6 +1358,12 @@ trait Types private[reflect] var baseTypeSeqPeriod = NoPeriod private[reflect] var baseClassesCache: List[Symbol] = _ private[reflect] var baseClassesPeriod = NoPeriod + private[Types] def invalidatedCompoundTypeCaches() { + baseTypeSeqCache = null + baseTypeSeqPeriod = NoPeriod + baseClassesCache = null + baseClassesPeriod = NoPeriod + } override def baseTypeSeq: BaseTypeSeq = { val cached = baseTypeSeqCache @@ -1912,6 +1922,9 @@ trait Types narrowedCache } + private[Types] def invalidateModuleTypeRefCaches(): Unit = { + narrowedCache = null + } override protected def finishPrefix(rest: String) = objectPrefix + rest override def directObjectString = super.safeToString override def toLongString = toString @@ -1991,6 +2004,10 @@ trait Types */ private var relativeInfoCache: Type = _ private var relativeInfoPeriod: Period = NoPeriod + private[Types] def invalidateNonClassTypeRefCaches(): Unit = { + relativeInfoCache = NoType + relativeInfoPeriod = NoPeriod + } private[Types] def relativeInfo = /*trace(s"relativeInfo(${safeToString}})")*/{ if (relativeInfoPeriod != currentPeriod) { @@ -2123,6 +2140,10 @@ trait Types } thisInfoCache } + private[Types] def invalidateAbstractTypeRefCaches(): Unit = { + symInfoCache = null + thisInfoCache = null + } override def bounds = thisInfo.bounds override protected[Types] def baseTypeSeqImpl: BaseTypeSeq = transform(bounds.hi).baseTypeSeq prepend this override def kind = "AbstractTypeRef" @@ -2142,9 +2163,12 @@ trait Types trivial = fromBoolean(!sym.isTypeParameter && pre.isTrivial && areTrivialTypes(args)) toBoolean(trivial) } - private[scala] def invalidateCaches(): Unit = { + private[Types] def invalidateTypeRefCaches(): Unit = { + parentsCache = null parentsPeriod = NoPeriod + baseTypeSeqCache = null baseTypeSeqPeriod = NoPeriod + normalized = null } private[reflect] var parentsCache: List[Type] = _ private[reflect] var parentsPeriod = NoPeriod @@ -4569,6 +4593,39 @@ trait Types if (!phase.erasedTypes && tp.typeSymbol == ObjectClass) AnyTpe else tp + def invalidateTreeTpeCaches(tree: Tree, updatedSyms: List[Symbol]) = if (updatedSyms.nonEmpty) + for (t <- tree if t.tpe != null) + for (tp <- t.tpe) { + invalidateCaches(tp, updatedSyms) + } + + def invalidateCaches(t: Type, updatedSyms: List[Symbol]) = { + t match { + case st: SingleType if updatedSyms.contains(st.sym) => st.invalidateSingleTypeCaches() + case _ => + } + t match { + case tr: NonClassTypeRef if updatedSyms.contains(tr.sym) => tr.invalidateNonClassTypeRefCaches() + case _ => + } + t match { + case tr: AbstractTypeRef if updatedSyms.contains(tr.sym) => tr.invalidateAbstractTypeRefCaches() + case _ => + } + t match { + case tr: TypeRef if updatedSyms.contains(tr.sym) => tr.invalidateTypeRefCaches() + case _ => + } + t match { + case tr: ModuleTypeRef if updatedSyms.contains(tr.sym) => tr.invalidateModuleTypeRefCaches() + case _ => + } + t match { + case ct: CompoundType if ct.baseClasses.exists(updatedSyms.contains) => ct.invalidatedCompoundTypeCaches() + case _ => + } + } + val shorthands = Set( "scala.collection.immutable.List", "scala.collection.immutable.Nil", diff --git a/test/files/pos/t9498.scala b/test/files/pos/t9498.scala new file mode 100644 index 0000000000..32fc01a806 --- /dev/null +++ b/test/files/pos/t9498.scala @@ -0,0 +1,25 @@ +trait Inv[A] { def head: A } +trait Cov[+A] { def head: A } + +class Test { + def inv(i: Inv[Inv[String]]) = i match { + case l: Inv[a] => + val x: a = l.head + x.head: String // okay + } + + def cov(c: Cov[Cov[String]]) = c match { + case l: Cov[a] => + val x: a = l.head + x.head: String // was: found A, required String + } + + def cov1(c: Cov[Cov[String]]) = c match { + case l: Cov[a] => l.head.head + } + cov1(null): String // was: found A, required String + + def cov3(c: Cov[Cov[String]]): String = c match { + case l: Cov[a] => val l1: l.type = l; l1.head.head + } +} |