summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2009-06-24 15:37:16 +0000
committerMartin Odersky <odersky@gmail.com>2009-06-24 15:37:16 +0000
commit410efa8317f2a244f45f33b2ae7c17be5472f5d5 (patch)
tree0cddab6b90904718b8162797656ab7076bb920ce /src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
parent1c9870541fb22ac032edaa0be0103cc1aa2c99b4 (diff)
downloadscala-410efa8317f2a244f45f33b2ae7c17be5472f5d5.tar.gz
scala-410efa8317f2a244f45f33b2ae7c17be5472f5d5.tar.bz2
scala-410efa8317f2a244f45f33b2ae7c17be5472f5d5.zip
fixed variance bug; added smart brace insertion...
fixed variance bug; added smart brace insertion to parser. moved interactive compiler interface along.
Diffstat (limited to 'src/compiler/scala/tools/nsc/typechecker/RefChecks.scala')
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/RefChecks.scala37
1 files changed, 31 insertions, 6 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
index 2015716aae..f9ad690472 100644
--- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
@@ -415,6 +415,7 @@ abstract class RefChecks extends InfoTransform {
val varianceValidator = new Traverser {
+ /** Validate variance of info of symbol `base` */
private def validateVariance(base: Symbol) {
def varianceString(variance: Int): String =
@@ -422,25 +423,46 @@ abstract class RefChecks extends InfoTransform {
else if (variance == -1) "contravariant"
else "invariant";
+ /** The variance of a symbol occurrence of `tvar`
+ * seen at the level of the definition of `base`.
+ * The search proceeds from `base` to the owner of `tvar`.
+ * Initially the state is covariant, but it might change along the search.
+ */
def relativeVariance(tvar: Symbol): Int = {
val clazz = tvar.owner
var sym = base
var state = CoVariance
while (sym != clazz && state != AnyVariance) {
//Console.println("flip: " + sym + " " + sym.isParameter());//DEBUG
+ // Flip occurrences of type parameters and parameters, unless
+ // - it's a constructor, or case class factory or extractor
+ // - it's a type parameter of tvar's owner.
if ((sym hasFlag PARAM) && !sym.owner.isConstructor && !sym.owner.isCaseApplyOrUnapply &&
!(tvar.isTypeParameterOrSkolem && sym.isTypeParameterOrSkolem &&
tvar.owner == sym.owner)) state = -state;
else if (!sym.owner.isClass ||
- sym.isTerm && ((sym.isPrivateLocal || sym.isProtectedLocal) && !(escapedPrivateLocals contains sym)))
+ sym.isTerm && ((sym.isPrivateLocal || sym.isProtectedLocal) && !(escapedPrivateLocals contains sym))) {
+ // return AnyVariance if `sym` is local to a term
+ // or is private[this] or protected[this]
state = AnyVariance
- else if (sym.isAliasType)
- state = AnyVariance // was NoVariance, but now we always expand aliases.
+ } else if (sym.isAliasType) {
+ // return AnyVariance if `sym` is an alias type
+ // that does not override anything. This is OK, because we always
+ // expand aliases for variance checking.
+ // However, if `sym` does override a type in a base class
+ // we have to assume NoVariance, as there might then be
+ // references to the type parameter that are not variance checked.
+ state = if (sym.allOverriddenSymbols.isEmpty) AnyVariance
+ else NoVariance
+ }
sym = sym.owner
}
state
}
+ /** Validate that the type `tp` is variance-correct, assuming
+ * the type occurs itself at variance position given by `variance`
+ */
def validateVariance(tp: Type, variance: Int): Unit = tp match {
case ErrorType => ;
case WildcardType => ;
@@ -452,10 +474,10 @@ abstract class RefChecks extends InfoTransform {
case SingleType(pre, sym) =>
validateVariance(pre, variance)
case TypeRef(pre, sym, args) =>
- if (sym.isAliasType)
+ if (sym.isAliasType && relativeVariance(sym) == AnyVariance)
validateVariance(tp.normalize, variance)
else if (sym.variance != NoVariance) {
- val v = relativeVariance(sym);
+ val v = relativeVariance(sym)
if (v != AnyVariance && sym.variance != v * variance) {
//Console.println("relativeVariance(" + base + "," + sym + ") = " + v);//DEBUG
def tpString(tp: Type) = tp match {
@@ -476,6 +498,8 @@ abstract class RefChecks extends InfoTransform {
validateVariances(parents, variance)
case RefinedType(parents, decls) =>
validateVariances(parents, variance)
+ for (sym <- decls.toList)
+ validateVariance(sym.info, if (sym.isAliasType) NoVariance else variance)
case TypeBounds(lo, hi) =>
validateVariance(lo, -variance)
validateVariance(hi, variance)
@@ -507,7 +531,8 @@ abstract class RefChecks extends InfoTransform {
override def traverse(tree: Tree) {
tree match {
- case ClassDef(_, _, _, _) | TypeDef(_, _, _, _) =>
+ case ClassDef(_, _, _, _) |
+ TypeDef(_, _, _, _) =>
validateVariance(tree.symbol)
super.traverse(tree)
// ModuleDefs need not be considered because they have been eliminated already