diff options
author | Josh Suereth <Joshua.Suereth@gmail.com> | 2012-10-20 18:02:00 -0700 |
---|---|---|
committer | Josh Suereth <Joshua.Suereth@gmail.com> | 2012-10-20 18:02:00 -0700 |
commit | 6daf9c642578c0af178075f5cc10e2a19c35e12a (patch) | |
tree | 3fda2b0dc88d6ad0091e58bce92a51978d25d367 /src/compiler | |
parent | 117bb2ac30a00f56e168f804a1561de1369ee944 (diff) | |
parent | 6ff9db6362c0b19c72b3b0ca2721367a85e13189 (diff) | |
download | scala-6daf9c642578c0af178075f5cc10e2a19c35e12a.tar.gz scala-6daf9c642578c0af178075f5cc10e2a19c35e12a.tar.bz2 scala-6daf9c642578c0af178075f5cc10e2a19c35e12a.zip |
Merge pull request #1509 from paulp/issue/6537
Fix for SI-6537, inaccurate unchecked warning.
Diffstat (limited to 'src/compiler')
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Checkable.scala | 67 |
1 files changed, 33 insertions, 34 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Checkable.scala b/src/compiler/scala/tools/nsc/typechecker/Checkable.scala index 7e15cf91a7..ec097a9b08 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Checkable.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Checkable.scala @@ -165,41 +165,43 @@ trait Checkable { /** X, P, [P1], etc. are all explained at the top of the file. */ private object CheckabilityChecker { - /** A knowable class is one which is either effectively final - * itself, or sealed with only knowable children. - */ - def isKnowable(sym: Symbol): Boolean = /*logResult(s"isKnowable($sym)")*/( - sym.initialize.isEffectivelyFinal // pesky .initialize requirement, or we receive lies about isSealed - || sym.isSealed && (sym.children forall isKnowable) + /** Are these symbols classes with no subclass relationship? */ + def areUnrelatedClasses(sym1: Symbol, sym2: Symbol) = ( + sym1.isClass + && sym2.isClass + && !(sym1 isSubClass sym2) + && !(sym2 isSubClass sym1) ) - def knownSubclasses(sym: Symbol): List[Symbol] = /*logResult(s"knownSubclasses($sym)")*/(sym :: { - if (sym.isSealed) sym.children.toList flatMap knownSubclasses - else Nil - }) - def excludable(s1: Symbol, s2: Symbol) = /*logResult(s"excludable($s1, $s2)")*/( - isKnowable(s1) - && !(s2 isSubClass s1) - && knownSubclasses(s1).forall(child => !(child isSubClass s2)) + /** Are all children of these symbols pairwise irreconcilable? */ + def allChildrenAreIrreconcilable(sym1: Symbol, sym2: Symbol) = ( + sym1.children.toList forall (c1 => + sym2.children.toList forall (c2 => + areIrreconcilableAsParents(c1, c2) + ) + ) ) - - /** Given classes A and B, can it be shown that nothing which is - * an A will ever be a subclass of something which is a B? This - * entails not only showing that !(A isSubClass B) but that the - * same is true of all their subclasses. Restated for symmetry: - * the same value cannot be a member of both A and B. + /** Is it impossible for the given symbols to be parents in the same class? + * This means given A and B, can there be an instance of A with B? This is the + * case if neither A nor B is a subclass of the other, and one of the following + * additional conditions holds: + * - either A or B is effectively final + * - neither A nor B is a trait (i.e. both are actual classes, not eligible for mixin) + * - both A and B are sealed, and every possible pairing of their children is irreconcilable * - * 1) A must not be a subclass of B, nor B of A (the trivial check) - * 2) One of A or B must be completely knowable (see isKnowable) - * 3) Assuming A is knowable, the proposition is true if - * !(A' isSubClass B) for all A', where A' is a subclass of A. - * - * Due to symmetry, the last condition applies as well in reverse. + * TODO: the last two conditions of the last possibility (that the symbols are not of + * classes being compiled in the current run) are because this currently runs too early, + * and .children returns Nil for sealed classes because their children will not be + * populated until typer. It was too difficult to move things around for the moment, + * so I will consult with moors about the optimal time to be doing this. */ - def isNeverSubClass(sym1: Symbol, sym2: Symbol) = /*logResult(s"isNeverSubClass($sym1, $sym2)")*/( - sym1.isClass - && sym2.isClass - && (excludable(sym1, sym2) || excludable(sym2, sym1)) + def areIrreconcilableAsParents(sym1: Symbol, sym2: Symbol): Boolean = areUnrelatedClasses(sym1, sym2) && ( + sym1.initialize.isEffectivelyFinal // initialization important + || sym2.initialize.isEffectivelyFinal + || !sym1.isTrait && !sym2.isTrait + || sym1.isSealed && sym2.isSealed && allChildrenAreIrreconcilable(sym1, sym2) && !currentRun.compiles(sym1) && !currentRun.compiles(sym2) ) + def isNeverSubClass(sym1: Symbol, sym2: Symbol) = areIrreconcilableAsParents(sym1, sym2) + private def isNeverSubArgs(tps1: List[Type], tps2: List[Type], tparams: List[Symbol]): Boolean = /*logResult(s"isNeverSubArgs($tps1, $tps2, $tparams)")*/ { def isNeverSubArg(t1: Type, t2: Type, variance: Int) = { if (variance > 0) isNeverSubType(t2, t1) @@ -210,10 +212,7 @@ trait Checkable { } private def isNeverSameType(tp1: Type, tp2: Type): Boolean = (tp1, tp2) match { case (TypeRef(_, sym1, args1), TypeRef(_, sym2, args2)) => - ( isNeverSubClass(sym1, sym2) - || isNeverSubClass(sym2, sym1) - || ((sym1 == sym2) && isNeverSubArgs(args1, args2, sym1.typeParams)) - ) + isNeverSubClass(sym1, sym2) || ((sym1 == sym2) && isNeverSubArgs(args1, args2, sym1.typeParams)) case _ => false } |