summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2013-10-12 10:46:21 -0700
committerPaul Phillips <paulp@improving.org>2013-10-12 10:46:21 -0700
commitcd966a1b33001988beca92e96181f6d49043babb (patch)
treee796b3b640ac7db034213fda9e5ae847e0f7dfe8
parent810ce7e2790e4da4e3f1d9473ccad5a721847096 (diff)
parent3e6b82c59c75e7ea925a015e33aaac95f7a56b60 (diff)
downloadscala-cd966a1b33001988beca92e96181f6d49043babb.tar.gz
scala-cd966a1b33001988beca92e96181f6d49043babb.tar.bz2
scala-cd966a1b33001988beca92e96181f6d49043babb.zip
Merge pull request #3021 from paulp/pr/is-he-stable-or-is-he-volatile
Extract isStable and isVolatile from Type.
-rw-r--r--src/reflect/scala/reflect/internal/Definitions.scala75
-rw-r--r--src/reflect/scala/reflect/internal/Types.scala85
-rw-r--r--src/reflect/scala/reflect/internal/tpe/TypeComparers.scala2
3 files changed, 85 insertions, 77 deletions
diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala
index 7b2e40b59c..4d8ae73bcc 100644
--- a/src/reflect/scala/reflect/internal/Definitions.scala
+++ b/src/reflect/scala/reflect/internal/Definitions.scala
@@ -709,7 +709,82 @@ trait Definitions extends api.StandardDefinitions {
case NullaryMethodType(restpe) => finalResultType(restpe)
case _ => tp
}
+ /** Similarly, putting all the isStable logic in one place.
+ * This makes it like 1000x easier to see the overall logic
+ * of the method.
+ */
+ def isStable(tp: Type): Boolean = tp match {
+ case _: SingletonType => true
+ case NoPrefix => true
+ case TypeRef(_, NothingClass | SingletonClass, _) => true
+ case TypeRef(_, sym, _) if sym.isAbstractType => tp.bounds.hi.typeSymbol isSubClass SingletonClass
+ case TypeRef(pre, sym, _) if sym.isModuleClass => isStable(pre)
+ case TypeRef(_, _, _) if tp ne tp.dealias => isStable(tp.dealias)
+ case TypeVar(origin, _) => isStable(origin)
+ case AnnotatedType(_, atp, _) => isStable(atp) // Really?
+ case _: SimpleTypeProxy => isStable(tp.underlying)
+ case _ => false
+ }
+ def isVolatile(tp: Type): Boolean = {
+ // need to be careful not to fall into an infinite recursion here
+ // because volatile checking is done before all cycles are detected.
+ // the case to avoid is an abstract type directly or
+ // indirectly upper-bounded by itself. See #2918
+ def isVolatileAbstractType: Boolean = {
+ def sym = tp.typeSymbol
+ def volatileUpperBound = isVolatile(tp.bounds.hi)
+ def safeIsVolatile = (
+ if (volatileRecursions < TypeConstants.LogVolatileThreshold)
+ volatileUpperBound
+ // we can return true when pendingVolatiles contains sym, because
+ // a cycle will be detected afterwards and an error will result anyway.
+ else pendingVolatiles(sym) || {
+ pendingVolatiles += sym
+ try volatileUpperBound finally pendingVolatiles -= sym
+ }
+ )
+ volatileRecursions += 1
+ try safeIsVolatile finally volatileRecursions -= 1
+ }
+ /** A refined type P1 with ... with Pn { decls } is volatile if
+ * one of the parent types Pi is an abstract type, and
+ * either i > 1, or decls or a following parent Pj, j > 1, contributes
+ * an abstract member.
+ * A type contributes an abstract member if it has an abstract member which
+ * is also a member of the whole refined type. A scope `decls` contributes
+ * an abstract member if it has an abstract definition which is also
+ * a member of the whole type.
+ */
+ def isVolatileRefinedType: Boolean = {
+ val RefinedType(parents, decls) = tp
+ def isVisibleDeferred(m: Symbol) = m.isDeferred && ((tp nonPrivateMember m.name).alternatives contains m)
+ def contributesAbstractMembers(p: Type) = p.deferredMembers exists isVisibleDeferred
+ def dropConcreteParents = parents dropWhile (p => !p.typeSymbol.isAbstractType)
+
+ (parents exists isVolatile) || {
+ dropConcreteParents match {
+ case Nil => false
+ case ps => (ps ne parents) || (ps.tail exists contributesAbstractMembers) || (decls exists isVisibleDeferred)
+ }
+ }
+ }
+
+ tp match {
+ case ThisType(_) => false
+ case SingleType(_, sym) => isVolatile(tp.underlying) && (sym.hasVolatileType || !sym.isStable)
+ case NullaryMethodType(restpe) => isVolatile(restpe)
+ case PolyType(_, restpe) => isVolatile(restpe)
+ case TypeRef(_, _, _) if tp ne tp.dealias => isVolatile(tp.dealias)
+ case TypeRef(_, sym, _) if sym.isAbstractType => isVolatileAbstractType
+ case RefinedType(_, _) => isVolatileRefinedType
+ case TypeVar(origin, _) => isVolatile(origin)
+ case _: SimpleTypeProxy => isVolatile(tp.underlying)
+ case _ => false
+ }
+ }
+ private[this] var volatileRecursions: Int = 0
+ private[this] val pendingVolatiles = mutable.HashSet[Symbol]()
def abstractFunctionForFunctionType(tp: Type) = {
assert(isFunctionType(tp), tp)
abstractFunctionType(tp.typeArgs.init, tp.typeArgs.last)
diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala
index 4367e51041..85dfa037ec 100644
--- a/src/reflect/scala/reflect/internal/Types.scala
+++ b/src/reflect/scala/reflect/internal/Types.scala
@@ -18,6 +18,7 @@ import util.Statistics
import util.ThreeValues._
import Variance._
import Depth._
+import TypeConstants._
/* A standard type pattern match:
case ErrorType =>
@@ -90,10 +91,6 @@ trait Types
private var explainSwitch = false
private final val emptySymbolSet = immutable.Set.empty[Symbol]
- protected[internal] final val DefaultLogThreshhold = 50
- private final val LogPendingBaseTypesThreshold = DefaultLogThreshhold
- private final val LogVolatileThreshold = DefaultLogThreshhold
-
private final val traceTypeVars = sys.props contains "scalac.debug.tvar"
private final val breakCycles = settings.breakCycles.value
/** In case anyone wants to turn off type parameter bounds being used
@@ -142,8 +139,6 @@ trait Types
override def typeConstructor: Type = underlying.typeConstructor
override def isError = underlying.isError
override def isErroneous = underlying.isErroneous
- override def isStable: Boolean = underlying.isStable
- override def isVolatile = underlying.isVolatile
override def paramSectionCount = underlying.paramSectionCount
override def paramss = underlying.paramss
override def params = underlying.params
@@ -270,7 +265,7 @@ trait Types
def takesTypeArgs: Boolean = this.isHigherKinded
/** Does this type denote a stable reference (i.e. singleton type)? */
- def isStable: Boolean = false
+ final def isStable: Boolean = definitions isStable this
/** Is this type dangerous (i.e. it might contain conflicting
* type information when empty, so that it can be constructed
@@ -278,7 +273,7 @@ trait Types
* type of the form T_1 with T_n { decls }, where one of the
* T_i (i > 1) is an abstract type.
*/
- def isVolatile: Boolean = false
+ final def isVolatile: Boolean = definitions isVolatile this
/** Is this type a structural refinement type (it ''refines'' members that have not been inherited) */
def isStructuralRefinement: Boolean = false
@@ -1221,8 +1216,6 @@ trait Types
abstract class SingletonType extends SubType with SimpleTypeProxy {
def supertype = underlying
override def isTrivial = false
- override def isStable = true
- override def isVolatile = underlying.isVolatile
override def widen: Type = underlying.widen
override def baseTypeSeq: BaseTypeSeq = {
if (Statistics.canEnable) Statistics.incCounter(singletonBaseTypeSeqCount)
@@ -1300,7 +1293,6 @@ trait Types
/** An object representing a non-existing prefix */
case object NoPrefix extends Type {
override def isTrivial: Boolean = true
- override def isStable: Boolean = true
override def prefixString = ""
override def safeToString: String = "<noprefix>"
override def kind = "NoPrefixType"
@@ -1318,7 +1310,6 @@ trait Types
override def isTrivial: Boolean = sym.isPackageClass
override def typeSymbol = sym
override def underlying: Type = sym.typeOfThis
- override def isVolatile = false
override def isHigherKinded = sym.isRefinementClass && underlying.isHigherKinded
override def prefixString =
if (settings.debug) sym.nameString + ".this."
@@ -1367,8 +1358,6 @@ trait Types
// more precise conceptually, but causes cyclic errors: (paramss exists (_ contains sym))
override def isImmediatelyDependent = (sym ne NoSymbol) && (sym.owner.isMethod && sym.isValueParameter)
-
- override def isVolatile : Boolean = underlying.isVolatile && (sym.hasVolatileType || !sym.isStable)
/*
override def narrow: Type = {
if (phase.erasedTypes) this
@@ -1764,33 +1753,6 @@ trait Types
typeSymbol))
} else super.normalize
}
-
- /** A refined type P1 with ... with Pn { decls } is volatile if
- * one of the parent types Pi is an abstract type, and
- * either i > 1, or decls or a following parent Pj, j > 1, contributes
- * an abstract member.
- * A type contributes an abstract member if it has an abstract member which
- * is also a member of the whole refined type. A scope `decls` contributes
- * an abstract member if it has an abstract definition which is also
- * a member of the whole type.
- */
- override def isVolatile = {
- def isVisible(m: Symbol) =
- this.nonPrivateMember(m.name).alternatives contains m
- def contributesAbstractMembers(p: Type) =
- p.deferredMembers exists isVisible
-
- ((parents exists (_.isVolatile))
- ||
- (parents dropWhile (! _.typeSymbol.isAbstractType) match {
- case ps @ (_ :: ps1) =>
- (ps ne parents) ||
- (ps1 exists contributesAbstractMembers) ||
- (decls.iterator exists (m => m.isDeferred && isVisible(m)))
- case _ =>
- false
- }))
- }
override def kind = "RefinedType"
}
@@ -2026,7 +1988,6 @@ trait Types
class ModuleTypeRef(pre0: Type, sym0: Symbol) extends NoArgsTypeRef(pre0, sym0) with ClassTypeRef {
require(sym.isModuleClass, sym)
private[this] var narrowedCache: Type = _
- override def isStable = pre.isStable
override def narrow = {
if (narrowedCache eq null)
narrowedCache = singleType(pre, sym.sourceModule)
@@ -2041,7 +2002,6 @@ trait Types
}
class PackageTypeRef(pre0: Type, sym0: Symbol) extends ModuleTypeRef(pre0, sym0) {
require(sym.isPackageClass, sym)
- override def isStable = true
override protected def finishPrefix(rest: String) = packagePrefix + rest
}
class RefinementTypeRef(pre0: Type, sym0: Symbol) extends NoArgsTypeRef(pre0, sym0) with ClassTypeRef {
@@ -2148,8 +2108,6 @@ trait Types
require(sym.isAliasType, sym)
override def dealias = if (typeParamsMatchArgs) betaReduce.dealias else super.dealias
- override def isStable = normalize.isStable
- override def isVolatile = normalize.isVolatile
override def narrow = normalize.narrow
override def thisInfo = normalize
override def prefix = if (this ne normalize) normalize.prefix else pre
@@ -2204,30 +2162,6 @@ trait Types
private var symInfoCache: Type = _
private var thisInfoCache: Type = _
- override def isVolatile = {
- // need to be careful not to fall into an infinite recursion here
- // because volatile checking is done before all cycles are detected.
- // the case to avoid is an abstract type directly or
- // indirectly upper-bounded by itself. See #2918
- try {
- volatileRecursions += 1
- if (volatileRecursions < LogVolatileThreshold)
- bounds.hi.isVolatile
- else if (pendingVolatiles(sym))
- true // we can return true here, because a cycle will be detected
- // here afterwards and an error will result anyway.
- else
- try {
- pendingVolatiles += sym
- bounds.hi.isVolatile
- } finally {
- pendingVolatiles -= sym
- }
- } finally {
- volatileRecursions -= 1
- }
- }
-
override def thisInfo = {
val symInfo = sym.info
if (thisInfoCache == null || (symInfo ne symInfoCache)) {
@@ -2242,7 +2176,6 @@ trait Types
}
thisInfoCache
}
- override def isStable = bounds.hi.typeSymbol isSubClass SingletonClass
override def bounds = thisInfo.bounds
override protected[Types] def baseTypeSeqImpl: BaseTypeSeq = transform(bounds.hi).baseTypeSeq prepend this
override def kind = "AbstractTypeRef"
@@ -2328,7 +2261,6 @@ trait Types
override def baseClasses = thisInfo.baseClasses
override def baseTypeSeqDepth = baseTypeSeq.maxDepth
- override def isStable = (sym eq NothingClass) || (sym eq SingletonClass)
override def prefix = pre
override def termSymbol = super.termSymbol
override def termSymbolDirect = super.termSymbol
@@ -2595,7 +2527,6 @@ trait Types
override def baseClasses: List[Symbol] = resultType.baseClasses
override def baseType(clazz: Symbol): Type = resultType.baseType(clazz)
override def boundSyms = resultType.boundSyms
- override def isVolatile = resultType.isVolatile
override def safeToString: String = "=> "+ resultType
override def kind = "NullaryMethodType"
}
@@ -2634,7 +2565,6 @@ trait Types
override def baseClasses: List[Symbol] = resultType.baseClasses
override def baseType(clazz: Symbol): Type = resultType.baseType(clazz)
override def narrow: Type = resultType.narrow
- override def isVolatile = resultType.isVolatile
/** @M: typeDefSig wraps a TypeBounds in a PolyType
* to represent a higher-kinded type parameter
@@ -2679,7 +2609,6 @@ trait Types
override protected def rewrap(newtp: Type) = existentialAbstraction(quantified, newtp)
override def isTrivial = false
- override def isStable: Boolean = false
override def bounds = TypeBounds(maybeRewrap(underlying.bounds.lo), maybeRewrap(underlying.bounds.hi))
override def parents = underlying.parents map maybeRewrap
override def boundSyms = quantified.toSet
@@ -3239,8 +3168,6 @@ trait Types
else super.normalize
)
override def typeSymbol = origin.typeSymbol
- override def isStable = origin.isStable
- override def isVolatile = origin.isVolatile
private def tparamsOfSym(sym: Symbol) = sym.info match {
case PolyType(tparams, _) if tparams.nonEmpty =>
@@ -4651,6 +4578,12 @@ trait Types
}
+object TypeConstants {
+ final val DefaultLogThreshhold = 50
+ final val LogPendingBaseTypesThreshold = DefaultLogThreshhold
+ final val LogVolatileThreshold = DefaultLogThreshhold
+}
+
object TypesStats {
import BaseTypeSeqsStats._
val rawTypeCount = Statistics.newCounter ("#raw type creations")
diff --git a/src/reflect/scala/reflect/internal/tpe/TypeComparers.scala b/src/reflect/scala/reflect/internal/tpe/TypeComparers.scala
index 152c689c56..6532bce9f0 100644
--- a/src/reflect/scala/reflect/internal/tpe/TypeComparers.scala
+++ b/src/reflect/scala/reflect/internal/tpe/TypeComparers.scala
@@ -12,7 +12,7 @@ trait TypeComparers {
import definitions._
import TypesStats._
- private final val LogPendingSubTypesThreshold = DefaultLogThreshhold
+ private final val LogPendingSubTypesThreshold = TypeConstants.DefaultLogThreshhold
private val pendingSubTypes = new mutable.HashSet[SubTypePair]