diff options
author | Martin Odersky <odersky@gmail.com> | 2007-06-29 17:53:23 +0000 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2007-06-29 17:53:23 +0000 |
commit | a8a692413d68f752dca8f5ad7cc551a03f7f9436 (patch) | |
tree | e1bb18431fe615eaa6a65e0bd01cff2b0ab56cd6 /src/compiler/scala/tools/nsc/typechecker/RefChecks.scala | |
parent | 674015b30bb6191f955548b6eff705506bf5591c (diff) | |
download | scala-a8a692413d68f752dca8f5ad7cc551a03f7f9436.tar.gz scala-a8a692413d68f752dca8f5ad7cc551a03f7f9436.tar.bz2 scala-a8a692413d68f752dca8f5ad7cc551a03f7f9436.zip |
fixed bug1170
Diffstat (limited to 'src/compiler/scala/tools/nsc/typechecker/RefChecks.scala')
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/RefChecks.scala | 194 |
1 files changed, 109 insertions, 85 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 162d291ddd..48ffb1a186 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -7,7 +7,7 @@ package scala.tools.nsc.typechecker import symtab.Flags._ -import collection.mutable.HashMap +import collection.mutable.{HashSet, HashMap} import transform.InfoTransform import scala.tools.nsc.util.{Position, NoPosition} @@ -358,88 +358,105 @@ abstract class RefChecks extends InfoTransform { private val CoVariance = 1 private val AnyVariance = 2 - /** Check variance of type variables in this type. - * - * @param base ... - * @param all ... - * @param variance ... - */ - private def validateVariance(base: Symbol, all: Type, variance: int): unit = { - - def varianceString(variance: int): String = - if (variance == 1) "covariant" - else if (variance == -1) "contravariant" - else "invariant"; - - 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 - if ((sym hasFlag PARAM) && !sym.owner.isConstructor && - !(tvar.isTypeParameterOrSkolem && sym.isTypeParameterOrSkolem && - tvar.owner == sym.owner)) state = -state; - else if (!sym.owner.isClass || sym.isPrivateLocal || sym.isProtectedLocal) - state = AnyVariance - else if (sym.isAliasType) - state = NoVariance - sym = sym.owner + private val escapedPrivateLocals = new HashSet[Symbol] + + val varianceValidator = new Traverser { + + private def validateVariance(base: Symbol) { + + def varianceString(variance: int): String = + if (variance == 1) "covariant" + else if (variance == -1) "contravariant" + else "invariant"; + + 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 + if ((sym hasFlag PARAM) && !sym.owner.isConstructor && !sym.owner.isCaseFactory && + !(tvar.isTypeParameterOrSkolem && sym.isTypeParameterOrSkolem && + tvar.owner == sym.owner)) state = -state; + else if (!sym.owner.isClass || + ((sym.isPrivateLocal || sym.isProtectedLocal) && !(escapedPrivateLocals contains sym))) + state = AnyVariance + else if (sym.isAliasType) + state = NoVariance + sym = sym.owner + } + state } - state - } - def validateVariance(tp: Type, variance: int): unit = tp match { - case ErrorType => ; - case WildcardType => ; - case NoType => ; - case NoPrefix => ; - case ThisType(_) => ; - case ConstantType(_) => ; - case DeBruijnIndex(_, _) => ; - case SingleType(pre, sym) => - validateVariance(pre, variance) - case TypeRef(pre, sym, args) => - if (sym.variance != NoVariance) { - val v = relativeVariance(sym); - if (v != AnyVariance && sym.variance != v * variance) { - //Console.println("relativeVariance(" + base + "," + sym + ") = " + v);//DEBUG - unit.error(base.pos, - varianceString(sym.variance) + " " + sym + - " occurs in " + varianceString(v * variance) + - " position in type " + all + " of " + base); + def validateVariance(tp: Type, variance: int): unit = tp match { + case ErrorType => ; + case WildcardType => ; + case NoType => ; + case NoPrefix => ; + case ThisType(_) => ; + case ConstantType(_) => ; + case DeBruijnIndex(_, _) => ; + case SingleType(pre, sym) => + validateVariance(pre, variance) + case TypeRef(pre, sym, args) => + if (sym.variance != NoVariance) { + val v = relativeVariance(sym); + if (v != AnyVariance && sym.variance != v * variance) { + //Console.println("relativeVariance(" + base + "," + sym + ") = " + v);//DEBUG + unit.error(base.pos, + varianceString(sym.variance) + " " + sym + + " occurs in " + varianceString(v * variance) + + " position in type " + base.info + " of " + base); + } } + validateVariance(pre, variance) + validateVarianceArgs(args, variance, sym.typeParams) //@M for higher-kinded typeref, args.isEmpty + // However, these args respect variances by construction anyway + // -- the interesting case is in type application, see checkKindBounds in Infer + case ClassInfoType(parents, decls, symbol) => + validateVariances(parents, variance) + case RefinedType(parents, decls) => + validateVariances(parents, variance) + case TypeBounds(lo, hi) => + validateVariance(lo, -variance) + validateVariance(hi, variance) + case MethodType(formals, result) => + validateVariance(result, variance) + case PolyType(tparams, result) => + validateVariance(result, variance) + case ExistentialType(tparams, result) => + validateVariance(result, variance) + case AnnotatedType(attribs, tp) => + validateVariance(tp, variance) + } + + def validateVariances(tps: List[Type], variance: int): unit = + tps foreach (tp => validateVariance(tp, variance)) + + def validateVarianceArgs(tps: List[Type], variance: int, tparams: List[Symbol]): unit = + (tps zip tparams) foreach { + case (tp, tparam) => validateVariance(tp, variance * tparam.variance) } - validateVariance(pre, variance) - validateVarianceArgs(args, variance, sym.typeParams) //@M for higher-kinded typeref, args.isEmpty - // However, these args respect variances by construction anyway - // -- the interesting case is in type application, see checkKindBounds in Infer - case ClassInfoType(parents, decls, symbol) => - validateVariances(parents, variance) - case RefinedType(parents, decls) => - validateVariances(parents, variance) - case TypeBounds(lo, hi) => - validateVariance(lo, -variance) - validateVariance(hi, variance) - case MethodType(formals, result) => - validateVariance(result, variance) - case PolyType(tparams, result) => - validateVariance(result, variance) - case ExistentialType(tparams, result) => - validateVariance(result, variance) - case AnnotatedType(attribs, tp) => - validateVariance(tp, variance) - } - def validateVariances(tps: List[Type], variance: int): unit = - tps foreach (tp => validateVariance(tp, variance)) + validateVariance(base.info, CoVariance) + } - def validateVarianceArgs(tps: List[Type], variance: int, tparams: List[Symbol]): unit = - (tps zip tparams) foreach { - case (tp, tparam) => validateVariance(tp, variance * tparam.variance) + override def traverse(tree: Tree): Unit = { + tree match { + case ClassDef(_, _, _, _) | TypeDef(_, _, _, _) => + validateVariance(tree.symbol) + super.traverse(tree) + // ModuleDefs need not be considered because they have been eliminated already + case ValDef(_, _, _, _) => + validateVariance(tree.symbol) + case DefDef(_, _, tparams, vparamss, tpt, rhs) => + validateVariance(tree.symbol) + traverseTrees(tparams); traverseTreess(vparamss) + case Template(_, _, _) => + super.traverse(tree) + case _ => } - - validateVariance(all, variance) + } } // Forward reference checking --------------------------------------------------- @@ -709,26 +726,17 @@ abstract class RefChecks extends InfoTransform { val sym = tree.symbol var result = tree tree match { - case ClassDef(mods, name, tparams, impl) => - validateVariance(sym, sym.info, CoVariance) - validateVariance(sym, sym.typeOfThis, CoVariance) - case DefDef(mods, name, tparams, vparams, tpt, EmptyTree) if tree.symbol.hasAttribute(definitions.NativeAttr.tpe) => tree.symbol.resetFlag(DEFERRED) result = transform(copy.DefDef(tree, mods, name, tparams, vparams, tpt, typed(Apply(gen.mkAttributedRef(definitions.Predef_error), List(Literal("native method stub")))))) case DefDef(_, _, _, _, _, _) => - validateVariance(sym, sym.tpe, CoVariance) //@M TODO: might be affected by change in tpe --> can't use tree.tpe though checkDeprecatedOvers() case ValDef(_, _, _, _) => - validateVariance(sym, sym.tpe, if (sym.isVariable) NoVariance else CoVariance) //@M TODO: might be affected by change in tpe --> can't use tree.tpe though checkDeprecatedOvers() - case TypeDef(_, _, _, _) => - validateVariance(sym, sym.info, CoVariance) - case Template(_, _, _) => localTyper = localTyper.atOwner(tree, currentOwner) validateBaseTypes(currentOwner) @@ -781,6 +789,15 @@ abstract class RefChecks extends InfoTransform { } case Select(qual, name) => + if (currentClass != sym.owner && (sym hasFlag LOCAL)) { + var o = currentClass + var hidden = false + while (!hidden && o != sym.owner && o != sym.owner.moduleClass && !o.isPackage) { + hidden = o.isTerm || o.isPrivateLocal + o = o.owner + } + if (!hidden) escapedPrivateLocals += sym + } if (sym.isSourceMethod && sym.hasFlag(CASE)) result = toConstructor(tree.pos, tree.tpe) else qual match { @@ -793,6 +810,13 @@ abstract class RefChecks extends InfoTransform { case _ => } result = super.transform(result) + result match { + case ClassDef(_, _, _, _) + | TypeDef(_, _, _, _) => + if (result.symbol.isLocal || result.symbol.owner.isPackageClass) + varianceValidator.traverse(result) + case _ => + } localTyper = savedLocalTyper result } catch { |