diff options
Diffstat (limited to 'src')
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 |