diff options
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Infer.scala | 1 | ||||
-rw-r--r-- | src/reflect/scala/reflect/internal/Trees.scala | 14 | ||||
-rw-r--r-- | src/reflect/scala/reflect/internal/Types.scala | 20 | ||||
-rw-r--r-- | test/files/pos/t9498.scala | 25 |
4 files changed, 45 insertions, 15 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/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..1ac772fb70 100644 --- a/src/reflect/scala/reflect/internal/Types.scala +++ b/src/reflect/scala/reflect/internal/Types.scala @@ -1989,8 +1989,8 @@ trait Types * several times. Hence, no need to protected with synchronized in a multi-threaded * usage scenario. */ - private var relativeInfoCache: Type = _ - private var relativeInfoPeriod: Period = NoPeriod + private[Types] var relativeInfoCache: Type = _ + private[Types] var relativeInfoPeriod: Period = NoPeriod private[Types] def relativeInfo = /*trace(s"relativeInfo(${safeToString}})")*/{ if (relativeInfoPeriod != currentPeriod) { @@ -4569,6 +4569,22 @@ 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.underlyingCache = NoType + st.underlyingPeriod = NoPeriod + case tr: NonClassTypeRef if updatedSyms.contains(tr.sym) => + tr.relativeInfoCache = NoType + tr.relativeInfoPeriod = NoPeriod + 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 + } +} |