summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeoffrey Washburn <geoffrey.washburn@epfl.ch>2008-09-05 14:25:05 +0000
committerGeoffrey Washburn <geoffrey.washburn@epfl.ch>2008-09-05 14:25:05 +0000
commitfa8d0d8d853cebdfa33552ca2f66c229b6d39f2d (patch)
treea626126927ae5f7c1933689bdfcf290d239064fe
parentd0eb6ae1a2a6136ed90d7cbab0efcacc4cd4c337 (diff)
downloadscala-fa8d0d8d853cebdfa33552ca2f66c229b6d39f2d.tar.gz
scala-fa8d0d8d853cebdfa33552ca2f66c229b6d39f2d.tar.bz2
scala-fa8d0d8d853cebdfa33552ca2f66c229b6d39f2d.zip
Added support for -Yrecursion compiler flag.
Added two tests involving this flag.
-rw-r--r--src/compiler/scala/tools/nsc/Settings.scala1
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Symbols.scala56
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Types.scala8
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala10
-rw-r--r--test/files/pos/comp-rec-test.flags1
-rw-r--r--test/files/pos/comp-rec-test.scala24
-rw-r--r--test/files/pos/proj-rec-test.flags1
-rw-r--r--test/files/pos/proj-rec-test.scala13
8 files changed, 99 insertions, 15 deletions
diff --git a/src/compiler/scala/tools/nsc/Settings.scala b/src/compiler/scala/tools/nsc/Settings.scala
index 3b1a3cff21..8425e49043 100644
--- a/src/compiler/scala/tools/nsc/Settings.scala
+++ b/src/compiler/scala/tools/nsc/Settings.scala
@@ -141,6 +141,7 @@ class Settings(error: String => Unit) {
val logAll = BooleanSetting ("-Ylog-all", "Log all operations").hideToIDE
val noimports = BooleanSetting ("-Yno-imports", "Compile without any implicit imports")
val nopredefs = BooleanSetting ("-Yno-predefs", "Compile without any implicit predefined values")
+ val Yrecursion = IntSetting ("-Yrecursion", "Recursion depth used when locking symbols", 0, Some(0), None)
val script = StringSetting ("-Xscript", "object", "Compile as a script, wrapping the code into object.main()", "").hideToIDE
val Xshowtrees = BooleanSetting ("-Yshow-trees", "Show detailed trees when used in connection with -print:phase").hideToIDE
diff --git a/src/compiler/scala/tools/nsc/symtab/Symbols.scala b/src/compiler/scala/tools/nsc/symtab/Symbols.scala
index 3365555ed6..f01b274d39 100644
--- a/src/compiler/scala/tools/nsc/symtab/Symbols.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Symbols.scala
@@ -7,6 +7,7 @@
package scala.tools.nsc.symtab
import scala.collection.mutable.ListBuffer
+import scala.collection.immutable.Map
import scala.tools.nsc.io.AbstractFile
import scala.tools.nsc.util.{Position, NoPosition, BatchSourceFile}
import Flags._
@@ -26,6 +27,11 @@ trait Symbols {
val emptySymbolArray = new Array[Symbol](0)
val emptySymbolSet = Set.empty[Symbol]
+
+
+ /** Used to keep track of the recursion depth on locked symbols */
+ private var recursionTable = Map.empty[Symbol, Int]
+
/*
type Position;
def NoPos : Position;
@@ -181,6 +187,44 @@ trait Symbols {
final def newErrorSymbol(name: Name): Symbol =
if (name.isTypeName) newErrorClass(name) else newErrorValue(name)
+// Locking and unlocking ------------------------------------------------------
+
+ // True if the symbol is unlocked.
+ // True if the symbol is locked but still below the allowed recursion depth.
+ // False otherwise
+ def lockOK: Boolean = {
+ ((rawflags & LOCKED) == 0) ||
+ ((settings.Yrecursion.value != 0) &&
+ (recursionTable get this match {
+ case Some(n) => (n <= settings.Yrecursion.value)
+ case None => true }))
+ }
+
+ // Lock a symbol, using the handler if the recursion depth becomes too great.
+ def lock(handler: => Unit) = {
+ if ((rawflags & LOCKED) != 0) {
+ if (settings.Yrecursion.value != 0) {
+ recursionTable get this match {
+ case Some(n) =>
+ if (n > settings.Yrecursion.value) {
+ handler
+ } else {
+ recursionTable += (this -> (n + 1))
+ }
+ case None =>
+ recursionTable += (this -> 1)
+ }
+ } else { handler }
+ } else { rawflags |= LOCKED }
+ }
+
+ // Unlock a symbol
+ def unlock() = {
+ rawflags = rawflags & ~LOCKED
+ if (settings.Yrecursion.value != 0)
+ recursionTable -= this
+ }
+
// Tests ----------------------------------------------------------------------
def isTerm = false //to be overridden
@@ -499,17 +543,16 @@ trait Symbols {
assert(infos.prev eq null, this.name)
val tp = infos.info
//if (settings.debug.value) System.out.println("completing " + this.rawname + tp.getClass());//debug
- if ((rawflags & LOCKED) != 0) {
+ lock {
setInfo(ErrorType)
throw CyclicReference(this, tp)
}
- rawflags = rawflags | LOCKED
val current = phase
try {
phase = phaseOf(infos.validFrom)
tp.complete(this)
// if (settings.debug.value && runId(validTo) == currentRunId) System.out.println("completed " + this/* + ":" + info*/);//DEBUG
- rawflags = rawflags & ~LOCKED
+ unlock()
} finally {
phase = current
}
@@ -531,10 +574,10 @@ trait Symbols {
assert(info ne null)
infos = TypeHistory(currentPeriod, info, null)
if (info.isComplete) {
- rawflags = rawflags & ~LOCKED
+ unlock()
validTo = currentPeriod
} else {
- rawflags = rawflags & ~LOCKED
+ unlock()
validTo = NoPeriod
}
this
@@ -1597,7 +1640,8 @@ trait Symbols {
privateWithin = this
override def setInfo(info: Type): this.type = {
infos = TypeHistory(1, NoType, null)
- rawflags = rawflags & ~ LOCKED
+ unlock()
+// rawflags = rawflags & ~ LOCKED
validTo = currentPeriod
this
}
diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala
index 5c6f9add84..aaa24b7d19 100644
--- a/src/compiler/scala/tools/nsc/symtab/Types.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Types.scala
@@ -2051,11 +2051,11 @@ A type's typeSymbol should never be inspected directly.
if (sym1.isAliasType && sym1.info.typeParams.length == args.length) {
// note: we require that object is initialized,
// that's why we use info.typeParams instead of typeParams.
- if (sym1.hasFlag(LOCKED))
+ sym1.lock {
throw new TypeError("illegal cyclic reference involving " + sym1)
- sym1.setFlag(LOCKED)
- transform(sym1.info) // check there are no cycles
- sym1.resetFlag(LOCKED)
+ }
+ transform(sym1.info) // check there are no cycles
+ sym1.unlock()
rawTypeRef(pre, sym1, args) // don't expand type alias (cycles checked above)
} else {
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index ea7f9d447d..592d95fd2e 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -301,9 +301,7 @@ trait Typers { self: Analyzer =>
def checkNonCyclic(pos: Position, tp: Type): Boolean = {
def checkNotLocked(sym: Symbol): Boolean = {
sym.initialize
- if (sym hasFlag LOCKED) {
- error(pos, "cyclic aliasing or subtyping involving "+sym); false
- } else true
+ sym.lockOK || {error(pos, "cyclic aliasing or subtyping involving "+sym); false}
}
tp match {
case TypeRef(pre, sym, args) =>
@@ -332,9 +330,11 @@ trait Typers { self: Analyzer =>
}
def checkNonCyclic(pos: Position, tp: Type, lockedSym: Symbol): Boolean = {
- lockedSym.setFlag(LOCKED)
+ lockedSym.lock {
+ throw new TypeError("illegal cyclic reference involving " + lockedSym)
+ }
val result = checkNonCyclic(pos, tp)
- lockedSym.resetFlag(LOCKED)
+ lockedSym.unlock()
result
}
diff --git a/test/files/pos/comp-rec-test.flags b/test/files/pos/comp-rec-test.flags
new file mode 100644
index 0000000000..ad928f52a0
--- /dev/null
+++ b/test/files/pos/comp-rec-test.flags
@@ -0,0 +1 @@
+-Yrecursion 1
diff --git a/test/files/pos/comp-rec-test.scala b/test/files/pos/comp-rec-test.scala
new file mode 100644
index 0000000000..eaf12942c7
--- /dev/null
+++ b/test/files/pos/comp-rec-test.scala
@@ -0,0 +1,24 @@
+object Comp extends Application {
+
+ trait Family {
+ type T
+ }
+
+ object Trivial extends Family {
+ type T = Unit
+ }
+
+ trait Wrap extends Family {
+ val v : Family
+ type T = v.T
+ }
+
+ object WrapTrivial extends Wrap {
+ val v = Trivial
+ }
+
+ object WrapWrapTrivial extends Wrap {
+ val v = WrapTrivial
+ }
+
+}
diff --git a/test/files/pos/proj-rec-test.flags b/test/files/pos/proj-rec-test.flags
new file mode 100644
index 0000000000..ad928f52a0
--- /dev/null
+++ b/test/files/pos/proj-rec-test.flags
@@ -0,0 +1 @@
+-Yrecursion 1
diff --git a/test/files/pos/proj-rec-test.scala b/test/files/pos/proj-rec-test.scala
new file mode 100644
index 0000000000..b7efcf3e8d
--- /dev/null
+++ b/test/files/pos/proj-rec-test.scala
@@ -0,0 +1,13 @@
+object ProjTest {
+ trait MInt { type Type }
+ trait _0 extends MInt { type Type = Boolean }
+ trait Succ[Pre <: MInt] extends MInt { type Type = Pre#Type }
+
+ type _1 = Succ[_0]
+ type _2 = Succ[_1]
+
+ type X1 = _0#Type // Ok
+ type X2 = _1#Type // Ok
+ type X3 = _2#Type // Compiler error, illegal cyclic reference involving type Type
+}
+