diff options
author | Eugene Burmako <xeno.by@gmail.com> | 2014-01-19 22:25:20 +0300 |
---|---|---|
committer | Eugene Burmako <xeno.by@gmail.com> | 2014-01-20 09:48:13 +0300 |
commit | 35300b46311c93c692744701275dbb4807f851e2 (patch) | |
tree | 492e5202d3f52afd60c9ee419c3e1a1a98098fed /src/reflect | |
parent | 936d60a2621088ba463a44c2f2d6450986022169 (diff) | |
download | scala-35300b46311c93c692744701275dbb4807f851e2.tar.gz scala-35300b46311c93c692744701275dbb4807f851e2.tar.bz2 scala-35300b46311c93c692744701275dbb4807f851e2.zip |
introduces failsafe against endless type printing
The parent commit works around a particular problem that led to a compiler
freeze in SI-8158, whereas this commit introduces a general solution -
a cache that tracks all types that we've recursed into during printing.
I can't immediately come up with an example of a type that would be caught
by this safety net, but unknown unknowns are the worst of them all, so why not
guard against them while we can.
Diffstat (limited to 'src/reflect')
3 files changed, 16 insertions, 1 deletions
diff --git a/src/reflect/scala/reflect/internal/tpe/TypeToStrings.scala b/src/reflect/scala/reflect/internal/tpe/TypeToStrings.scala index ebc4394d25..b08aabef85 100644 --- a/src/reflect/scala/reflect/internal/tpe/TypeToStrings.scala +++ b/src/reflect/scala/reflect/internal/tpe/TypeToStrings.scala @@ -3,6 +3,8 @@ package reflect package internal package tpe +import scala.collection.mutable.HashSet + private[internal] trait TypeToStrings { self: SymbolTable => @@ -14,8 +16,15 @@ private[internal] trait TypeToStrings { def tostringRecursions = _tostringRecursions def tostringRecursions_=(value: Int) = _tostringRecursions = value + private var _tostringSubjects = HashSet[Type]() + def tostringSubjects = _tostringSubjects + protected def typeToString(tpe: Type): String = - if (tostringRecursions >= maxTostringRecursions) { + if (tostringSubjects contains tpe) { + // handles self-referential anonymous classes and who knows what else + "..." + } + else if (tostringRecursions >= maxTostringRecursions) { devWarning("Exceeded recursion depth attempting to print " + util.shortClassOfInstance(tpe)) if (settings.debug) (new Throwable).printStackTrace @@ -25,8 +34,10 @@ private[internal] trait TypeToStrings { else try { tostringRecursions += 1 + tostringSubjects += tpe tpe.safeToString } finally { + tostringSubjects -= tpe tostringRecursions -= 1 } } diff --git a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala index 6b3985d434..ac6dd0783d 100644 --- a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala +++ b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala @@ -42,6 +42,7 @@ trait JavaUniverseForce { self: runtime.JavaUniverse => // inaccessible: this._glbResults // inaccessible: this._indent // inaccessible: this._tostringRecursions + // inaccessible: this._tostringSubjects // inaccessible: this.atomicIds // inaccessible: this.atomicExistentialIds // inaccessible: this._recursionTable diff --git a/src/reflect/scala/reflect/runtime/SynchronizedTypes.scala b/src/reflect/scala/reflect/runtime/SynchronizedTypes.scala index de78e527a7..12ada07a56 100644 --- a/src/reflect/scala/reflect/runtime/SynchronizedTypes.scala +++ b/src/reflect/scala/reflect/runtime/SynchronizedTypes.scala @@ -85,6 +85,9 @@ private[reflect] trait SynchronizedTypes extends internal.Types { self: SymbolTa override def tostringRecursions = _tostringRecursions.get override def tostringRecursions_=(value: Int) = _tostringRecursions.set(value) + private lazy val _tostringSubjects = mkThreadLocalStorage(new mutable.HashSet[Type]) + override def tostringSubjects = _tostringSubjects.get + /* The idea of caches is as follows. * When in reflexive mode, a cache is either null, or one sentinal * value representing undefined or the final defined |