diff options
author | Paul Phillips <paulp@improving.org> | 2012-09-28 14:36:42 -0700 |
---|---|---|
committer | Paul Phillips <paulp@improving.org> | 2012-10-09 14:17:34 -0700 |
commit | ba36c44c31d1a1e0b5c0cf3d4775edd0ae0d5a13 (patch) | |
tree | 8eb8caeb82afa0677a2e78291a990a9e525f3c7e /src/compiler/scala/tools/nsc/typechecker/Namers.scala | |
parent | 432f9368011e0fd9e89ca0e18082bfec180baf32 (diff) | |
download | scala-ba36c44c31d1a1e0b5c0cf3d4775edd0ae0d5a13.tar.gz scala-ba36c44c31d1a1e0b5c0cf3d4775edd0ae0d5a13.tar.bz2 scala-ba36c44c31d1a1e0b5c0cf3d4775edd0ae0d5a13.zip |
Fix for SI-4744, another variety of cycle.
I threw this in with the previous commit behind -Ybreak-cycles, but
this one is much less sketchy. Explanation: have to handle f-bounds
more deftly. Namers forces lower bounds to prevent recursion in
that direction, but a light touch is required to handle these two
situations differently:
// This is a cyclic type parameter - an error is correct
class A[T <: Comparable[_ <: T]]
// This is not cyclic - it flips the arrow
class B[T <: Comparable[_ >: T]]
Long have I been haunted by the knowledge that you can
write class B in java, but not in scala:
public class B<T extends Comparable<? super T>> {}
It's over! We've achieved parity with java.
Diffstat (limited to 'src/compiler/scala/tools/nsc/typechecker/Namers.scala')
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Namers.scala | 40 |
1 files changed, 30 insertions, 10 deletions
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 + } } } |