From 35300b46311c93c692744701275dbb4807f851e2 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Sun, 19 Jan 2014 22:25:20 +0300 Subject: 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. --- src/reflect/scala/reflect/internal/tpe/TypeToStrings.scala | 13 ++++++++++++- src/reflect/scala/reflect/runtime/JavaUniverseForce.scala | 1 + src/reflect/scala/reflect/runtime/SynchronizedTypes.scala | 3 +++ 3 files changed, 16 insertions(+), 1 deletion(-) (limited to 'src') 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 -- cgit v1.2.3