summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/reflect/internal/SymbolTable.scala8
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Parsers.scala4
-rw-r--r--src/compiler/scala/tools/nsc/interactive/Global.scala1
-rw-r--r--src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala2
-rw-r--r--src/compiler/scala/tools/nsc/util/WeakHashSet.scala60
-rw-r--r--test/files/run/t5527.check20
-rw-r--r--test/files/run/t5527.scala41
7 files changed, 129 insertions, 7 deletions
diff --git a/src/compiler/scala/reflect/internal/SymbolTable.scala b/src/compiler/scala/reflect/internal/SymbolTable.scala
index 7745b21aad..c8c1a51102 100644
--- a/src/compiler/scala/reflect/internal/SymbolTable.scala
+++ b/src/compiler/scala/reflect/internal/SymbolTable.scala
@@ -8,6 +8,7 @@ package internal
import scala.collection.{ mutable, immutable }
import util._
+import scala.tools.nsc.util.WeakHashSet
abstract class SymbolTable extends api.Universe
with Collections
@@ -266,9 +267,10 @@ abstract class SymbolTable extends api.Universe
}
}
- def newWeakMap[K, V]() = recordCache(mutable.WeakHashMap[K, V]())
- def newMap[K, V]() = recordCache(mutable.HashMap[K, V]())
- def newSet[K]() = recordCache(mutable.HashSet[K]())
+ def newWeakMap[K, V]() = recordCache(mutable.WeakHashMap[K, V]())
+ def newMap[K, V]() = recordCache(mutable.HashMap[K, V]())
+ def newSet[K]() = recordCache(mutable.HashSet[K]())
+ def newWeakSet[K <: AnyRef]() = recordCache(new WeakHashSet[K]())
}
/** Break into repl debugger if assertion is true. */
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
index 2b95300bad..0e5f9ee80e 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
@@ -2967,9 +2967,9 @@ self =>
val annots = annotations(true)
val pos = in.offset
val mods = (localModifiers() | implicitMod) withAnnotations annots
- val defs =
+ val defs = joinComment( // for SI-5527
if (!(mods hasFlag ~(Flags.IMPLICIT | Flags.LAZY))) defOrDcl(pos, mods)
- else List(tmplDef(pos, mods))
+ else List(tmplDef(pos, mods)))
in.token match {
case RBRACE | CASE => defs :+ (Literal(Constant()) setPos o2p(in.offset))
diff --git a/src/compiler/scala/tools/nsc/interactive/Global.scala b/src/compiler/scala/tools/nsc/interactive/Global.scala
index 0f28407f5a..477cec8c8e 100644
--- a/src/compiler/scala/tools/nsc/interactive/Global.scala
+++ b/src/compiler/scala/tools/nsc/interactive/Global.scala
@@ -1052,7 +1052,6 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "")
def newTyperRun() {
currentTyperRun = new TyperRun
- perRunCaches.clearAll()
}
class TyperResult(val tree: Tree) extends ControlThrowable
diff --git a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
index e5df144f2e..be6200b353 100644
--- a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
+++ b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
@@ -97,7 +97,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
private val wasSpecializedForTypeVars = perRunCaches.newMap[Symbol, Set[Symbol]]() withDefaultValue Set()
/** Concrete methods that use a specialized type, or override such methods. */
- private val concreteSpecMethods = perRunCaches.newSet[Symbol]()
+ private val concreteSpecMethods = perRunCaches.newWeakSet[Symbol]()
private def isSpecialized(sym: Symbol) = sym hasAnnotation SpecializedClass
private def hasSpecializedFlag(sym: Symbol) = sym hasFlag SPECIALIZED
diff --git a/src/compiler/scala/tools/nsc/util/WeakHashSet.scala b/src/compiler/scala/tools/nsc/util/WeakHashSet.scala
new file mode 100644
index 0000000000..6a10422b00
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/util/WeakHashSet.scala
@@ -0,0 +1,60 @@
+package scala.tools.nsc.util
+
+import scala.collection.mutable
+import scala.collection.mutable.ArrayBuffer
+import scala.collection.mutable.Builder
+import scala.collection.mutable.SetBuilder
+import scala.runtime.AbstractFunction1
+
+/** A bare-bones implementation of a mutable `Set` that uses weak references
+ * to hold the elements.
+ *
+ * This implementation offers only add/remove/test operations,
+ * therefore it does not fulfill the contract of Scala collection sets.
+ */
+class WeakHashSet[T <: AnyRef] extends AbstractFunction1[T, Boolean] {
+ private val underlying = mutable.HashSet[WeakReferenceWithEquals[T]]()
+
+ /** Add the given element to this set. */
+ def +=(elem: T): this.type = {
+ underlying += new WeakReferenceWithEquals(elem)
+ this
+ }
+
+ /** Remove the given element from this set. */
+ def -=(elem: T): this.type = {
+ underlying -= new WeakReferenceWithEquals(elem)
+ this
+ }
+
+ /** Does the given element belong to this set? */
+ def contains(elem: T): Boolean =
+ underlying.contains(new WeakReferenceWithEquals(elem))
+
+ /** Does the given element belong to this set? */
+ def apply(elem: T): Boolean = contains(elem)
+
+ /** Return the number of elements in this set, including reclaimed elements. */
+ def size = underlying.size
+
+ /** Remove all elements in this set. */
+ def clear() = underlying.clear()
+}
+
+/** A WeakReference implementation that implements equals and hashCode by
+ * delegating to the referent.
+ */
+class WeakReferenceWithEquals[T <: AnyRef](ref: T) {
+ def get(): T = underlying.get()
+
+ override val hashCode = ref.hashCode
+
+ override def equals(other: Any): Boolean = other match {
+ case wf: WeakReferenceWithEquals[_] =>
+ underlying.get() == wf.get()
+ case _ =>
+ false
+ }
+
+ private val underlying = new java.lang.ref.WeakReference(ref)
+}
diff --git a/test/files/run/t5527.check b/test/files/run/t5527.check
new file mode 100644
index 0000000000..cae1a80199
--- /dev/null
+++ b/test/files/run/t5527.check
@@ -0,0 +1,20 @@
+[[syntax trees at end of parser]]// Scala source: newSource1
+package <empty> {
+ abstract trait Test extends scala.ScalaObject {
+ def $init$() = {
+ ()
+ };
+ def sth: scala.Unit = {
+ /** Some comment here */
+ object Maybe extends scala.ScalaObject {
+ def <init>() = {
+ super.<init>();
+ ()
+ };
+ /** Some comment inside */
+ def nothing() = ()
+ };
+ ()
+ }
+ }
+}
diff --git a/test/files/run/t5527.scala b/test/files/run/t5527.scala
new file mode 100644
index 0000000000..3badffde14
--- /dev/null
+++ b/test/files/run/t5527.scala
@@ -0,0 +1,41 @@
+import scala.tools.partest._
+import java.io._
+import scala.tools.nsc._
+import scala.tools.nsc.util.CommandLineParser
+import scala.tools.nsc.doc.{Settings, DocFactory}
+import scala.tools.nsc.reporters.ConsoleReporter
+
+object Test extends DirectTest {
+
+ override def extraSettings: String = "-usejavacp -Xprint:parser -Yrangepos -Ystop-after:parser -d " + testOutput.path
+
+ override def code = """
+ // SI-5527
+ trait Test {
+ def sth {
+ /** Some comment here */
+ object Maybe {
+ /** Some comment inside */
+ def nothing() = ()
+ }
+ }
+ }
+ """
+
+ override def show(): Unit = {
+ // redirect err to out, for logging
+ val prevErr = System.err
+ System.setErr(System.out)
+ compile()
+ System.setErr(prevErr)
+ }
+
+ override def newCompiler(args: String*): Global = {
+ // we want the Scaladoc compiler here, because it keeps DocDef nodes in the tree
+ val settings = new Settings(_ => ())
+ val command = new ScalaDoc.Command((CommandLineParser tokenize extraSettings) ++ args.toList, settings)
+ new DocFactory(new ConsoleReporter(settings), settings).compiler
+ }
+
+ override def isDebug = false // so we don't get the newSettings warning
+}