summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2013-01-01 16:27:48 -0800
committerPaul Phillips <paulp@improving.org>2013-01-09 12:11:13 -0800
commit069359240a902cc989553123a61db3f6abe8fd1a (patch)
tree905f66556212ff1a259c9d3f15c37af83ad4aff5
parent882f8e640b034cc69b122ac221f75cbe0018e2c3 (diff)
downloadscala-069359240a902cc989553123a61db3f6abe8fd1a.tar.gz
scala-069359240a902cc989553123a61db3f6abe8fd1a.tar.bz2
scala-069359240a902cc989553123a61db3f6abe8fd1a.zip
Move escaping local logic into VarianceValidator.
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/RefChecks.scala16
-rw-r--r--src/reflect/scala/reflect/internal/Variances.scala18
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