diff options
author | Dmitry Petrashko <dmitry.petrashko@gmail.com> | 2016-12-19 13:25:28 +0100 |
---|---|---|
committer | Dmitry Petrashko <dmitry.petrashko@gmail.com> | 2016-12-19 13:25:28 +0100 |
commit | a5363c4e08d01c32501036af6aeeb8a6c07e0d3b (patch) | |
tree | c33590930e3cf4d52354dc9afa460ad7e659db46 /compiler | |
parent | 3ea7b994208bec886b5fb464e4da91550a3d8582 (diff) | |
download | dotty-a5363c4e08d01c32501036af6aeeb8a6c07e0d3b.tar.gz dotty-a5363c4e08d01c32501036af6aeeb8a6c07e0d3b.tar.bz2 dotty-a5363c4e08d01c32501036af6aeeb8a6c07e0d3b.zip |
Fix #1812, Symbols.mapSymbols shouldn't replace denotations
It will use lazy types instead.
The current version transforms a type, with a context that has denotations
that may be forcefully replaced by mapSymbols. Types created during this
transformation may cache denots, that are-to-be replaced.
This is very problematic as this method is called from TreeTypeMap.withMappedSyms
in a fixed-point cycle, creating new symbols on every iteration. Those cached denotations
could make types keep symbols from previous iterations indefinitely.
The changed version does not transform the types eagerly, and instead makes them lazy.
Assuming there are no cycles, this should ensure correct ordering.
Unfortunatelly, at this point in the compiler we basically always touch everything,
and we can't even transform the info of denotation without this denotations info.
We basically have a chicked&egg problem here. To solve it, I use the same trick as used by
other lazy types by assigning an approximation of future type first.
This allows to pass the tests and makes dotty more robust, but I suspect this isn't a complete
fix and new similar bugs may arrive.
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/src/dotty/tools/dotc/core/Symbols.scala | 21 |
1 files changed, 15 insertions, 6 deletions
diff --git a/compiler/src/dotty/tools/dotc/core/Symbols.scala b/compiler/src/dotty/tools/dotc/core/Symbols.scala index cfd85c49c..c475e99f5 100644 --- a/compiler/src/dotty/tools/dotc/core/Symbols.scala +++ b/compiler/src/dotty/tools/dotc/core/Symbols.scala @@ -313,10 +313,7 @@ trait Symbols { this: Context => newNakedSymbol[original.ThisName](original.coord) } val ttmap1 = ttmap.withSubstitution(originals, copies) - (originals, copies).zipped foreach {(original, copy) => - copy.denot = original.denot // preliminary denotation, so that we can access symbols in subsequent transform - } - (originals, copies).zipped foreach {(original, copy) => + (originals, copies).zipped foreach { (original, copy) => val odenot = original.denot val oinfo = original.info match { case ClassInfo(pre, _, parents, decls, selfInfo) => @@ -324,14 +321,26 @@ trait Symbols { this: Context => ClassInfo(pre, copy.asClass, parents, decls.cloneScope, selfInfo) case oinfo => oinfo } + + val completer = new LazyType { + def complete(denot: SymDenotation)(implicit ctx: Context): Unit = { + denot.info = oinfo // needed as otherwise we won't be able to go from Sym -> parents & etc + // Note that this is a hack, but hack commonly used in Dotty + // The same thing is done by other completers all the time + denot.info = ttmap1.mapType(oinfo) + } + } + copy.denot = odenot.copySymDenotation( symbol = copy, owner = ttmap1.mapOwner(odenot.owner), - initFlags = odenot.flags &~ Frozen | Fresh, - info = ttmap1.mapType(oinfo), + initFlags = odenot.flags &~ (Frozen | Touched) | Fresh, + info = completer, privateWithin = ttmap1.mapOwner(odenot.privateWithin), // since this refers to outer symbols, need not include copies (from->to) in ownermap here. annotations = odenot.annotations.mapConserve(ttmap1.apply)) + } + copies } |