summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2013-08-25 09:13:44 -0700
committerPaul Phillips <paulp@improving.org>2013-08-25 09:57:28 -0700
commit4412a92d3609d23f7369fc67bf5a67ddedf3511e (patch)
treef90b215c02df3a193940a00c94cfd8947122f637
parent9e81f0016bc3510482540379dc4e05140b513cee (diff)
downloadscala-4412a92d3609d23f7369fc67bf5a67ddedf3511e.tar.gz
scala-4412a92d3609d23f7369fc67bf5a67ddedf3511e.tar.bz2
scala-4412a92d3609d23f7369fc67bf5a67ddedf3511e.zip
Value class Depth.
It's the obvious translation from a raw Int into a value class. It wasn't that long ago one could find a signature like this: def merge(tps: List[Type], variance: Int, depth: Int): Type Do you feel lucky, method caller? Well, do ya? Anyway, now it is: def merge(tps: List[Type], variance: Variance, depth: Depth): Type Forget for a moment the fact that you'd probably rather not pass variance for depth and depth for variance and look at the type signatures: (List[Type], Variance, Depth) => Type (List[Type], Int, Int) => Type
-rw-r--r--src/compiler/scala/reflect/macros/compiler/Validators.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Implicits.scala3
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Infer.scala51
-rw-r--r--src/reflect/scala/reflect/internal/BaseTypeSeqs.scala8
-rw-r--r--src/reflect/scala/reflect/internal/Depth.scala28
-rw-r--r--src/reflect/scala/reflect/internal/Types.scala136
-rw-r--r--src/reflect/scala/reflect/internal/tpe/GlbLubs.scala50
-rw-r--r--src/reflect/scala/reflect/internal/tpe/TypeComparers.scala10
-rw-r--r--src/reflect/scala/reflect/internal/tpe/TypeConstraints.scala34
-rw-r--r--src/reflect/scala/reflect/internal/util/package.scala2
-rw-r--r--src/reflect/scala/reflect/runtime/SynchronizedTypes.scala3
11 files changed, 166 insertions, 161 deletions
diff --git a/src/compiler/scala/reflect/macros/compiler/Validators.scala b/src/compiler/scala/reflect/macros/compiler/Validators.scala
index af17fd87c0..8d396a56d8 100644
--- a/src/compiler/scala/reflect/macros/compiler/Validators.scala
+++ b/src/compiler/scala/reflect/macros/compiler/Validators.scala
@@ -57,7 +57,7 @@ trait Validators {
checkMacroImplResultTypeMismatch(atpeToRtpe(aret), rret)
val maxLubDepth = lubDepth(aparamss.flatten map (_.tpe)) max lubDepth(rparamss.flatten map (_.tpe))
- val atargs = solvedTypes(atvars, atparams, atparams map varianceInType(aret), upper = false, depth = maxLubDepth)
+ val atargs = solvedTypes(atvars, atparams, atparams map varianceInType(aret), upper = false, maxLubDepth)
val boundsOk = typer.silent(_.infer.checkBounds(macroDdef, NoPrefix, NoSymbol, atparams, atargs, ""))
boundsOk match {
case SilentResultValue(true) => // do nothing, success
diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
index 4265efc839..3a6b25f1cd 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
@@ -644,8 +644,7 @@ trait Implicits {
if (tvars.nonEmpty)
typingLog("solve", ptLine("tvars" -> tvars, "tvars.constr" -> tvars.map(_.constr)))
- val targs = solvedTypes(tvars, undetParams, undetParams map varianceInType(pt),
- upper = false, lubDepth(List(itree2.tpe, pt)))
+ val targs = solvedTypes(tvars, undetParams, undetParams map varianceInType(pt), upper = false, lubDepth(itree2.tpe :: pt :: Nil))
// #2421: check that we correctly instantiated type parameters outside of the implicit tree:
checkBounds(itree2, NoPrefix, NoSymbol, undetParams, targs, "inferred ")
diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
index 50d88d7c4d..fa85d7a2fb 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
@@ -9,6 +9,7 @@ package typechecker
import scala.collection.{ mutable, immutable }
import scala.util.control.ControlThrowable
import symtab.Flags._
+import scala.reflect.internal.Depth
/** This trait contains methods related to type parameter inference.
*
@@ -21,6 +22,7 @@ trait Infer extends Checkable {
import global._
import definitions._
import typeDebug.ptBlock
+ import typeDebug.str.parentheses
import typingStack.{ printTyping }
/** The formal parameter types corresponding to `formals`.
@@ -132,34 +134,17 @@ trait Infer extends Checkable {
* @param upper When `true` search for max solution else min.
* @throws NoInstance
*/
- def solvedTypes(tvars: List[TypeVar], tparams: List[Symbol],
- variances: List[Variance], upper: Boolean, depth: Int): List[Type] = {
-
- if (tvars.nonEmpty) {
- def tp_s = (tparams, tvars).zipped map { case (tp, tv) => s"${tp.name}/$tv" } mkString ","
- printTyping(s"solving for $tp_s")
- }
-
- if (!solve(tvars, tparams, variances, upper, depth)) {
- // no panic, it's good enough to just guess a solution, we'll find out
- // later whether it works. *ZAP* @M danger, Will Robinson! this means
- // that you should never trust inferred type arguments!
- //
- // Need to call checkBounds on the args/typars or type1 on the tree
- // for the expression that results from type inference see e.g., #2421:
- // implicit search had been ignoring this caveat
- // throw new DeferredNoInstance(() =>
- // "no solution exists for constraints"+(tvars map boundsString))
+ def solvedTypes(tvars: List[TypeVar], tparams: List[Symbol], variances: List[Variance], upper: Boolean, depth: Depth): List[Type] = {
+ if (tvars.isEmpty) Nil else {
+ printTyping("solving for " + parentheses((tparams, tvars).zipped map ((p, tv) => s"${p.name}: $tv")))
+ // !!! What should be done with the return value of "solve", which is at present ignored?
+ // The historical commentary says "no panic, it's good enough to just guess a solution,
+ // we'll find out later whether it works", meaning don't issue an error here when types
+ // don't conform to bounds. That means you can never trust the results of implicit search.
+ // For an example where this was not being heeded, SI-2421.
+ solve(tvars, tparams, variances, upper, depth)
+ tvars map instantiate
}
- for (tvar <- tvars ; if tvar.constr.inst == tvar) {
- if (tvar.origin.typeSymbol.info eq ErrorType)
- // this can happen if during solving a cyclic type parameter
- // such as T <: T gets completed. See #360
- tvar.constr.inst = ErrorType
- else
- abort(tvar.origin+" at "+tvar.origin.typeSymbol.owner)
- }
- tvars map instantiate
}
def skipImplicit(tp: Type) = tp match {
@@ -554,10 +539,7 @@ trait Infer extends Checkable {
"argument expression's type is not compatible with formal parameter type" + foundReqMsg(tp1, pt1))
}
}
- val targs = solvedTypes(
- tvars, tparams, tparams map varianceInTypes(formals),
- upper = false, lubDepth(formals) max lubDepth(argtpes)
- )
+ val targs = solvedTypes(tvars, tparams, tparams map varianceInTypes(formals), upper = false, lubDepth(formals) max lubDepth(argtpes))
// Can warn about inferring Any/AnyVal as long as they don't appear
// explicitly anywhere amongst the formal, argument, result, or expected type.
def canWarnAboutAny = !(pt :: restpe :: formals ::: argtpes exists (t => (t contains AnyClass) || (t contains AnyValClass)))
@@ -1030,7 +1012,10 @@ trait Infer extends Checkable {
val variances =
if (ctorTp.paramTypes.isEmpty) undetparams map varianceInType(ctorTp)
else undetparams map varianceInTypes(ctorTp.paramTypes)
- val targs = solvedTypes(tvars, undetparams, variances, upper = true, lubDepth(List(resTp, pt)))
+
+ // Note: this is the only place where solvedTypes (or, indirectly, solve) is called
+ // with upper = true.
+ val targs = solvedTypes(tvars, undetparams, variances, upper = true, lubDepth(resTp :: pt :: Nil))
// checkBounds(tree, NoPrefix, NoSymbol, undetparams, targs, "inferred ")
// no checkBounds here. If we enable it, test bug602 fails.
// TODO: reinstate checkBounds, return params that fail to meet their bounds to undetparams
@@ -1099,7 +1084,7 @@ trait Infer extends Checkable {
val tvars1 = tvars map (_.cloneInternal)
// Note: right now it's not clear that solving is complete, or how it can be made complete!
// So we should come back to this and investigate.
- solve(tvars1, tvars1 map (_.origin.typeSymbol), tvars1 map (_ => Variance.Covariant), upper = false)
+ solve(tvars1, tvars1 map (_.origin.typeSymbol), tvars1 map (_ => Variance.Covariant), upper = false, Depth.AnyDepth)
}
// this is quite nasty: it destructively changes the info of the syms of e.g., method type params
diff --git a/src/reflect/scala/reflect/internal/BaseTypeSeqs.scala b/src/reflect/scala/reflect/internal/BaseTypeSeqs.scala
index e3498a95a6..05aaa462c4 100644
--- a/src/reflect/scala/reflect/internal/BaseTypeSeqs.scala
+++ b/src/reflect/scala/reflect/internal/BaseTypeSeqs.scala
@@ -130,9 +130,9 @@ trait BaseTypeSeqs {
lazy val maxDepth = maxDepthOfElems
- protected def maxDepthOfElems: Int = {
- var d = 0
- for (i <- 1 until length) d = max(d, typeDepth(elems(i)))
+ protected def maxDepthOfElems: Depth = {
+ var d = Depth.Zero
+ 1 until length foreach (i => d = d max typeDepth(elems(i)))
d
}
@@ -234,7 +234,7 @@ trait BaseTypeSeqs {
override def map(g: Type => Type) = lateMap(g)
override def lateMap(g: Type => Type) = orig.lateMap(x => g(f(x)))
override def exists(p: Type => Boolean) = elems exists (x => p(f(x)))
- override protected def maxDepthOfElems: Int = elems.map(x => typeDepth(f(x))).max
+ override protected def maxDepthOfElems: Depth = elems.map(x => typeDepth(f(x))).max
override def toString = elems.mkString("MBTS(", ",", ")")
}
diff --git a/src/reflect/scala/reflect/internal/Depth.scala b/src/reflect/scala/reflect/internal/Depth.scala
new file mode 100644
index 0000000000..357abf765f
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/Depth.scala
@@ -0,0 +1,28 @@
+package scala
+package reflect
+package internal
+
+import Depth._
+
+final class Depth private (val depth: Int) extends AnyVal with Ordered[Depth] {
+ def max(that: Depth): Depth = if (this < that) that else this
+ def decr(n: Int): Depth = if (isAnyDepth) this else Depth(depth - n)
+ def incr(n: Int): Depth = if (isAnyDepth) this else Depth(depth + n)
+ def decr: Depth = decr(1)
+ def incr: Depth = incr(1)
+
+ def isNegative = depth < 0
+ def isZero = depth == 0
+ def isAnyDepth = this == AnyDepth
+
+ def compare(that: Depth): Int = if (depth < that.depth) -1 else if (this == that) 0 else 1
+ override def toString = s"Depth($depth)"
+}
+
+object Depth {
+ // A don't care value for the depth parameter in lubs/glbs and related operations.
+ final val AnyDepth = new Depth(Int.MinValue)
+ final val Zero = new Depth(0)
+
+ @inline final def apply(depth: Int): Depth = if (depth < 0) AnyDepth else new Depth(depth)
+}
diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala
index b4ae384594..f96959a728 100644
--- a/src/reflect/scala/reflect/internal/Types.scala
+++ b/src/reflect/scala/reflect/internal/Types.scala
@@ -17,6 +17,7 @@ import scala.annotation.tailrec
import util.Statistics
import util.ThreeValues._
import Variance._
+import Depth._
/* A standard type pattern match:
case ErrorType =>
@@ -93,12 +94,6 @@ trait Types
private final val LogPendingBaseTypesThreshold = DefaultLogThreshhold
private final val LogVolatileThreshold = DefaultLogThreshhold
- /** A don't care value for the depth parameter in lubs/glbs and related operations. */
- protected[internal] final val AnyDepth = -3
-
- /** Decrement depth unless it is a don't care. */
- protected[internal] final def decr(depth: Int) = if (depth == AnyDepth) AnyDepth else depth - 1
-
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
@@ -784,8 +779,8 @@ trait Types
if (Statistics.canEnable) stat_<:<(that)
else {
(this eq that) ||
- (if (explainSwitch) explain("<:", isSubType, this, that)
- else isSubType(this, that, AnyDepth))
+ (if (explainSwitch) explain("<:", isSubType(_: Type, _: Type), this, that)
+ else isSubType(this, that))
}
}
@@ -817,8 +812,8 @@ trait Types
val start = if (Statistics.canEnable) Statistics.pushTimer(typeOpsStack, subtypeNanos) else null
val result =
(this eq that) ||
- (if (explainSwitch) explain("<:", isSubType, this, that)
- else isSubType(this, that, AnyDepth))
+ (if (explainSwitch) explain("<:", isSubType(_: Type, _: Type), this, that)
+ else isSubType(this, that))
if (Statistics.canEnable) Statistics.popTimer(typeOpsStack, start)
result
}
@@ -883,7 +878,7 @@ trait Types
/** The maximum depth (@see typeDepth)
* of each type in the BaseTypeSeq of this type except the first.
*/
- def baseTypeSeqDepth: Int = 1
+ def baseTypeSeqDepth: Depth = Depth(1)
/** The list of all baseclasses of this type (including its own typeSymbol)
* in linearization order, starting with the class itself and ending
@@ -1220,7 +1215,7 @@ trait Types
override def decls: Scope = supertype.decls
override def baseType(clazz: Symbol): Type = supertype.baseType(clazz)
override def baseTypeSeq: BaseTypeSeq = supertype.baseTypeSeq
- override def baseTypeSeqDepth: Int = supertype.baseTypeSeqDepth
+ override def baseTypeSeqDepth: Depth = supertype.baseTypeSeqDepth
override def baseClasses: List[Symbol] = supertype.baseClasses
}
@@ -1514,7 +1509,7 @@ trait Types
}
}
- override def baseTypeSeqDepth: Int = baseTypeSeq.maxDepth
+ override def baseTypeSeqDepth: Depth = baseTypeSeq.maxDepth
override def baseClasses: List[Symbol] = {
val cached = baseClassesCache
@@ -2603,7 +2598,7 @@ trait Types
override def parents: List[Type] = resultType.parents
override def decls: Scope = resultType.decls
override def baseTypeSeq: BaseTypeSeq = resultType.baseTypeSeq
- override def baseTypeSeqDepth: Int = resultType.baseTypeSeqDepth
+ override def baseTypeSeqDepth: Depth = resultType.baseTypeSeqDepth
override def baseClasses: List[Symbol] = resultType.baseClasses
override def baseType(clazz: Symbol): Type = resultType.baseType(clazz)
override def boundSyms = resultType.boundSyms
@@ -2642,7 +2637,7 @@ trait Types
override def boundSyms = immutable.Set[Symbol](typeParams ++ resultType.boundSyms: _*)
override def prefix: Type = resultType.prefix
override def baseTypeSeq: BaseTypeSeq = resultType.baseTypeSeq
- override def baseTypeSeqDepth: Int = resultType.baseTypeSeqDepth
+ override def baseTypeSeqDepth: Depth = resultType.baseTypeSeqDepth
override def baseClasses: List[Symbol] = resultType.baseClasses
override def baseType(clazz: Symbol): Type = resultType.baseType(clazz)
override def narrow: Type = resultType.narrow
@@ -2777,13 +2772,13 @@ trait Types
def withTypeVars(op: Type => Boolean): Boolean = withTypeVars(op, AnyDepth)
- def withTypeVars(op: Type => Boolean, depth: Int): Boolean = {
+ def withTypeVars(op: Type => Boolean, depth: Depth): Boolean = {
val quantifiedFresh = cloneSymbols(quantified)
val tvars = quantifiedFresh map (tparam => TypeVar(tparam))
val underlying1 = underlying.instantiateTypeParams(quantified, tvars) // fuse subst quantified -> quantifiedFresh -> tvars
op(underlying1) && {
solve(tvars, quantifiedFresh, quantifiedFresh map (_ => Invariant), upper = false, depth) &&
- isWithinBounds(NoPrefix, NoSymbol, quantifiedFresh, tvars map (_.constr.inst))
+ isWithinBounds(NoPrefix, NoSymbol, quantifiedFresh, tvars map (_.inst))
}
}
}
@@ -2984,7 +2979,9 @@ trait Types
* or `encounteredHigherLevel` or `suspended` accesses should be necessary.
*/
def instValid = constr.instValid
- override def isGround = instValid && constr.inst.isGround
+ def inst = constr.inst
+ def instWithinBounds = constr.instWithinBounds
+ override def isGround = instValid && inst.isGround
/** The variable's skolemization level */
val level = skolemizationLevel
@@ -3025,8 +3022,7 @@ trait Types
// When comparing to types containing skolems, remember the highest level
// of skolemization. If that highest level is higher than our initial
// skolemizationLevel, we can't re-use those skolems as the solution of this
- // typevar, which means we'll need to repack our constr.inst into a fresh
- // existential.
+ // typevar, which means we'll need to repack our inst into a fresh existential.
// were we compared to skolems at a higher skolemizationLevel?
// EXPERIMENTAL: value will not be considered unless enableTypeVarExperimentals is true
// see SI-5729 for why this is still experimental
@@ -3171,8 +3167,8 @@ trait Types
// AM: I think we could use the `suspended` flag to avoid side-effecting during unification
if (suspended) // constraint accumulation is disabled
checkSubtype(tp, origin)
- else if (constr.instValid) // type var is already set
- checkSubtype(tp, constr.inst)
+ else if (instValid) // type var is already set
+ checkSubtype(tp, inst)
else isRelatable(tp) && {
unifySimple || unifyFull(tp) || (
// only look harder if our gaze is oriented toward Any
@@ -3188,14 +3184,14 @@ trait Types
}
def registerTypeEquality(tp: Type, typeVarLHS: Boolean): Boolean = {
-// println("regTypeEq: "+(safeToString, debugString(tp), tp.getClass, if (typeVarLHS) "in LHS" else "in RHS", if (suspended) "ZZ" else if (constr.instValid) "IV" else "")) //@MDEBUG
+// println("regTypeEq: "+(safeToString, debugString(tp), tp.getClass, if (typeVarLHS) "in LHS" else "in RHS", if (suspended) "ZZ" else if (instValid) "IV" else "")) //@MDEBUG
def checkIsSameType(tp: Type) = (
- if (typeVarLHS) constr.inst =:= tp
- else tp =:= constr.inst
+ if (typeVarLHS) inst =:= tp
+ else tp =:= inst
)
if (suspended) tp =:= origin
- else if (constr.instValid) checkIsSameType(tp)
+ else if (instValid) checkIsSameType(tp)
else isRelatable(tp) && {
val newInst = wildcardToTypeVarMap(tp)
(constr isWithinBounds newInst) && {
@@ -3234,7 +3230,7 @@ trait Types
)
override def normalize: Type = (
- if (constr.instValid) constr.inst
+ if (instValid) inst
// get here when checking higher-order subtyping of the typevar by itself
// TODO: check whether this ever happens?
else if (isHigherKinded) logResult("Normalizing HK $this")(typeFun(params, applyArgs(params map (_.typeConstructor))))
@@ -3265,10 +3261,11 @@ trait Types
}
private def levelString = if (settings.explaintypes) level else ""
override def safeToString = (
- if ((constr eq null) || (constr.inst eq null)) "TVar<" + originName + "=null>"
- else if (constr.inst ne NoType) "=?" + constr.inst
+ if ((constr eq null) || (inst eq null)) "TVar<" + originName + "=null>"
+ else if (inst ne NoType) "=?" + inst
else (if(untouchable) "!?" else "?") + levelString + originName
)
+ def originString = s"$originName in $originLocation"
override def kind = "TypeVar"
def cloneInternal = {
@@ -3853,7 +3850,7 @@ trait Types
/** The maximum allowable depth of lubs or glbs over types `ts`.
*/
- def lubDepth(ts: List[Type]): Int = {
+ def lubDepth(ts: List[Type]): Depth = {
val td = typeDepth(ts)
val bd = baseTypeSeqDepth(ts)
lubDepthAdjust(td, td max bd)
@@ -3863,16 +3860,17 @@ trait Types
* as a function over the maximum depth `td` of these types, and
* the maximum depth `bd` of all types in the base type sequences of these types.
*/
- private def lubDepthAdjust(td: Int, bd: Int): Int =
+ private def lubDepthAdjust(td: Depth, bd: Depth): Depth = (
if (settings.XfullLubs) bd
- else if (bd <= 3) bd
- else if (bd <= 5) td max (bd - 1)
- else if (bd <= 7) td max (bd - 2)
- else (td - 1) max (bd - 3)
+ else if (bd <= Depth(3)) bd
+ else if (bd <= Depth(5)) td max bd.decr
+ else if (bd <= Depth(7)) td max (bd decr 2)
+ else td.decr max (bd decr 3)
+ )
- private def symTypeDepth(syms: List[Symbol]): Int = typeDepth(syms map (_.info))
- private def typeDepth(tps: List[Type]): Int = maxDepth(tps)
- private def baseTypeSeqDepth(tps: List[Type]): Int = maxBaseTypeSeqDepth(tps)
+ private def symTypeDepth(syms: List[Symbol]): Depth = typeDepth(syms map (_.info))
+ private def typeDepth(tps: List[Type]): Depth = maxDepth(tps)
+ private def baseTypeSeqDepth(tps: List[Type]): Depth = maxbaseTypeSeqDepth(tps)
/** Is intersection of given types populated? That is,
* for all types tp1, tp2 in intersection
@@ -4141,7 +4139,7 @@ trait Types
case _ => false
}
- def isSubArgs(tps1: List[Type], tps2: List[Type], tparams: List[Symbol], depth: Int): Boolean = {
+ def isSubArgs(tps1: List[Type], tps2: List[Type], tparams: List[Symbol], depth: Depth): Boolean = {
def isSubArg(t1: Type, t2: Type, variance: Variance) = (
(variance.isContravariant || isSubType(t1, t2, depth))
&& (variance.isCovariant || isSubType(t2, t1, depth))
@@ -4150,7 +4148,7 @@ trait Types
corresponds3(tps1, tps2, tparams map (_.variance))(isSubArg)
}
- def specializesSym(tp: Type, sym: Symbol, depth: Int): Boolean = {
+ def specializesSym(tp: Type, sym: Symbol, depth: Depth): Boolean = {
def directlySpecializedBy(member: Symbol): Boolean = (
member == sym
|| specializesSym(tp.narrow, member, sym.owner.thisType, sym, depth)
@@ -4170,7 +4168,7 @@ trait Types
/** Does member `sym1` of `tp1` have a stronger type
* than member `sym2` of `tp2`?
*/
- protected[internal] def specializesSym(tp1: Type, sym1: Symbol, tp2: Type, sym2: Symbol, depth: Int): Boolean = {
+ protected[internal] def specializesSym(tp1: Type, sym1: Symbol, tp2: Type, sym2: Symbol, depth: Depth): Boolean = {
require((sym1 ne NoSymbol) && (sym2 ne NoSymbol), ((tp1, sym1, tp2, sym2, depth)))
val info1 = tp1.memberInfo(sym1)
val info2 = tp2.memberInfo(sym2).substThis(tp2.typeSymbol, tp1)
@@ -4370,7 +4368,7 @@ trait Types
* Return `x` if the computation succeeds with result `x`.
* Return `NoType` if the computation fails.
*/
- def mergePrefixAndArgs(tps: List[Type], variance: Variance, depth: Int): Type = tps match {
+ def mergePrefixAndArgs(tps: List[Type], variance: Variance, depth: Depth): Type = tps match {
case tp :: Nil => tp
case TypeRef(_, sym, _) :: rest =>
val pres = tps map (_.prefix) // prefix normalizes automatically
@@ -4403,7 +4401,7 @@ trait Types
val args = map2(sym.typeParams, argsst) { (tparam, as0) =>
val as = as0.distinct
if (as.size == 1) as.head
- else if (depth == 0) {
+ else if (depth.isZero) {
log("Giving up merging args: can't unify %s under %s".format(as.mkString(", "), tparam.fullLocationString))
// Don't return "Any" (or "Nothing") when we have to give up due to
// recursion depth. Return NoType, which prevents us from poisoning
@@ -4412,11 +4410,11 @@ trait Types
NoType
}
else {
- if (tparam.variance == variance) lub(as, decr(depth))
- else if (tparam.variance == variance.flip) glb(as, decr(depth))
+ if (tparam.variance == variance) lub(as, depth.decr)
+ else if (tparam.variance == variance.flip) glb(as, depth.decr)
else {
- val l = lub(as, decr(depth))
- val g = glb(as, decr(depth))
+ val l = lub(as, depth.decr)
+ val g = glb(as, depth.decr)
if (l <:< g) l
else { // Martin: I removed this, because incomplete. Not sure there is a good way to fix it. For the moment we
// just err on the conservative side, i.e. with a bound that is too high.
@@ -4454,7 +4452,7 @@ trait Types
/** Make symbol `sym` a member of scope `tp.decls`
* where `thistp` is the narrowed owner type of the scope.
*/
- def addMember(thistp: Type, tp: Type, sym: Symbol, depth: Int) {
+ def addMember(thistp: Type, tp: Type, sym: Symbol, depth: Depth) {
assert(sym != NoSymbol)
// debuglog("add member " + sym+":"+sym.info+" to "+thistp) //DEBUG
if (!specializesSym(thistp, sym, depth)) {
@@ -4581,23 +4579,15 @@ trait Types
private[scala] val typeIsHigherKinded = (tp: Type) => tp.isHigherKinded
/** The maximum depth of type `tp` */
- def typeDepth(tp: Type): Int = tp match {
- case TypeRef(pre, sym, args) =>
- math.max(typeDepth(pre), typeDepth(args) + 1)
- case RefinedType(parents, decls) =>
- math.max(typeDepth(parents), symTypeDepth(decls.toList) + 1)
- case TypeBounds(lo, hi) =>
- math.max(typeDepth(lo), typeDepth(hi))
- case MethodType(paramtypes, result) =>
- typeDepth(result)
- case NullaryMethodType(result) =>
- typeDepth(result)
- case PolyType(tparams, result) =>
- math.max(typeDepth(result), symTypeDepth(tparams) + 1)
- case ExistentialType(tparams, result) =>
- math.max(typeDepth(result), symTypeDepth(tparams) + 1)
- case _ =>
- 1
+ def typeDepth(tp: Type): Depth = tp match {
+ case TypeRef(pre, sym, args) => typeDepth(pre) max typeDepth(args).incr
+ case RefinedType(parents, decls) => typeDepth(parents) max symTypeDepth(decls.toList).incr
+ case TypeBounds(lo, hi) => typeDepth(lo) max typeDepth(hi)
+ case MethodType(paramtypes, result) => typeDepth(result)
+ case NullaryMethodType(result) => typeDepth(result)
+ case PolyType(tparams, result) => typeDepth(result) max symTypeDepth(tparams).incr
+ case ExistentialType(tparams, result) => typeDepth(result) max symTypeDepth(tparams).incr
+ case _ => Depth(1)
}
def withUncheckedVariance(tp: Type): Type =
@@ -4608,19 +4598,19 @@ trait Types
// var d = 0
// for (tp <- tps) d = d max by(tp) //!!!OPT!!!
// d
- private[scala] def maxDepth(tps: List[Type]): Int = {
- @tailrec def loop(tps: List[Type], acc: Int): Int = tps match {
- case tp :: rest => loop(rest, math.max(acc, typeDepth(tp)))
+ private[scala] def maxDepth(tps: List[Type]): Depth = {
+ @tailrec def loop(tps: List[Type], acc: Depth): Depth = tps match {
+ case tp :: rest => loop(rest, acc max typeDepth(tp))
case _ => acc
}
- loop(tps, 0)
+ loop(tps, Depth.Zero)
}
- private[scala] def maxBaseTypeSeqDepth(tps: List[Type]): Int = {
- @tailrec def loop(tps: List[Type], acc: Int): Int = tps match {
- case tp :: rest => loop(rest, math.max(acc, tp.baseTypeSeqDepth))
+ private[scala] def maxbaseTypeSeqDepth(tps: List[Type]): Depth = {
+ @tailrec def loop(tps: List[Type], acc: Depth): Depth = tps match {
+ case tp :: rest => loop(rest, acc max tp.baseTypeSeqDepth)
case _ => acc
}
- loop(tps, 0)
+ loop(tps, Depth.Zero)
}
@tailrec private def typesContain(tps: List[Type], sym: Symbol): Boolean = tps match {
diff --git a/src/reflect/scala/reflect/internal/tpe/GlbLubs.scala b/src/reflect/scala/reflect/internal/tpe/GlbLubs.scala
index 1d3c6b0f23..6fa536d84c 100644
--- a/src/reflect/scala/reflect/internal/tpe/GlbLubs.scala
+++ b/src/reflect/scala/reflect/internal/tpe/GlbLubs.scala
@@ -19,7 +19,7 @@ private[internal] trait GlbLubs {
private final val verifyLubs = true
- private def printLubMatrix(btsMap: Map[Type, List[Type]], depth: Int) {
+ private def printLubMatrix(btsMap: Map[Type, List[Type]], depth: Depth) {
import util.TableDef
import TableDef.Column
def str(tp: Type) = {
@@ -76,8 +76,8 @@ private[internal] trait GlbLubs {
* (except that type constructors have been applied to their dummyArgs)
* @See baseTypeSeq for a definition of sorted and upwards closed.
*/
- def lubList(ts: List[Type], depth: Int): List[Type] = {
- var lubListDepth = 0
+ def lubList(ts: List[Type], depth: Depth): List[Type] = {
+ var lubListDepth = Depth.Zero
// This catches some recursive situations which would otherwise
// befuddle us, e.g. pos/hklub0.scala
def isHotForTs(xs: List[Type]) = ts exists (_.typeParams == xs.map(_.typeSymbol))
@@ -89,7 +89,7 @@ private[internal] trait GlbLubs {
}
// pretypes is a tail-recursion-preserving accumulator.
@tailrec def loop(pretypes: List[Type], tsBts: List[List[Type]]): List[Type] = {
- lubListDepth += 1
+ lubListDepth = lubListDepth.incr
if (tsBts.isEmpty || (tsBts exists typeListIsEmpty)) pretypes.reverse
else if (tsBts.tail.isEmpty) pretypes.reverse ++ tsBts.head
@@ -181,13 +181,13 @@ private[internal] trait GlbLubs {
/** Eliminate from list of types all elements which are a subtype
* of some other element of the list. */
- private def elimSub(ts: List[Type], depth: Int): List[Type] = {
+ private def elimSub(ts: List[Type], depth: Depth): List[Type] = {
def elimSub0(ts: List[Type]): List[Type] = ts match {
case List() => List()
case List(t) => List(t)
case t :: ts1 =>
- val rest = elimSub0(ts1 filter (t1 => !isSubType(t1, t, decr(depth))))
- if (rest exists (t1 => isSubType(t, t1, decr(depth)))) rest else t :: rest
+ val rest = elimSub0(ts1 filter (t1 => !isSubType(t1, t, depth.decr)))
+ if (rest exists (t1 => isSubType(t, t1, depth.decr))) rest else t :: rest
}
val ts0 = elimSub0(ts)
if (ts0.isEmpty || ts0.tail.isEmpty) ts0
@@ -251,8 +251,8 @@ private[internal] trait GlbLubs {
else if (isNumericSubType(t2, t1)) t1
else IntTpe)
- private val lubResults = new mutable.HashMap[(Int, List[Type]), Type]
- private val glbResults = new mutable.HashMap[(Int, List[Type]), Type]
+ private val lubResults = new mutable.HashMap[(Depth, List[Type]), Type]
+ private val glbResults = new mutable.HashMap[(Depth, List[Type]), Type]
/** Given a list of types, finds all the base classes they have in
* common, then returns a list of type constructors derived directly
@@ -299,7 +299,7 @@ private[internal] trait GlbLubs {
}
/** The least upper bound wrt <:< of a list of types */
- protected[internal] def lub(ts: List[Type], depth: Int): Type = {
+ protected[internal] def lub(ts: List[Type], depth: Depth): Type = {
def lub0(ts0: List[Type]): Type = elimSub(ts0, depth) match {
case List() => NothingTpe
case List(t) => t
@@ -321,7 +321,7 @@ private[internal] trait GlbLubs {
lubType
case None =>
lubResults((depth, ts)) = AnyTpe
- val res = if (depth < 0) AnyTpe else lub1(ts)
+ val res = if (depth.isNegative) AnyTpe else lub1(ts)
lubResults((depth, ts)) = res
res
}
@@ -333,7 +333,7 @@ private[internal] trait GlbLubs {
val lubOwner = commonOwner(ts)
val lubBase = intersectionType(lubParents, lubOwner)
val lubType =
- if (phase.erasedTypes || depth == 0 ) lubBase
+ if (phase.erasedTypes || depth.isZero ) lubBase
else {
val lubRefined = refinedType(lubParents, lubOwner)
val lubThisType = lubRefined.typeSymbol.thisType
@@ -357,12 +357,12 @@ private[internal] trait GlbLubs {
val symtypes =
map2(narrowts, syms)((t, sym) => t.memberInfo(sym).substThis(t.typeSymbol, lubThisType))
if (proto.isTerm) // possible problem: owner of info is still the old one, instead of new refinement class
- proto.cloneSymbol(lubRefined.typeSymbol).setInfoOwnerAdjusted(lub(symtypes, decr(depth)))
+ proto.cloneSymbol(lubRefined.typeSymbol).setInfoOwnerAdjusted(lub(symtypes, depth.decr))
else if (symtypes.tail forall (symtypes.head =:= _))
proto.cloneSymbol(lubRefined.typeSymbol).setInfoOwnerAdjusted(symtypes.head)
else {
def lubBounds(bnds: List[TypeBounds]): TypeBounds =
- TypeBounds(glb(bnds map (_.lo), decr(depth)), lub(bnds map (_.hi), decr(depth)))
+ TypeBounds(glb(bnds map (_.lo), depth.decr), lub(bnds map (_.hi), depth.decr))
lubRefined.typeSymbol.newAbstractType(proto.name.toTypeName, proto.pos)
.setInfoOwnerAdjusted(lubBounds(symtypes map (_.bounds)))
}
@@ -432,8 +432,8 @@ private[internal] trait GlbLubs {
* The counter breaks this recursion after two calls.
* If the recursion is broken, no member is added to the glb.
*/
- private var globalGlbDepth = 0
- private final val globalGlbLimit = 2
+ private var globalGlbDepth = Depth.Zero
+ private final val globalGlbLimit = Depth(2)
/** The greatest lower bound of a list of types (as determined by `<:<`). */
def glb(ts: List[Type]): Type = elimSuper(ts) match {
@@ -451,7 +451,7 @@ private[internal] trait GlbLubs {
}
}
- protected[internal] def glb(ts: List[Type], depth: Int): Type = elimSuper(ts) match {
+ protected[internal] def glb(ts: List[Type], depth: Depth): Type = elimSuper(ts) match {
case List() => AnyTpe
case List(t) => t
case ts0 => glbNorm(ts0, depth)
@@ -459,7 +459,7 @@ private[internal] trait GlbLubs {
/** The greatest lower bound of a list of types (as determined by `<:<`), which have been normalized
* with regard to `elimSuper`. */
- protected def glbNorm(ts: List[Type], depth: Int): Type = {
+ protected def glbNorm(ts: List[Type], depth: Depth): Type = {
def glb0(ts0: List[Type]): Type = ts0 match {
case List() => AnyTpe
case List(t) => t
@@ -479,7 +479,7 @@ private[internal] trait GlbLubs {
glbType
case _ =>
glbResults((depth, ts)) = NothingTpe
- val res = if (depth < 0) NothingTpe else glb1(ts)
+ val res = if (depth.isNegative) NothingTpe else glb1(ts)
glbResults((depth, ts)) = res
res
}
@@ -501,7 +501,7 @@ private[internal] trait GlbLubs {
val ts1 = ts flatMap refinedToParents
val glbBase = intersectionType(ts1, glbOwner)
val glbType =
- if (phase.erasedTypes || depth == 0) glbBase
+ if (phase.erasedTypes || depth.isZero) glbBase
else {
val glbRefined = refinedType(ts1, glbOwner)
val glbThisType = glbRefined.typeSymbol.thisType
@@ -514,15 +514,15 @@ private[internal] trait GlbLubs {
val symtypes = syms map glbThisType.memberInfo
assert(!symtypes.isEmpty)
proto.cloneSymbol(glbRefined.typeSymbol).setInfoOwnerAdjusted(
- if (proto.isTerm) glb(symtypes, decr(depth))
+ if (proto.isTerm) glb(symtypes, depth.decr)
else {
def isTypeBound(tp: Type) = tp match {
case TypeBounds(_, _) => true
case _ => false
}
def glbBounds(bnds: List[Type]): TypeBounds = {
- val lo = lub(bnds map (_.bounds.lo), decr(depth))
- val hi = glb(bnds map (_.bounds.hi), decr(depth))
+ val lo = lub(bnds map (_.bounds.lo), depth.decr)
+ val hi = glb(bnds map (_.bounds.hi), depth.decr)
if (lo <:< hi) TypeBounds(lo, hi)
else throw GlbFailure
}
@@ -539,7 +539,7 @@ private[internal] trait GlbLubs {
}
if (globalGlbDepth < globalGlbLimit)
try {
- globalGlbDepth += 1
+ globalGlbDepth = globalGlbDepth.incr
val dss = ts flatMap refinedToDecls
for (ds <- dss; sym <- ds.iterator)
if (globalGlbDepth < globalGlbLimit && !specializesSym(glbThisType, sym, depth))
@@ -549,7 +549,7 @@ private[internal] trait GlbLubs {
case ex: NoCommonType =>
}
} finally {
- globalGlbDepth -= 1
+ globalGlbDepth = globalGlbDepth.decr
}
if (glbRefined.decls.isEmpty) glbBase else glbRefined
}
diff --git a/src/reflect/scala/reflect/internal/tpe/TypeComparers.scala b/src/reflect/scala/reflect/internal/tpe/TypeComparers.scala
index 63f17dff34..d8b3b04d0e 100644
--- a/src/reflect/scala/reflect/internal/tpe/TypeComparers.scala
+++ b/src/reflect/scala/reflect/internal/tpe/TypeComparers.scala
@@ -232,9 +232,7 @@ trait TypeComparers {
)
}
- def isSubType(tp1: Type, tp2: Type): Boolean = isSubType(tp1, tp2, AnyDepth)
-
- def isSubType(tp1: Type, tp2: Type, depth: Int): Boolean = try {
+ def isSubType(tp1: Type, tp2: Type, depth: Depth = Depth.AnyDepth): Boolean = try {
subsametypeRecursions += 1
//OPT cutdown on Function0 allocation
@@ -314,7 +312,7 @@ trait TypeComparers {
else TriState.Unknown
}
- private def isSubType1(tp1: Type, tp2: Type, depth: Int): Boolean = typeRelationPreCheck(tp1, tp2) match {
+ private def isSubType1(tp1: Type, tp2: Type, depth: Depth): Boolean = typeRelationPreCheck(tp1, tp2) match {
case state if state.isKnown => state.booleanValue
case _ if typeHasAnnotations(tp1) || typeHasAnnotations(tp2) => annotationsConform(tp1, tp2) && (tp1.withoutAnnotations <:< tp2.withoutAnnotations)
case _ => isSubType2(tp1, tp2, depth)
@@ -338,7 +336,7 @@ trait TypeComparers {
}
// @assume tp1.isHigherKinded || tp2.isHigherKinded
- def isHKSubType(tp1: Type, tp2: Type, depth: Int): Boolean = {
+ def isHKSubType(tp1: Type, tp2: Type, depth: Depth): Boolean = {
def isSub(ntp1: Type, ntp2: Type) = (ntp1.withoutAnnotations, ntp2.withoutAnnotations) match {
case (TypeRef(_, AnyClass, _), _) => false // avoid some warnings when Nothing/Any are on the other side
case (_, TypeRef(_, NothingClass, _)) => false
@@ -357,7 +355,7 @@ trait TypeComparers {
}
/** Does type `tp1` conform to `tp2`? */
- private def isSubType2(tp1: Type, tp2: Type, depth: Int): Boolean = {
+ private def isSubType2(tp1: Type, tp2: Type, depth: Depth): Boolean = {
def retry(lhs: Type, rhs: Type) = ((lhs ne tp1) || (rhs ne tp2)) && isSubType(lhs, rhs, depth)
if (isSingleType(tp1) && isSingleType(tp2) || isConstantType(tp1) && isConstantType(tp2))
diff --git a/src/reflect/scala/reflect/internal/tpe/TypeConstraints.scala b/src/reflect/scala/reflect/internal/tpe/TypeConstraints.scala
index 123c296f95..927d86380c 100644
--- a/src/reflect/scala/reflect/internal/tpe/TypeConstraints.scala
+++ b/src/reflect/scala/reflect/internal/tpe/TypeConstraints.scala
@@ -170,11 +170,14 @@ private[internal] trait TypeConstraints {
}
}
- def isWithinBounds(tp: Type): Boolean =
- lobounds.forall(_ <:< tp) &&
- hibounds.forall(tp <:< _) &&
- (numlo == NoType || (numlo weak_<:< tp)) &&
- (numhi == NoType || (tp weak_<:< numhi))
+ def instWithinBounds = instValid && isWithinBounds(inst)
+
+ def isWithinBounds(tp: Type): Boolean = (
+ lobounds.forall(_ <:< tp)
+ && hibounds.forall(tp <:< _)
+ && (numlo == NoType || (numlo weak_<:< tp))
+ && (numhi == NoType || (tp weak_<:< numhi))
+ )
var inst: Type = NoType // @M reduce visibility?
@@ -208,12 +211,7 @@ private[internal] trait TypeConstraints {
* solution direction for all contravariant variables.
* @param upper When `true` search for max solution else min.
*/
- def solve(tvars: List[TypeVar], tparams: List[Symbol],
- variances: List[Variance], upper: Boolean): Boolean =
- solve(tvars, tparams, variances, upper, AnyDepth)
-
- def solve(tvars: List[TypeVar], tparams: List[Symbol],
- variances: List[Variance], upper: Boolean, depth: Int): Boolean = {
+ def solve(tvars: List[TypeVar], tparams: List[Symbol], variances: List[Variance], upper: Boolean, depth: Depth): Boolean = {
def solveOne(tvar: TypeVar, tparam: Symbol, variance: Variance) {
if (tvar.constr.inst == NoType) {
@@ -265,12 +263,16 @@ private[internal] trait TypeConstraints {
//println("solving "+tvar+" "+up+" "+(if (up) (tvar.constr.hiBounds) else tvar.constr.loBounds)+((if (up) (tvar.constr.hiBounds) else tvar.constr.loBounds) map (_.widen)))
val newInst = (
if (up) {
- if (depth != AnyDepth) glb(tvar.constr.hiBounds, depth) else glb(tvar.constr.hiBounds)
- } else {
- if (depth != AnyDepth) lub(tvar.constr.loBounds, depth) else lub(tvar.constr.loBounds)
+ if (depth.isAnyDepth) glb(tvar.constr.hiBounds)
+ else glb(tvar.constr.hiBounds, depth)
+ }
+ else {
+ if (depth.isAnyDepth) lub(tvar.constr.loBounds)
+ else lub(tvar.constr.loBounds, depth)
}
)
- log(s"$tvar setInst $newInst")
+
+ debuglog(s"$tvar setInst $newInst")
tvar setInst newInst
//Console.println("solving "+tvar+" "+up+" "+(if (up) (tvar.constr.hiBounds) else tvar.constr.loBounds)+((if (up) (tvar.constr.hiBounds) else tvar.constr.loBounds) map (_.widen))+" = "+tvar.constr.inst)//@MDEBUG
}
@@ -278,6 +280,6 @@ private[internal] trait TypeConstraints {
// println("solving "+tvars+"/"+tparams+"/"+(tparams map (_.info)))
foreach3(tvars, tparams, variances)(solveOne)
- tvars forall (tvar => tvar.constr.isWithinBounds(tvar.constr.inst))
+ tvars forall (tv => tv.instWithinBounds || util.andFalse(log(s"Inferred type for ${tv.originString} does not conform to bounds: ${tv.constr}")))
}
}
diff --git a/src/reflect/scala/reflect/internal/util/package.scala b/src/reflect/scala/reflect/internal/util/package.scala
index 49164d366c..df63a55090 100644
--- a/src/reflect/scala/reflect/internal/util/package.scala
+++ b/src/reflect/scala/reflect/internal/util/package.scala
@@ -7,6 +7,8 @@ import scala.language.existentials // SI-6541
package object util {
import StringOps.longestCommonPrefix
+ def andFalse(body: Unit): Boolean = false
+
// Shorten a name like Symbols$FooSymbol to FooSymbol.
private def shortenName(name: String): String = {
if (name == "") return ""
diff --git a/src/reflect/scala/reflect/runtime/SynchronizedTypes.scala b/src/reflect/scala/reflect/runtime/SynchronizedTypes.scala
index f4b02c5bcd..c0146167df 100644
--- a/src/reflect/scala/reflect/runtime/SynchronizedTypes.scala
+++ b/src/reflect/scala/reflect/runtime/SynchronizedTypes.scala
@@ -4,6 +4,7 @@ package runtime
import scala.collection.mutable.WeakHashMap
import java.lang.ref.WeakReference
+import scala.reflect.internal.Depth
/** This trait overrides methods in reflect.internal, bracketing
* them in synchronized { ... } to make them thread-safe
@@ -57,7 +58,7 @@ private[reflect] trait SynchronizedTypes extends internal.Types { self: SymbolTa
override def isDifferentType(tp1: Type, tp2: Type): Boolean =
subsametypeLock.synchronized { super.isDifferentType(tp1, tp2) }
- override def isSubType(tp1: Type, tp2: Type, depth: Int): Boolean =
+ override def isSubType(tp1: Type, tp2: Type, depth: Depth): Boolean =
subsametypeLock.synchronized { super.isSubType(tp1, tp2, depth) }
private object lubglbLock