summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/tools/nsc/settings/ScalaSettings.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala40
-rw-r--r--src/reflect/scala/reflect/internal/Symbols.scala6
-rw-r--r--src/reflect/scala/reflect/internal/Types.scala3
-rw-r--r--test/files/neg/cycle-bounds.check4
-rw-r--r--test/files/neg/cycle-bounds.flags1
-rw-r--r--test/files/neg/cycle-bounds.scala5
-rw-r--r--test/files/neg/t1224.check2
-rw-r--r--test/files/neg/t1224.flags1
-rw-r--r--test/files/pos/cycle-bounds.scala1
-rw-r--r--test/files/pos/t4744.flags1
-rw-r--r--test/files/pos/t4744/Bar.scala (renamed from test/pending/pos/t4744/Bar.scala)0
-rw-r--r--test/files/pos/t4744/Foo.java (renamed from test/pending/pos/t4744/Foo.java)0
-rw-r--r--wip.scala2
14 files changed, 51 insertions, 17 deletions
diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
index 4829fb81b5..404f5e6b6e 100644
--- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
+++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
@@ -127,7 +127,7 @@ trait ScalaSettings extends AbsScalaSettings
val overrideObjects = BooleanSetting ("-Yoverride-objects", "Allow member objects to be overridden.")
val overrideVars = BooleanSetting ("-Yoverride-vars", "Allow vars to be overridden.")
val Yhelp = BooleanSetting ("-Y", "Print a synopsis of private options.")
- val breakCycles = BooleanSetting ("-Ybreak-cycles", "Attempt to break cycles encountered during classfile parsing")
+ val breakCycles = BooleanSetting ("-Ybreak-cycles", "Attempt to break cycles encountered during typing")
val browse = PhasesSetting ("-Ybrowse", "Browse the abstract syntax tree after")
val check = PhasesSetting ("-Ycheck", "Check the tree at the end of")
val Yshow = PhasesSetting ("-Yshow", "(Requires -Xshow-class or -Xshow-object) Show after")
diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
index 4b60fd8b27..710b3e4e54 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
@@ -707,30 +707,50 @@ trait Namers extends MethodSynthesis {
// --- Lazy Type Assignment --------------------------------------------------
- def initializeLowerBounds(tp: Type): Type = {
+ def findCyclicalLowerBound(tp: Type): Symbol = {
tp match {
case TypeBounds(lo, _) =>
// check that lower bound is not an F-bound
// but carefully: class Foo[T <: Bar[_ >: T]] should be allowed
- for (TypeRef(_, sym, _) <- lo)
- sym.maybeInitialize
+ for (tp1 @ TypeRef(_, sym, _) <- lo) {
+ if (settings.breakCycles.value) {
+ if (!sym.maybeInitialize) {
+ log(s"Cycle inspecting $lo for possible f-bounds: ${sym.fullLocationString}")
+ return sym
+ }
+ }
+ else sym.initialize
+ }
case _ =>
}
- tp
+ NoSymbol
}
def monoTypeCompleter(tree: Tree) = mkTypeCompleter(tree) { sym =>
+ // this early test is there to avoid infinite baseTypes when
+ // adding setters and getters --> bug798
+ def needsCycleCheck = sym.isNonClassType && !sym.isParameter && !sym.isExistential
logAndValidate(sym) {
- val tp = initializeLowerBounds(typeSig(tree))
+ val tp = typeSig(tree)
+
+ findCyclicalLowerBound(tp) andAlso { sym =>
+ if (needsCycleCheck) {
+ // neg/t1224: trait C[T] ; trait A { type T >: C[T] <: C[C[T]] }
+ // To avoid an infinite loop on the above, we cannot break all cycles
+ log(s"Reinitializing info of $sym to catch any genuine cycles")
+ sym reset sym.info
+ sym.initialize
+ }
+ }
sym setInfo {
if (sym.isJavaDefined) RestrictJavaArraysMap(tp)
else tp
}
- // this early test is there to avoid infinite baseTypes when
- // adding setters and getters --> bug798
- val needsCycleCheck = (sym.isAliasType || sym.isAbstractType) && !sym.isParameter
- if (needsCycleCheck && !typer.checkNonCyclic(tree.pos, tp))
- sym setInfo ErrorType
+ if (needsCycleCheck) {
+ log(s"Needs cycle check: ${sym.debugLocationString}")
+ if (!typer.checkNonCyclic(tree.pos, tp))
+ sym setInfo ErrorType
+ }
}
}
diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala
index d506a43829..7d0c05bc81 100644
--- a/src/reflect/scala/reflect/internal/Symbols.scala
+++ b/src/reflect/scala/reflect/internal/Symbols.scala
@@ -1398,9 +1398,9 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
if (!isInitialized) info
this
}
- def maybeInitialize: this.type = {
- try initialize
- catch { case _: CyclicReference => debuglog("Encountering cycle in maybe-initialization of $this") ; this }
+ def maybeInitialize = {
+ try { initialize ; true }
+ catch { case _: CyclicReference => debuglog("Hit cycle in maybeInitialize of $this") ; false }
}
/** Called when the programmer requests information that might require initialization of the underlying symbol.
diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala
index 9a43ad441f..f8b5d089e8 100644
--- a/src/reflect/scala/reflect/internal/Types.scala
+++ b/src/reflect/scala/reflect/internal/Types.scala
@@ -1710,7 +1710,8 @@ trait Types extends api.Types { self: SymbolTable =>
object baseClassesCycleMonitor {
private var open: List[Symbol] = Nil
@inline private def cycleLog(msg: => String) {
- Console.err.println(msg)
+ if (settings.debug.value)
+ Console.err.println(msg)
}
def size = open.size
def push(clazz: Symbol) {
diff --git a/test/files/neg/cycle-bounds.check b/test/files/neg/cycle-bounds.check
new file mode 100644
index 0000000000..d924838aec
--- /dev/null
+++ b/test/files/neg/cycle-bounds.check
@@ -0,0 +1,4 @@
+cycle-bounds.scala:5: error: illegal cyclic reference involving type T
+class NotOk[T <: Comparable[_ <: T]]
+ ^
+one error found
diff --git a/test/files/neg/cycle-bounds.flags b/test/files/neg/cycle-bounds.flags
new file mode 100644
index 0000000000..ca20f55172
--- /dev/null
+++ b/test/files/neg/cycle-bounds.flags
@@ -0,0 +1 @@
+-Ybreak-cycles
diff --git a/test/files/neg/cycle-bounds.scala b/test/files/neg/cycle-bounds.scala
new file mode 100644
index 0000000000..0b43bc703e
--- /dev/null
+++ b/test/files/neg/cycle-bounds.scala
@@ -0,0 +1,5 @@
+// This should be allowed
+class Ok[T <: Comparable[_ >: T]]
+
+// This is (il)legitimately a cyclic reference
+class NotOk[T <: Comparable[_ <: T]]
diff --git a/test/files/neg/t1224.check b/test/files/neg/t1224.check
index fb61275911..ab8a6f1130 100644
--- a/test/files/neg/t1224.check
+++ b/test/files/neg/t1224.check
@@ -1,4 +1,4 @@
-t1224.scala:4: error: illegal cyclic reference involving type T
+t1224.scala:4: error: lower bound C[A.this.T] does not conform to upper bound C[C[A.this.T]]
type T >: C[T] <: C[C[T]]
^
one error found
diff --git a/test/files/neg/t1224.flags b/test/files/neg/t1224.flags
new file mode 100644
index 0000000000..ca20f55172
--- /dev/null
+++ b/test/files/neg/t1224.flags
@@ -0,0 +1 @@
+-Ybreak-cycles
diff --git a/test/files/pos/cycle-bounds.scala b/test/files/pos/cycle-bounds.scala
deleted file mode 100644
index 0aa7aa552b..0000000000
--- a/test/files/pos/cycle-bounds.scala
+++ /dev/null
@@ -1 +0,0 @@
-class Foo[T <: Comparable[_ >: T]]
diff --git a/test/files/pos/t4744.flags b/test/files/pos/t4744.flags
new file mode 100644
index 0000000000..ca20f55172
--- /dev/null
+++ b/test/files/pos/t4744.flags
@@ -0,0 +1 @@
+-Ybreak-cycles
diff --git a/test/pending/pos/t4744/Bar.scala b/test/files/pos/t4744/Bar.scala
index 1fb6d78973..1fb6d78973 100644
--- a/test/pending/pos/t4744/Bar.scala
+++ b/test/files/pos/t4744/Bar.scala
diff --git a/test/pending/pos/t4744/Foo.java b/test/files/pos/t4744/Foo.java
index 6c764d0470..6c764d0470 100644
--- a/test/pending/pos/t4744/Foo.java
+++ b/test/files/pos/t4744/Foo.java
diff --git a/wip.scala b/wip.scala
new file mode 100644
index 0000000000..ed9ba97640
--- /dev/null
+++ b/wip.scala
@@ -0,0 +1,2 @@
+object Foo { }
+case class Foo(x: Int)