summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2011-10-06 10:00:13 +0000
committerPaul Phillips <paulp@improving.org>2011-10-06 10:00:13 +0000
commit0afd6d1b192900f2a0cda3a8fa3d8498ded91d5f (patch)
treed019e2cd31e06a0663b7dda825b7a6d1eef61516
parent1e0f7dcb4fcc216afff4b88555d5751bbcc9a58d (diff)
downloadscala-0afd6d1b192900f2a0cda3a8fa3d8498ded91d5f.tar.gz
scala-0afd6d1b192900f2a0cda3a8fa3d8498ded91d5f.tar.bz2
scala-0afd6d1b192900f2a0cda3a8fa3d8498ded91d5f.zip
Closing soundness hole in variance checking.
See SI-5060. Review by odersky.
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/RefChecks.scala13
-rw-r--r--test/files/neg/t5060.check7
-rw-r--r--test/files/neg/t5060.scala19
3 files changed, 37 insertions, 2 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
index 3b9cf88a00..b3e1e3feb8 100644
--- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
@@ -762,6 +762,9 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R
/** Validate variance of info of symbol `base` */
private def validateVariance(base: Symbol) {
+ // A flag for when we're in a refinement, meaning method parameter types
+ // need to be checked.
+ var inRefinement = false
def varianceString(variance: Int): String =
if (variance == 1) "covariant"
@@ -845,12 +848,17 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R
validateVariances(parents, variance)
case RefinedType(parents, decls) =>
validateVariances(parents, variance)
+ val saved = inRefinement
+ inRefinement = true
for (sym <- decls)
validateVariance(sym.info, if (sym.isAliasType) NoVariance else variance)
+ inRefinement = saved
case TypeBounds(lo, hi) =>
validateVariance(lo, -variance)
validateVariance(hi, variance)
case MethodType(formals, result) =>
+ if (inRefinement)
+ validateVariances(formals map (_.tpe), -variance)
validateVariance(result, variance)
case NullaryMethodType(result) =>
validateVariance(result, variance)
@@ -887,9 +895,10 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R
// ModuleDefs need not be considered because they have been eliminated already
case ValDef(_, _, _, _) =>
validateVariance(tree.symbol)
- case DefDef(_, _, tparams, vparamss, tpt, rhs) =>
+ case DefDef(_, _, tparams, vparamss, _, _) =>
validateVariance(tree.symbol)
- traverseTrees(tparams); traverseTreess(vparamss)
+ traverseTrees(tparams)
+ traverseTreess(vparamss)
case Template(_, _, _) =>
super.traverse(tree)
case _ =>
diff --git a/test/files/neg/t5060.check b/test/files/neg/t5060.check
new file mode 100644
index 0000000000..ab860c9d5b
--- /dev/null
+++ b/test/files/neg/t5060.check
@@ -0,0 +1,7 @@
+t5060.scala:2: error: covariant type T occurs in contravariant position in type => Object with ScalaObject{def contains(x: T): Unit} of value foo0
+ val foo0 = {
+ ^
+t5060.scala:6: error: covariant type T occurs in contravariant position in type => Object with ScalaObject{def contains(x: T): Unit} of method foo1
+ def foo1 = {
+ ^
+two errors found
diff --git a/test/files/neg/t5060.scala b/test/files/neg/t5060.scala
new file mode 100644
index 0000000000..4d934a9a16
--- /dev/null
+++ b/test/files/neg/t5060.scala
@@ -0,0 +1,19 @@
+class A[+T] {
+ val foo0 = {
+ class AsVariantAsIWantToBe { def contains(x: T) = () }
+ new AsVariantAsIWantToBe
+ }
+ def foo1 = {
+ class VarianceIsTheSpiceOfTypes { def contains(x: T) = () }
+ new VarianceIsTheSpiceOfTypes
+ }
+}
+
+object Test {
+ def main(args: Array[String]): Unit = {
+ val xs: A[String] = new A[String]
+ println(xs.foo0 contains "abc")
+ println((xs: A[Any]).foo0 contains 5)
+ // java.lang.NoSuchMethodException: A$AsVariantAsIWantToBe$1.contains(java.lang.String)
+ }
+}