summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2012-12-31 12:36:04 -0800
committerPaul Phillips <paulp@improving.org>2013-01-09 12:11:13 -0800
commit91d8584fde15140972f7d6037d632bc24fc50f94 (patch)
treebe48d686376c24648cb9a27abd323ed63f94254a /src/compiler/scala/tools
parent36ec5ff749a8148637129aa83d2cc597a773272b (diff)
downloadscala-91d8584fde15140972f7d6037d632bc24fc50f94.tar.gz
scala-91d8584fde15140972f7d6037d632bc24fc50f94.tar.bz2
scala-91d8584fde15140972f7d6037d632bc24fc50f94.zip
Moved Variances into SymbolTable.
So I can centralize all the redundant variance code.
Diffstat (limited to 'src/compiler/scala/tools')
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Analyzer.scala1
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/RefChecks.scala13
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Variances.scala197
3 files changed, 11 insertions, 200 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala b/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala
index 5e8bb3e424..d4d6def3cb 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala
@@ -16,7 +16,6 @@ trait Analyzer extends AnyRef
with Typers
with Infer
with Implicits
- with Variances
with EtaExpansion
with SyntheticMethods
with Unapplies
diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
index eeb76dced2..704aebc50b 100644
--- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
@@ -38,7 +38,7 @@ import scala.language.postfixOps
*
* @todo Check whether we always check type parameter bounds.
*/
-abstract class RefChecks extends InfoTransform with scala.reflect.internal.transform.RefChecks with Variances {
+abstract class RefChecks extends InfoTransform with scala.reflect.internal.transform.RefChecks {
val global: Global // need to repeat here because otherwise last mixin defines global as
// SymbolTable. If we had DOT this would not be an issue
@@ -844,7 +844,16 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
// Variance Checking --------------------------------------------------------
- val varianceValidator = new VarianceValidator
+ object varianceValidator extends VarianceValidator {
+ private def tpString(tp: Type) = tp match {
+ case ClassInfoType(parents, _, clazz) => "supertype "+intersectionType(parents, clazz.owner)
+ case _ => "type "+tp
+ }
+ override def issueVarianceError(base: Symbol, sym: Symbol, required: Variance) {
+ currentRun.currentUnit.error(base.pos,
+ s"${sym.variance} $sym occurs in $required position in ${tpString(base.info)} of $base")
+ }
+ }
// Forward reference checking ---------------------------------------------------
diff --git a/src/compiler/scala/tools/nsc/typechecker/Variances.scala b/src/compiler/scala/tools/nsc/typechecker/Variances.scala
deleted file mode 100644
index 66eb415b10..0000000000
--- a/src/compiler/scala/tools/nsc/typechecker/Variances.scala
+++ /dev/null
@@ -1,197 +0,0 @@
-/* NSC -- new scala compiler
- * Copyright 2005-2013 LAMP/EPFL
- * @author Martin Odersky
- */
-
-package scala.tools.nsc
-package typechecker
-
-import scala.reflect.internal.Variance, scala.reflect.internal.Variance._
-import scala.collection.{ mutable, immutable }
-
-/** See comments at scala.reflect.internal.Variance.
- */
-trait Variances {
- val global: Global
- import global._
- import definitions.uncheckedVarianceClass
-
- class VarianceValidator extends Traverser {
- val escapedPrivateLocals = mutable.HashSet[Symbol]()
-
- /** 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
-
- /** 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): Variance = {
- val clazz = tvar.owner
- var sym = base
- var state: Variance = Covariant
- while (sym != clazz && !state.isBivariant) {
- //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.isParameter && !sym.owner.isConstructor && !sym.owner.isCaseApplyOrUnapply &&
- !(tvar.isTypeParameterOrSkolem && sym.isTypeParameterOrSkolem &&
- tvar.owner == sym.owner)) state = state.flip
- else if (!sym.owner.isClass ||
- sym.isTerm && ((sym.isPrivateLocal || sym.isProtectedLocal || sym.isSuperAccessor /* super accessors are implicitly local #4345*/) && !(escapedPrivateLocals contains sym))) {
- // return Bivariant if `sym` is local to a term
- // or is private[this] or protected[this]
- state = Bivariant
- }
- else if (sym.isAliasType) {
- // return Bivariant 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 Invariant, as there might then be
- // references to the type parameter that are not variance checked.
- state = if (sym.isOverridingSymbol) Invariant else Bivariant
- }
- 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: Variance): Unit = tp match {
- case ErrorType =>
- case WildcardType =>
- case BoundedWildcardType(bounds) =>
- validateVariance(bounds, variance)
- case NoType =>
- case NoPrefix =>
- case ThisType(_) =>
- case ConstantType(_) =>
- case SingleType(pre, sym) =>
- validateVariance(pre, variance)
- case TypeRef(pre, sym, args) =>
-// println("validate "+sym+" at "+relativeVariance(sym))
- if (sym.isAliasType/* && relativeVariance(sym) == Bivariant*/)
- validateVariance(tp.normalize, variance)
- else if (!sym.variance.isInvariant) {
- val v = relativeVariance(sym)
-
- if (!v.isBivariant && sym.variance != v * variance) {
- //Console.println("relativeVariance(" + base + "," + sym + ") = " + v);//DEBUG
- def tpString(tp: Type) = tp match {
- case ClassInfoType(parents, _, clazz) => "supertype "+intersectionType(parents, clazz.owner)
- case _ => "type "+tp
- }
- currentRun.currentUnit.error(base.pos,
- sym.variance + " " + sym +
- " occurs in " + (v * variance) +
- " position in " + tpString(base.info) + " of " + base);
- }
- }
- validateVariance(pre, variance)
- // @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
- if (args.nonEmpty)
- validateVarianceArgs(args, variance, sym.typeParams)
- case ClassInfoType(parents, decls, symbol) =>
- validateVariances(parents, variance)
- case RefinedType(parents, decls) =>
- validateVariances(parents, variance)
- val saved = inRefinement
- inRefinement = true
- for (sym <- decls)
- validateVariance(sym.info, if (sym.isAliasType) Invariant else variance)
- inRefinement = saved
- case TypeBounds(lo, hi) =>
- validateVariance(lo, variance.flip)
- validateVariance(hi, variance)
- case mt @ MethodType(formals, result) =>
- if (inRefinement)
- validateVariances(mt.paramTypes, variance.flip)
- validateVariance(result, variance)
- case NullaryMethodType(result) =>
- validateVariance(result, variance)
- case PolyType(tparams, result) =>
- // type parameters will be validated separately, because they are defined explicitly.
- validateVariance(result, variance)
- case ExistentialType(tparams, result) =>
- validateVariances(tparams map (_.info), variance)
- validateVariance(result, variance)
- case AnnotatedType(annots, tp, selfsym) =>
- if (!annots.exists(_ matches uncheckedVarianceClass))
- validateVariance(tp, variance)
- }
-
- def validateVariances(tps: List[Type], variance: Variance) {
- tps foreach (tp => validateVariance(tp, variance))
- }
-
- def validateVarianceArgs(tps: List[Type], variance: Variance, tparams: List[Symbol]) {
- foreach2(tps, tparams)((tp, tparam) => validateVariance(tp, variance * tparam.variance))
- }
-
- validateVariance(base.info, Covariant)
- }
-
- override def traverse(tree: Tree) {
- tree match {
- case ClassDef(_, _, _, _) | TypeDef(_, _, _, _) =>
- validateVariance(tree.symbol)
- super.traverse(tree)
- // ModuleDefs need not be considered because they have been eliminated already
- case ValDef(_, _, _, _) =>
- if (!tree.symbol.hasLocalFlag)
- validateVariance(tree.symbol)
- case DefDef(_, _, tparams, vparamss, _, _) =>
- // No variance check for object-private/protected methods/values.
- if (!tree.symbol.hasLocalFlag) {
- validateVariance(tree.symbol)
- traverseTrees(tparams)
- traverseTreess(vparamss)
- }
- case Template(_, _, _) =>
- super.traverse(tree)
- case _ =>
- }
- }
- }
-
- /** Compute variance of type parameter `tparam` in all types `tps`. */
- def varianceInTypes(tps: List[Type])(tparam: Symbol): Variance =
- fold(tps map (tp => varianceInType(tp)(tparam)))
-
- /** Compute variance of type parameter `tparam` in type `tp`. */
- def varianceInType(tp: Type)(tparam: Symbol): Variance = {
- def inArgs(sym: Symbol, args: List[Type]): Variance = fold(map2(args, sym.typeParams)((a, p) => inType(a) * p.variance))
- def inSyms(syms: List[Symbol]): Variance = fold(syms map inSym)
- def inTypes(tps: List[Type]): Variance = fold(tps map inType)
-
- def inSym(sym: Symbol): Variance = if (sym.isAliasType) inType(sym.info).cut else inType(sym.info)
- def inType(tp: Type): Variance = tp match {
- case ErrorType | WildcardType | NoType | NoPrefix => Bivariant
- case ThisType(_) | ConstantType(_) => Bivariant
- case TypeRef(_, `tparam`, _) => Covariant
- case BoundedWildcardType(bounds) => inType(bounds)
- case NullaryMethodType(restpe) => inType(restpe)
- case SingleType(pre, sym) => inType(pre)
- case TypeRef(pre, _, _) if tp.isHigherKinded => inType(pre) // a type constructor cannot occur in tp's args
- case TypeRef(pre, sym, args) => inType(pre) & inArgs(sym, args)
- case TypeBounds(lo, hi) => inType(lo).flip & inType(hi)
- case RefinedType(parents, defs) => inTypes(parents) & inSyms(defs.toList)
- case MethodType(params, restpe) => inSyms(params).flip & inType(restpe)
- case PolyType(tparams, restpe) => inSyms(tparams).flip & inType(restpe)
- case ExistentialType(tparams, restpe) => inSyms(tparams) & inType(restpe)
- case AnnotatedType(annots, tp, _) => inTypes(annots map (_.atp)) & inType(tp)
- }
-
- inType(tp)
- }
-}