summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Infer.scala1
-rw-r--r--src/reflect/scala/reflect/internal/Trees.scala14
-rw-r--r--src/reflect/scala/reflect/internal/Types.scala20
-rw-r--r--test/files/pos/t9498.scala25
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
+ }
+}