aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2015-11-05 14:13:14 +0100
committerMartin Odersky <odersky@gmail.com>2015-11-05 14:13:40 +0100
commit1e280d03886e3b20fa28661b0d25b6b11dec56f3 (patch)
tree1b0dcad7124c0e7cb9881f0c629fb01195fb5a48 /src
parent4b76eeaa13176aede421af3fe86c392c438b0e5d (diff)
downloaddotty-1e280d03886e3b20fa28661b0d25b6b11dec56f3.tar.gz
dotty-1e280d03886e3b20fa28661b0d25b6b11dec56f3.tar.bz2
dotty-1e280d03886e3b20fa28661b0d25b6b11dec56f3.zip
Handle variance unsoundness in scalac
The included test pos-special/variances-constr.scala demonstrates an unsoundness in the variance checking of scalac. Scalac excludes symbols owned by constructors from the checking. This is unsound, as can be demonstrated by compiling the test and observing output of the program run: Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String at Test$.main(variances-constr.scala:17) at Test.main(variances-constr.scala) Dotty allows this code only under -language:Scala2 and issues a migration warning.
Diffstat (limited to 'src')
-rw-r--r--src/dotty/tools/dotc/typer/VarianceChecker.scala12
1 files changed, 8 insertions, 4 deletions
diff --git a/src/dotty/tools/dotc/typer/VarianceChecker.scala b/src/dotty/tools/dotc/typer/VarianceChecker.scala
index 1d3ceaa57..5d3bd4f20 100644
--- a/src/dotty/tools/dotc/typer/VarianceChecker.scala
+++ b/src/dotty/tools/dotc/typer/VarianceChecker.scala
@@ -110,16 +110,20 @@ class VarianceChecker()(implicit ctx: Context) {
private object Traverser extends TreeTraverser {
def checkVariance(sym: Symbol) = Validator.validateDefinition(sym) match {
case Some(VarianceError(tvar, required)) =>
- ctx.error(
- i"${varianceString(tvar.flags)} $tvar occurs in ${varianceString(required)} position in type ${sym.info} of $sym",
- sym.pos)
+ def msg = i"${varianceString(tvar.flags)} $tvar occurs in ${varianceString(required)} position in type ${sym.info} of $sym"
+ if (ctx.scala2Mode && sym.owner.isConstructor)
+ ctx.migrationWarning(s"According to new variance rules, this is no longer accepted; need to annotate with @uncheckedVariance:\n$msg", sym.pos)
+ else ctx.error(msg, sym.pos)
case None =>
}
override def traverse(tree: Tree)(implicit ctx: Context) = {
def sym = tree.symbol
// No variance check for private/protected[this] methods/values.
- def skip = !sym.exists || sym.is(Local)
+ def skip =
+ !sym.exists ||
+ sym.is(Local) || // !!! watch out for protected local!
+ sym.is(TypeParam) && sym.owner.isClass // already taken care of in primary constructor of class
tree match {
case defn: MemberDef if skip =>
ctx.debuglog(s"Skipping variance check of ${sym.showDcl}")