summaryrefslogtreecommitdiff
path: root/src/reflect/scala/reflect/internal/Symbols.scala
diff options
context:
space:
mode:
authorJason Zaugg <jzaugg@gmail.com>2013-09-04 15:02:00 +0200
committerJason Zaugg <jzaugg@gmail.com>2013-09-04 15:59:36 +0200
commitfdd860df184f4c8bc6997ce2c1045b23c9fb61aa (patch)
treeab85d470988990e0e0da76e6e21d611e5dbece3b /src/reflect/scala/reflect/internal/Symbols.scala
parenta8c05274f738943ae58ecefda4b012b9daf5d8dc (diff)
downloadscala-fdd860df184f4c8bc6997ce2c1045b23c9fb61aa.tar.gz
scala-fdd860df184f4c8bc6997ce2c1045b23c9fb61aa.tar.bz2
scala-fdd860df184f4c8bc6997ce2c1045b23c9fb61aa.zip
SI-7801 Fix a nightmarish bug in Symbols#adaptInfos
The compiler-in-residence has always been a sketchy affair; FSC and REPL offers a bounty of bugs that exploit the menagerie of time-travel mechanisms in play for symbols' metadata (type, flags, name and owner.) but are often cleverly masked by optimizations in the compiler based on reference equality. The latest: an innocuous change in Erasure: https://github.com/scala/scala/commit/d8b96bb8#commitcomment-3995163 means that some `ErasureMap`-s over `MethodType`-s are now true identities (as `UnitTpe` is always the same object, whereas `erasedTypeRef(UnitClass)` returns an different `TypeRef` each time.) This, in turn, enables `TypeMap#mapOver` to reuse the existing enclosing type, and so on. On such subtleties hinge further optimizations, such as whether or not a given phase's `InfoTransformer` needs to add an entry in a symbols type history. When the REPL (or FSC / Presentation Compiler) creates a new `Run`, `Symbol#rawInfo` tries to adapt the entries in the type history for the new run. For packages, this was taken to be a no-op; each entry is marked as being valid in the new run and no further action is taken. This logic lurks in `adaptInfos`. But, when the namer enters a new symbol in a package, it *mutates* the Scope of that package classes info `enteringTyper`. So the later entries in the type history *must* be invalidated and recomputed. We have two choices for a fix: 1) modify `Namers#enterInScope` to blow away the subsequent type history for the owning symbol after inserting the new member. Something like `owner.setInfo(owner.info)` would have the desired effect. 2) Change `adaptInfos` to be more conservative when it comes to package classes, and retain only the oldest entry in the type history. This commit goes for option 2.
Diffstat (limited to 'src/reflect/scala/reflect/internal/Symbols.scala')
-rw-r--r--src/reflect/scala/reflect/internal/Symbols.scala14
1 files changed, 10 insertions, 4 deletions
diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala
index d3a0ffb744..d58ea09386 100644
--- a/src/reflect/scala/reflect/internal/Symbols.scala
+++ b/src/reflect/scala/reflect/internal/Symbols.scala
@@ -1435,6 +1435,13 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
assert(isCompilerUniverse)
if (infos == null || runId(infos.validFrom) == currentRunId) {
infos
+ } else if (isPackageClass) {
+ // SI-7801 early phase package scopes are mutated in new runs (Namers#enterPackage), so we have to
+ // discard transformed infos, rather than just marking them as from this run.
+ val oldest = infos.oldest
+ oldest.validFrom = validTo
+ this.infos = oldest
+ oldest
} else {
val prev1 = adaptInfos(infos.prev)
if (prev1 ne infos.prev) prev1
@@ -1444,10 +1451,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
_validTo = period(currentRunId, pid)
phase = phaseWithId(pid)
- val info1 = (
- if (isPackageClass) infos.info
- else adaptToNewRunMap(infos.info)
- )
+ val info1 = adaptToNewRunMap(infos.info)
if (info1 eq infos.info) {
infos.validFrom = validTo
infos
@@ -3473,6 +3477,8 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
"TypeHistory(" + phaseOf(validFrom)+":"+runId(validFrom) + "," + info + "," + prev + ")"
def toList: List[TypeHistory] = this :: ( if (prev eq null) Nil else prev.toList )
+
+ def oldest: TypeHistory = if (prev == null) this else prev.oldest
}
// ----- Hoisted closures and convenience methods, for compile time reductions -------