From 4412a92d3609d23f7369fc67bf5a67ddedf3511e Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Sun, 25 Aug 2013 09:13:44 -0700 Subject: 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 --- .../scala/reflect/macros/compiler/Validators.scala | 2 +- .../scala/tools/nsc/typechecker/Implicits.scala | 3 +- .../scala/tools/nsc/typechecker/Infer.scala | 51 +++----- .../scala/reflect/internal/BaseTypeSeqs.scala | 8 +- src/reflect/scala/reflect/internal/Depth.scala | 28 +++++ src/reflect/scala/reflect/internal/Types.scala | 136 ++++++++++----------- .../scala/reflect/internal/tpe/GlbLubs.scala | 50 ++++---- .../scala/reflect/internal/tpe/TypeComparers.scala | 10 +- .../reflect/internal/tpe/TypeConstraints.scala | 34 +++--- .../scala/reflect/internal/util/package.scala | 2 + .../scala/reflect/runtime/SynchronizedTypes.scala | 3 +- 11 files changed, 166 insertions(+), 161 deletions(-) create mode 100644 src/reflect/scala/reflect/internal/Depth.scala 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 -- cgit v1.2.3 From 7d83be218473f08ab560c937318faadce2617d95 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Sun, 25 Aug 2013 09:22:47 -0700 Subject: Logging cleanup. Reduced the amount of extraneous logging noise at the default logging level. Was brought to my usual crashing halt by the discovery of identical logging statements throughout GenASM and elsewhere. I'm supposing the reason people so grossly underestimate the cost of such duplication is that most of the effects are in things which don't happen, aka "silent evidence". An example of a thing which isn't happening is the remainder of this commit, which exists only in parallel universes. --- .../scala/tools/nsc/backend/icode/GenICode.scala | 10 ++++----- .../tools/nsc/backend/jvm/BCodeBodyBuilder.scala | 4 ++-- .../scala/tools/nsc/backend/jvm/GenASM.scala | 6 ++--- .../scala/tools/nsc/transform/Constructors.scala | 4 ++-- .../scala/tools/nsc/transform/Erasure.scala | 20 ++++++++++++----- .../scala/tools/nsc/transform/Flatten.scala | 4 ++-- .../scala/tools/nsc/typechecker/Checkable.scala | 4 +++- .../scala/tools/nsc/typechecker/Contexts.scala | 2 +- .../scala/tools/nsc/typechecker/Infer.scala | 23 ++++++++++--------- .../scala/tools/nsc/typechecker/Namers.scala | 7 ++++-- .../tools/nsc/typechecker/PatternTypers.scala | 6 +---- .../scala/tools/nsc/typechecker/Typers.scala | 2 +- src/reflect/scala/reflect/internal/Symbols.scala | 11 +++++++-- src/reflect/scala/reflect/internal/Types.scala | 2 +- src/reflect/scala/reflect/internal/Variance.scala | 3 +-- src/reflect/scala/reflect/internal/Variances.scala | 6 +++-- .../reflect/internal/tpe/TypeConstraints.scala | 26 +++++++++++++--------- .../scala/reflect/internal/tpe/TypeMaps.scala | 13 +++++------ 18 files changed, 88 insertions(+), 65 deletions(-) diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala index 410d451316..843299398b 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala @@ -72,7 +72,7 @@ abstract class GenICode extends SubComponent { * it is the host class; otherwise the symbol's owner. */ def findHostClass(selector: Type, sym: Symbol) = selector member sym.name match { - case NoSymbol => log(s"Rejecting $selector as host class for $sym") ; sym.owner + case NoSymbol => debuglog(s"Rejecting $selector as host class for $sym") ; sym.owner case _ => selector.typeSymbol } @@ -739,7 +739,7 @@ abstract class GenICode extends SubComponent { resolveForwardLabel(ctx.defdef, ctx, sym) ctx.labels.get(sym) match { case Some(l) => - log("Forward jump for " + sym.fullLocationString + ": scan found label " + l) + debuglog("Forward jump for " + sym.fullLocationString + ": scan found label " + l) l case _ => abort("Unknown label target: " + sym + " at: " + (fun.pos) + ": ctx: " + ctx) @@ -845,7 +845,7 @@ abstract class GenICode extends SubComponent { val sym = tree.symbol generatedType = toTypeKind(sym.info) val hostClass = findHostClass(qualifier.tpe, sym) - log(s"Host class of $sym with qual $qualifier (${qualifier.tpe}) is $hostClass") + debuglog(s"Host class of $sym with qual $qualifier (${qualifier.tpe}) is $hostClass") val qualSafeToElide = treeInfo isQualifierSafeToElide qualifier def genLoadQualUnlessElidable: Context = @@ -1026,7 +1026,7 @@ abstract class GenICode extends SubComponent { * type Null is holding a null. */ private def adaptNullRef(from: TypeKind, to: TypeKind, ctx: Context, pos: Position) { - log(s"GenICode#adaptNullRef($from, $to, $ctx, $pos)") + debuglog(s"GenICode#adaptNullRef($from, $to, $ctx, $pos)") // Don't need to adapt null to unit because we'll just drop it anyway. Don't // need to adapt to Object or AnyRef because the JVM is happy with @@ -1046,7 +1046,7 @@ abstract class GenICode extends SubComponent { private def adapt(from: TypeKind, to: TypeKind, ctx: Context, pos: Position) { // An awful lot of bugs explode here - let's leave ourselves more clues. // A typical example is an overloaded type assigned after typer. - log(s"GenICode#adapt($from, $to, $ctx, $pos)") + debuglog(s"GenICode#adapt($from, $to, $ctx, $pos)") def coerce(from: TypeKind, to: TypeKind) = ctx.bb.emit(CALL_PRIMITIVE(Conversion(from, to)), pos) diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala index 683f35e41f..817546b0f1 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala @@ -36,7 +36,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder { * it is the host class; otherwise the symbol's owner. */ def findHostClass(selector: Type, sym: Symbol) = selector member sym.name match { - case NoSymbol => log(s"Rejecting $selector as host class for $sym") ; sym.owner + case NoSymbol => debuglog(s"Rejecting $selector as host class for $sym") ; sym.owner case _ => selector.typeSymbol } @@ -330,7 +330,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder { val sym = tree.symbol generatedType = symInfoTK(sym) val hostClass = findHostClass(qualifier.tpe, sym) - log(s"Host class of $sym with qual $qualifier (${qualifier.tpe}) is $hostClass") + debuglog(s"Host class of $sym with qual $qualifier (${qualifier.tpe}) is $hostClass") val qualSafeToElide = treeInfo isQualifierSafeToElide qualifier def genLoadQualUnlessElidable() { if (!qualSafeToElide) { genLoadQualifier(tree) } } diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala index 4cb2f514ec..3947db2dd4 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala @@ -1122,13 +1122,13 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM { for (m <- moduleClass.info.membersBasedOnFlags(ExcludedForwarderFlags, Flags.METHOD)) { if (m.isType || m.isDeferred || (m.owner eq ObjectClass) || m.isConstructor) - debuglog("No forwarder for '%s' from %s to '%s'".format(m, jclassName, moduleClass)) + debuglog(s"No forwarder for '$m' from $jclassName to '$moduleClass'") else if (conflictingNames(m.name)) - log("No forwarder for " + m + " due to conflict with " + linkedClass.info.member(m.name)) + log(s"No forwarder for $m due to conflict with " + linkedClass.info.member(m.name)) else if (m.hasAccessBoundary) log(s"No forwarder for non-public member $m") else { - log("Adding static forwarder for '%s' from %s to '%s'".format(m, jclassName, moduleClass)) + debuglog(s"Adding static forwarder for '$m' from $jclassName to '$moduleClass'") addForwarder(isRemoteClass, jclass, moduleClass, m) } } diff --git a/src/compiler/scala/tools/nsc/transform/Constructors.scala b/src/compiler/scala/tools/nsc/transform/Constructors.scala index e80117afbd..cbe4f69d25 100644 --- a/src/compiler/scala/tools/nsc/transform/Constructors.scala +++ b/src/compiler/scala/tools/nsc/transform/Constructors.scala @@ -44,8 +44,8 @@ abstract class Constructors extends Transform with ast.TreeDSL { val uninitializedVals = mutable.Set[Symbol]( stats collect { case vd: ValDef if checkableForInit(vd.symbol) => vd.symbol.accessedOrSelf }: _* ) - if (uninitializedVals.nonEmpty) - log("Checking constructor for init order issues among: " + uninitializedVals.map(_.name).mkString(", ")) + if (uninitializedVals.size > 1) + log("Checking constructor for init order issues among: " + uninitializedVals.toList.map(_.name.toString.trim).distinct.sorted.mkString(", ")) for (stat <- stats) { // Checking the qualifier symbol is necessary to prevent a selection on diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index 0a66ba8a32..b8f79ced79 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -529,7 +529,8 @@ abstract class Erasure extends AddInterfaces @inline private def box(tree: Tree, target: => String): Tree = { val result = box1(tree) - log(s"boxing ${tree.summaryString}: ${tree.tpe} into $target: ${result.tpe}") + if (tree.tpe =:= UnitTpe) () + else log(s"boxing ${tree.summaryString}: ${tree.tpe} into $target: ${result.tpe}") result } @@ -571,7 +572,7 @@ abstract class Erasure extends AddInterfaces private def unbox(tree: Tree, pt: Type): Tree = { val result = unbox1(tree, pt) - log(s"unboxing ${tree.summaryString}: ${tree.tpe} with pt=$pt as type ${result.tpe}") + log(s"unboxing ${tree.shortClass}: ${tree.tpe} as a ${result.tpe}") result } @@ -594,7 +595,6 @@ abstract class Erasure extends AddInterfaces val tree1 = pt match { case ErasedValueType(tref) => val clazz = tref.sym - log("not boxed: "+tree) lazy val underlying = underlyingOfValueClass(clazz) val tree0 = if (tree.tpe.typeSymbol == NullClass && @@ -622,8 +622,18 @@ abstract class Erasure extends AddInterfaces /** Generate a synthetic cast operation from tree.tpe to pt. * @pre pt eq pt.normalize */ - private def cast(tree: Tree, pt: Type): Tree = logResult(s"cast($tree, $pt)") { - if (pt.typeSymbol == UnitClass) { + private def cast(tree: Tree, pt: Type): Tree = { + if ((tree.tpe ne null) && !(tree.tpe =:= ObjectTpe)) { + def word = ( + if (tree.tpe <:< pt) "upcast" + else if (pt <:< tree.tpe) "downcast" + else if (pt weak_<:< tree.tpe) "coerce" + else if (tree.tpe weak_<:< pt) "widen" + else "cast" + ) + log(s"erasure ${word}s from ${tree.tpe} to $pt") + } + if (pt =:= UnitTpe) { // See SI-4731 for one example of how this occurs. log("Attempted to cast to Unit: " + tree) tree.duplicate setType pt diff --git a/src/compiler/scala/tools/nsc/transform/Flatten.scala b/src/compiler/scala/tools/nsc/transform/Flatten.scala index 44d39de205..e31211d321 100644 --- a/src/compiler/scala/tools/nsc/transform/Flatten.scala +++ b/src/compiler/scala/tools/nsc/transform/Flatten.scala @@ -24,8 +24,8 @@ abstract class Flatten extends InfoTransform { val old = (scope lookupUnshadowedEntries sym.name).toList old foreach (scope unlink _) scope enter sym - log(s"lifted ${sym.fullLocationString}" + ( if (old.isEmpty) "" else s" after unlinking $old from scope." )) - old + def old_s = old map (_.sym) mkString ", " + debuglog(s"In scope of ${sym.owner}, unlinked $old_s and entered $sym") } private def liftClass(sym: Symbol) { diff --git a/src/compiler/scala/tools/nsc/typechecker/Checkable.scala b/src/compiler/scala/tools/nsc/typechecker/Checkable.scala index 67c5666f66..0eae17612d 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Checkable.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Checkable.scala @@ -277,7 +277,9 @@ trait Checkable { parents foreach (p => checkCheckable(tree, p, X, inPattern, canRemedy)) case _ => val checker = new CheckabilityChecker(X, P) - log(checker.summaryString) + if (checker.result == RuntimeCheckable) + log(checker.summaryString) + if (checker.neverMatches) { val addendum = if (checker.neverSubClass) "" else " (but still might match its erasure)" getContext.unit.warning(tree.pos, s"fruitless type test: a value of type $X cannot also be a $P$addendum") diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala index 86a0d33737..8d42bf94f3 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala @@ -1026,7 +1026,7 @@ trait Contexts { self: Analyzer => (scope lookupUnshadowedEntries name filter (e => qualifies(e.sym))).toList def newOverloaded(owner: Symbol, pre: Type, entries: List[ScopeEntry]) = - logResult(s"!!! lookup overloaded")(owner.newOverloaded(pre, entries map (_.sym))) + logResult(s"overloaded symbol in $pre")(owner.newOverloaded(pre, entries map (_.sym))) // Constructor lookup should only look in the decls of the enclosing class // not in the self-type, nor in the enclosing context, nor in imports (SI-4460, SI-6745) diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index fa85d7a2fb..03f680525c 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -159,7 +159,10 @@ trait Infer extends Checkable { * This method seems to be performance critical. */ def normalize(tp: Type): Type = tp match { - case PolyType(_, restpe) => logResult(s"Normalizing $tp in infer")(normalize(restpe)) + case PolyType(_, restpe) => + logResult(sm"""|Normalizing PolyType in infer: + | was: $restpe + | now""")(normalize(restpe)) case mt @ MethodType(_, restpe) if mt.isImplicit => normalize(restpe) case mt @ MethodType(_, restpe) if !mt.isDependentMethodType => functionType(mt.paramTypes, normalize(restpe)) case NullaryMethodType(restpe) => normalize(restpe) @@ -1095,16 +1098,14 @@ trait Infer extends Checkable { val TypeBounds(lo0, hi0) = tparam.info.bounds val tb @ TypeBounds(lo1, hi1) = instBounds(tvar) val enclCase = context.enclosingCaseDef - - log("\n" + sm""" - |----- - | enclCase: ${enclCase.tree} - | saved: ${enclCase.savedTypeBounds} - | tparam: ${tparam.shortSymbolClass} - | def_s: ${tparam.defString} - | seen_s: ${tparam.defStringSeenAs(tb)} - |----- - """.trim) + def enclCase_s = enclCase.toString.replaceAll("\\n", " ").take(60) + + if (enclCase.savedTypeBounds.nonEmpty) log( + sm"""|instantiateTypeVar with nonEmpty saved type bounds { + | enclosing $enclCase_s + | saved ${enclCase.savedTypeBounds} + | tparam ${tparam.shortSymbolClass} ${tparam.defString} + |}""") if (lo1 <:< hi1) { if (lo1 <:< lo0 && hi0 <:< hi1) // bounds unimproved diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index 2bb2cc1ab4..95d6ca52ec 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -291,10 +291,13 @@ trait Namers extends MethodSynthesis { } private def logAssignSymbol(tree: Tree, sym: Symbol): Symbol = { - sym.name.toTermName match { + if (isPastTyper) sym.name.toTermName match { case nme.IMPORT | nme.OUTER | nme.ANON_CLASS_NAME | nme.ANON_FUN_NAME | nme.CONSTRUCTOR => () case _ => - log("[+symbol] " + sym.debugLocationString) + tree match { + case md: DefDef => log("[+symbol] " + sym.debugLocationString) + case _ => + } } tree.symbol = sym sym diff --git a/src/compiler/scala/tools/nsc/typechecker/PatternTypers.scala b/src/compiler/scala/tools/nsc/typechecker/PatternTypers.scala index 7120aeaaa6..8bf9ce49be 100644 --- a/src/compiler/scala/tools/nsc/typechecker/PatternTypers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/PatternTypers.scala @@ -340,11 +340,7 @@ trait PatternTypers { // use "tree" for the context, not context.tree: don't make another CaseDef context, // as instantiateTypeVar's bounds would end up there - log(sm"""|convert to case constructor { - | tree: $tree: ${tree.tpe} - | ptSafe: $ptSafe - | context.tree: ${context.tree}: ${context.tree.tpe} - |}""".trim) + log(s"convert ${tree.summaryString}: ${tree.tpe} to case constructor, pt=$ptSafe") val ctorContext = context.makeNewScope(tree, context.owner) freeVars foreach ctorContext.scope.enter diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index cccd0949a2..dd16b5be85 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -3717,7 +3717,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper * */ def mkInvoke(cxTree: Tree, tree: Tree, qual: Tree, name: Name): Option[Tree] = { - log(s"dyna.mkInvoke($cxTree, $tree, $qual, $name)") + debuglog(s"dyna.mkInvoke($cxTree, $tree, $qual, $name)") val treeInfo.Applied(treeSelection, _, _) = tree def isDesugaredApply = treeSelection match { case Select(`qual`, nme.apply) => true diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala index a8efa938c8..d3a0ffb744 100644 --- a/src/reflect/scala/reflect/internal/Symbols.scala +++ b/src/reflect/scala/reflect/internal/Symbols.scala @@ -147,7 +147,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => def name: NameType def name_=(n: Name): Unit = { if (shouldLogAtThisPhase) { - val msg = s"Renaming $fullLocationString to $n" + def msg = s"In $owner, renaming $name -> $n" if (isSpecialized) debuglog(msg) else log(msg) } } @@ -2524,7 +2524,14 @@ trait Symbols extends api.Symbols { self: SymbolTable => } def infosString = infos.toString - def debugLocationString = fullLocationString + " (flags: " + debugFlagString + ")" + def debugLocationString = { + val pre = flagString match { + case "" => "" + case s if s contains ' ' => "(" + s + ") " + case s => s + " " + } + pre + fullLocationString + } private def defStringCompose(infoString: String) = compose( flagString, diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala index f96959a728..49b5dae0ea 100644 --- a/src/reflect/scala/reflect/internal/Types.scala +++ b/src/reflect/scala/reflect/internal/Types.scala @@ -800,7 +800,7 @@ trait Types case TypeRef(_, sym, args) => val that1 = existentialAbstraction(args map (_.typeSymbol), that) (that ne that1) && (this <:< that1) && { - log(s"$this.matchesPattern($that) depended on discarding args and testing <:< $that1") + debuglog(s"$this.matchesPattern($that) depended on discarding args and testing <:< $that1") true } case _ => diff --git a/src/reflect/scala/reflect/internal/Variance.scala b/src/reflect/scala/reflect/internal/Variance.scala index 3480161567..ecc5d99a40 100644 --- a/src/reflect/scala/reflect/internal/Variance.scala +++ b/src/reflect/scala/reflect/internal/Variance.scala @@ -60,8 +60,7 @@ final class Variance private (val flags: Int) extends AnyVal { /** The symbolic annotation used to indicate the given kind of variance. */ def symbolicString = ( - if (isBivariant) "+/-" - else if (isCovariant) "+" + if (isCovariant) "+" else if (isContravariant) "-" else "" ) diff --git a/src/reflect/scala/reflect/internal/Variances.scala b/src/reflect/scala/reflect/internal/Variances.scala index 78df3c9617..bf00a7ac87 100644 --- a/src/reflect/scala/reflect/internal/Variances.scala +++ b/src/reflect/scala/reflect/internal/Variances.scala @@ -92,7 +92,9 @@ trait Variances { val relative = relativeVariance(sym) val required = relative * variance if (!relative.isBivariant) { - log(s"verifying $sym (${sym.variance}${sym.locationString}) is $required at $base in ${base.owner}") + def sym_s = s"$sym (${sym.variance}${sym.locationString})" + def base_s = s"$base in ${base.owner}" + (if (base.owner.isClass) "" else " in " + base.owner.enclClass) + log(s"verifying $sym_s is $required at $base_s") if (sym.variance != required) issueVarianceError(base, sym, required) } @@ -146,7 +148,7 @@ trait Variances { ) tree match { case defn: MemberDef if skip => - log(s"Skipping variance check of ${sym.defString}") + debuglog(s"Skipping variance check of ${sym.defString}") case ClassDef(_, _, _, _) | TypeDef(_, _, _, _) => validateVariance(sym) super.traverse(tree) diff --git a/src/reflect/scala/reflect/internal/tpe/TypeConstraints.scala b/src/reflect/scala/reflect/internal/tpe/TypeConstraints.scala index 927d86380c..fdfe376c18 100644 --- a/src/reflect/scala/reflect/internal/tpe/TypeConstraints.scala +++ b/src/reflect/scala/reflect/internal/tpe/TypeConstraints.scala @@ -6,7 +6,6 @@ package tpe import scala.collection.{ generic } import generic.Clearable - private[internal] trait TypeConstraints { self: SymbolTable => import definitions._ @@ -191,12 +190,17 @@ private[internal] trait TypeConstraints { override def toString = { val boundsStr = { - val lo = loBounds filterNot typeIsNothing - val hi = hiBounds filterNot typeIsAny - val lostr = if (lo.isEmpty) Nil else List(lo.mkString(" >: (", ", ", ")")) - val histr = if (hi.isEmpty) Nil else List(hi.mkString(" <: (", ", ", ")")) - - lostr ++ histr mkString ("[", " | ", "]") + val lo = loBounds filterNot typeIsNothing match { + case Nil => "" + case tp :: Nil => " >: " + tp + case tps => tps.mkString(" >: (", ", ", ")") + } + val hi = hiBounds filterNot typeIsAny match { + case Nil => "" + case tp :: Nil => " <: " + tp + case tps => tps.mkString(" <: (", ", ", ")") + } + lo + hi } if (inst eq NoType) boundsStr else boundsStr + " _= " + inst.safeToString @@ -234,25 +238,25 @@ private[internal] trait TypeConstraints { if (!cyclic) { if (up) { if (bound.typeSymbol != AnyClass) { - log(s"$tvar addHiBound $bound.instantiateTypeParams($tparams, $tvars)") + debuglog(s"$tvar addHiBound $bound.instantiateTypeParams($tparams, $tvars)") tvar addHiBound bound.instantiateTypeParams(tparams, tvars) } for (tparam2 <- tparams) tparam2.info.bounds.lo.dealias match { case TypeRef(_, `tparam`, _) => - log(s"$tvar addHiBound $tparam2.tpeHK.instantiateTypeParams($tparams, $tvars)") + debuglog(s"$tvar addHiBound $tparam2.tpeHK.instantiateTypeParams($tparams, $tvars)") tvar addHiBound tparam2.tpeHK.instantiateTypeParams(tparams, tvars) case _ => } } else { if (bound.typeSymbol != NothingClass && bound.typeSymbol != tparam) { - log(s"$tvar addLoBound $bound.instantiateTypeParams($tparams, $tvars)") + debuglog(s"$tvar addLoBound $bound.instantiateTypeParams($tparams, $tvars)") tvar addLoBound bound.instantiateTypeParams(tparams, tvars) } for (tparam2 <- tparams) tparam2.info.bounds.hi.dealias match { case TypeRef(_, `tparam`, _) => - log(s"$tvar addLoBound $tparam2.tpeHK.instantiateTypeParams($tparams, $tvars)") + debuglog(s"$tvar addLoBound $tparam2.tpeHK.instantiateTypeParams($tparams, $tvars)") tvar addLoBound tparam2.tpeHK.instantiateTypeParams(tparams, tvars) case _ => } diff --git a/src/reflect/scala/reflect/internal/tpe/TypeMaps.scala b/src/reflect/scala/reflect/internal/tpe/TypeMaps.scala index 0d9bbfa5e0..be61c45041 100644 --- a/src/reflect/scala/reflect/internal/tpe/TypeMaps.scala +++ b/src/reflect/scala/reflect/internal/tpe/TypeMaps.scala @@ -17,12 +17,11 @@ private[internal] trait TypeMaps { * so it is no longer carries the too-stealthy name "deAlias". */ object normalizeAliases extends TypeMap { - def apply(tp: Type): Type = tp match { - case TypeRef(_, sym, _) if sym.isAliasType => - def msg = if (tp.isHigherKinded) s"Normalizing type alias function $tp" else s"Dealiasing type alias $tp" - mapOver(logResult(msg)(tp.normalize)) - case _ => mapOver(tp) - } + def apply(tp: Type): Type = mapOver(tp match { + case TypeRef(_, sym, _) if sym.isAliasType && tp.isHigherKinded => logResult(s"Normalized type alias function $tp")(tp.normalize) + case TypeRef(_, sym, _) if sym.isAliasType => tp.normalize + case tp => tp + }) } /** Remove any occurrence of type from this type and its parents */ @@ -944,7 +943,7 @@ private[internal] trait TypeMaps { } } - /** A map to convert every occurrence of a type variable to a wildcard type. */ + /** A map to convert each occurrence of a type variable to its origin. */ object typeVarToOriginMap extends TypeMap { def apply(tp: Type): Type = tp match { case TypeVar(origin, _) => origin -- cgit v1.2.3