aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2015-09-08 12:13:34 +0200
committerMartin Odersky <odersky@gmail.com>2015-09-08 12:13:34 +0200
commit71150c808111055d23ab88763a487dbf743c4b88 (patch)
tree8143864dea4f2da2909f70c3aaf13281ed27a808 /src
parent76d083889d52a5abbf883e5577b1fd21c9a1d903 (diff)
downloaddotty-71150c808111055d23ab88763a487dbf743c4b88.tar.gz
dotty-71150c808111055d23ab88763a487dbf743c4b88.tar.bz2
dotty-71150c808111055d23ab88763a487dbf743c4b88.zip
Surivive Cyclic References when unpickling Scala 2 HK types
Closes $778. It seems impossible (or very hard) to avoid Cyclic References when unpickling Scala2 files. So we try to survive them instead. Review by @DarkDimius
Diffstat (limited to 'src')
-rw-r--r--src/dotty/tools/dotc/core/TypeApplications.scala22
-rw-r--r--src/dotty/tools/dotc/core/classfile/ClassfileParser.scala3
-rw-r--r--src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala6
-rw-r--r--src/dotty/tools/dotc/typer/Mode.scala3
4 files changed, 27 insertions, 7 deletions
diff --git a/src/dotty/tools/dotc/core/TypeApplications.scala b/src/dotty/tools/dotc/core/TypeApplications.scala
index f466cee77..a29c26fad 100644
--- a/src/dotty/tools/dotc/core/TypeApplications.scala
+++ b/src/dotty/tools/dotc/core/TypeApplications.scala
@@ -11,6 +11,7 @@ import Names._
import NameOps._
import Flags._
import StdNames.tpnme
+import typer.Mode
import util.Positions.Position
import config.Printers._
import collection.mutable
@@ -144,10 +145,23 @@ class TypeApplications(val self: Type) extends AnyVal {
println(s"precomplete decls = ${self.typeSymbol.unforcedDecls.toList.map(_.denot).mkString("\n ")}")
}
val tparam = tparams.head
- val arg1 =
- if ((tparam is HigherKinded) && !arg.isLambda && arg.typeParams.nonEmpty)
- arg.EtaExpand
- else arg
+ def needsEtaExpand =
+ try {
+ (tparam is HigherKinded) && !arg.isLambda && arg.typeParams.nonEmpty
+ }
+ catch {
+ case ex: CyclicReference =>
+ if (ctx.mode.is(Mode.Scala2Unpickling))
+ // When unpickling Scala2, we might run into cyclic references when
+ // checking whether eta expansion is needed or eta expanding.
+ // (e.g. try compile collection/generic/GenericTraversableTemplate.scala).
+ // In that case, back out gracefully. Ideally, we should not have
+ // underdefined pickling data that requires post-transformations like
+ // eta expansion, but we can't change Scala2's.
+ false
+ else throw ex
+ }
+ val arg1 = if (needsEtaExpand) arg.EtaExpand else arg
val tp1 = RefinedType(tp, tparam.name, arg1.toBounds(tparam))
matchParams(tp1, tparams.tail, args1)
case nil => tp
diff --git a/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala b/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala
index d53f545d3..b948efebb 100644
--- a/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala
+++ b/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala
@@ -12,6 +12,7 @@ import scala.collection.{ mutable, immutable }
import scala.collection.mutable.{ ListBuffer, ArrayBuffer }
import scala.annotation.switch
import typer.Checking.checkNonCyclic
+import typer.Mode
import io.AbstractFile
import scala.util.control.NonFatal
@@ -673,7 +674,7 @@ class ClassfileParser(
def unpickleScala(bytes: Array[Byte]): Some[Embedded] = {
val unpickler = new unpickleScala2.Scala2Unpickler(bytes, classRoot, moduleRoot)(ctx)
- unpickler.run()
+ unpickler.run()(ctx.addMode(Mode.Scala2Unpickling))
Some(unpickler)
}
diff --git a/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala b/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala
index a3c131427..e6eb89008 100644
--- a/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala
+++ b/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala
@@ -17,6 +17,7 @@ import printing.Printer
import io.AbstractFile
import util.common._
import typer.Checking.checkNonCyclic
+import typer.Mode
import PickleBuffer._
import scala.reflect.internal.pickling.PickleFormat._
import Decorators._
@@ -520,7 +521,7 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas
class LocalUnpickler extends LazyType {
def startCoord(denot: SymDenotation): Coord = denot.symbol.coord
def complete(denot: SymDenotation)(implicit ctx: Context): Unit = try {
- def parseToCompletion(denot: SymDenotation) = {
+ def parseToCompletion(denot: SymDenotation)(implicit ctx: Context) = {
val tag = readByte()
val end = readNat() + readIndex
def atEnd = readIndex == end
@@ -566,7 +567,8 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas
}
// println(s"unpickled ${denot.debugString}, info = ${denot.info}") !!! DEBUG
}
- atReadPos(startCoord(denot).toIndex, () => parseToCompletion(denot))
+ atReadPos(startCoord(denot).toIndex,
+ () => parseToCompletion(denot)(ctx.addMode(Mode.Scala2Unpickling)))
} catch {
case ex: RuntimeException => handleRuntimeException(ex)
}
diff --git a/src/dotty/tools/dotc/typer/Mode.scala b/src/dotty/tools/dotc/typer/Mode.scala
index 8dd4c5b68..55d44ad7a 100644
--- a/src/dotty/tools/dotc/typer/Mode.scala
+++ b/src/dotty/tools/dotc/typer/Mode.scala
@@ -79,5 +79,8 @@ object Mode {
*/
val ImplicitExploration = newMode(12, "ImplicitExploration")
+ /** We are currently unpickling Scala2 info */
+ val Scala2Unpickling = newMode(13, "Scala2Unpickling")
+
val PatternOrType = Pattern | Type
}