diff options
author | Paul Phillips <paulp@improving.org> | 2011-10-06 10:00:13 +0000 |
---|---|---|
committer | Paul Phillips <paulp@improving.org> | 2011-10-06 10:00:13 +0000 |
commit | 0afd6d1b192900f2a0cda3a8fa3d8498ded91d5f (patch) | |
tree | d019e2cd31e06a0663b7dda825b7a6d1eef61516 | |
parent | 1e0f7dcb4fcc216afff4b88555d5751bbcc9a58d (diff) | |
download | scala-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.scala | 13 | ||||
-rw-r--r-- | test/files/neg/t5060.check | 7 | ||||
-rw-r--r-- | test/files/neg/t5060.scala | 19 |
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) + } +} |