From 069359240a902cc989553123a61db3f6abe8fd1a Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Tue, 1 Jan 2013 16:27:48 -0800 Subject: Move escaping local logic into VarianceValidator. --- .../scala/tools/nsc/typechecker/RefChecks.scala | 16 ++++------------ src/reflect/scala/reflect/internal/Variances.scala | 18 +++++++++++++++--- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 750a4f65ec..8a34d58e6e 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -1449,18 +1449,10 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans checkMigration(sym, tree.pos) checkCompileTimeOnly(sym, tree.pos) - if (sym eq NoSymbol) { - unit.warning(tree.pos, "Select node has NoSymbol! " + tree + " / " + tree.tpe) - } - else if (currentClass != sym.owner && sym.hasLocalFlag) { - 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) varianceValidator.escapedLocals += sym - } + if (sym eq NoSymbol) + devWarning("Select node has NoSymbol! " + tree + " / " + tree.tpe) + else if (sym.hasLocalFlag) + varianceValidator.checkForEscape(sym, currentClass) def checkSuper(mix: Name) = // term should have been eliminated by super accessors diff --git a/src/reflect/scala/reflect/internal/Variances.scala b/src/reflect/scala/reflect/internal/Variances.scala index a54420dd94..779d1ac0fe 100644 --- a/src/reflect/scala/reflect/internal/Variances.scala +++ b/src/reflect/scala/reflect/internal/Variances.scala @@ -8,6 +8,7 @@ package internal import Variance._ import scala.collection.{ mutable, immutable } +import scala.annotation.tailrec /** See comments at scala.reflect.internal.Variance. */ @@ -18,14 +19,25 @@ trait Variances { * TODO - eliminate duplication with varianceInType */ class VarianceValidator extends Traverser { - val escapedLocals = mutable.HashSet[Symbol]() + private val escapedLocals = mutable.HashSet[Symbol]() + + /** Is every symbol in the owner chain between `site` and the owner of `sym` + * either a term symbol or private[this]? If not, add `sym` to the set of + * esacped locals. + * @pre sym.hasLocalFlag + */ + @tailrec final def checkForEscape(sym: Symbol, site: Symbol) { + if (site == sym.owner || site == sym.owner.moduleClass || site.isPackage) () // done + else if (site.isTerm || site.isPrivateLocal) checkForEscape(sym, site.owner) // ok - recurse to owner + else escapedLocals += sym + } protected def issueVarianceError(base: Symbol, sym: Symbol, required: Variance): Unit = () // 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. - private def isFlipped(sym: Symbol, tvar: Symbol) = ( + def shouldFlip(sym: Symbol, tvar: Symbol) = ( sym.isParameter && !sym.owner.isConstructor && !sym.owner.isCaseApplyOrUnapply @@ -56,7 +68,7 @@ trait Variances { */ def relativeVariance(tvar: Symbol): Variance = { def nextVariance(sym: Symbol, v: Variance): Variance = ( - if (isFlipped(sym, tvar)) v.flip + if (shouldFlip(sym, tvar)) v.flip else if (isLocalOnly(sym)) Bivariant else if (!sym.isAliasType) v else if (sym.isOverridingSymbol) Invariant -- cgit v1.2.3