summaryrefslogtreecommitdiff
path: root/src/reflect
diff options
context:
space:
mode:
authorJason Zaugg <jzaugg@gmail.com>2015-01-16 13:25:31 +1000
committerJason Zaugg <jzaugg@gmail.com>2015-01-16 13:47:37 +1000
commit286dafbd45caa2b85f8113845105aaaec98be71a (patch)
tree46310ed939fe054c5b4f7cb47f0e89a8554eb5e0 /src/reflect
parent3d76836bc81c3ec183e83ee186e447ff212507d0 (diff)
downloadscala-286dafbd45caa2b85f8113845105aaaec98be71a.tar.gz
scala-286dafbd45caa2b85f8113845105aaaec98be71a.tar.bz2
scala-286dafbd45caa2b85f8113845105aaaec98be71a.zip
SI-9050 Fix crasher with value classes, recursion
From the "Substitution is hard to do" department. In 7babdab9a, TreeSymSubstitutor was modified to mutate the info of symbols defined in the tree, if that symbol's info referred to one of the `from` symbols in the substitution. It would have been more principled to create a cloned symbol with the updated info, and add that to the substitution. But I wasn't able implement that correctly (let alone efficiently.) The in-place mutation of the info of a symbol led to the crasher in this bug: a singleton type over that symbol ends up with a stale cached value of 'underlying'. In the enclosed test case, this leads to a type error in the `SubstituteRecursion` of the extension methods phase. This commit performs a cleanup job at the end of `substituteSymbols` by invalidating the cache of any `SingleType`-s in the tree that refer to one of the mutated symbols.
Diffstat (limited to 'src/reflect')
-rw-r--r--src/reflect/scala/reflect/internal/Trees.scala20
1 files changed, 19 insertions, 1 deletions
diff --git a/src/reflect/scala/reflect/internal/Trees.scala b/src/reflect/scala/reflect/internal/Trees.scala
index 35de3adff6..ccf907e05d 100644
--- a/src/reflect/scala/reflect/internal/Trees.scala
+++ b/src/reflect/scala/reflect/internal/Trees.scala
@@ -1576,6 +1576,7 @@ trait Trees extends api.Trees {
*/
class TreeSymSubstituter(from: List[Symbol], to: List[Symbol]) extends Transformer {
val symSubst = new SubstSymMap(from, to)
+ private var mutatedSymbols: List[Symbol] = Nil
override def transform(tree: Tree): Tree = {
def subst(from: List[Symbol], to: List[Symbol]) {
if (!from.isEmpty)
@@ -1594,6 +1595,7 @@ trait Trees extends api.Trees {
|TreeSymSubstituter: updated info of symbol ${tree.symbol}
| Old: ${showRaw(tree.symbol.info, printTypes = true, printIds = true)}
| New: ${showRaw(newInfo, printTypes = true, printIds = true)}""")
+ mutatedSymbols ::= tree.symbol
tree.symbol updateInfo newInfo
}
case _ =>
@@ -1613,7 +1615,23 @@ trait Trees extends api.Trees {
} else
super.transform(tree)
}
- def apply[T <: Tree](tree: T): T = transform(tree).asInstanceOf[T]
+ def apply[T <: Tree](tree: T): T = {
+ val tree1 = transform(tree)
+ invalidateSingleTypeCaches(tree1)
+ tree1.asInstanceOf[T]
+ }
+ private def invalidateSingleTypeCaches(tree: Tree): Unit = {
+ if (mutatedSymbols.nonEmpty)
+ for (t <- tree)
+ 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)
}