diff options
author | Adriaan Moors <adriaan.moors@typesafe.com> | 2013-08-27 10:11:08 -0700 |
---|---|---|
committer | Adriaan Moors <adriaan.moors@typesafe.com> | 2013-08-27 10:11:08 -0700 |
commit | 7817efe2468480317965fc5baece52be392f0f7a (patch) | |
tree | c5cbf391f48d26bc15d8380ea13d771271eaabd3 /src | |
parent | a3fad0d1d42b4af4b506ce167209bdeea5cd9d5c (diff) | |
parent | 7d83be218473f08ab560c937318faadce2617d95 (diff) | |
download | scala-7817efe2468480317965fc5baece52be392f0f7a.tar.gz scala-7817efe2468480317965fc5baece52be392f0f7a.tar.bz2 scala-7817efe2468480317965fc5baece52be392f0f7a.zip |
Merge pull request #2874 from paulp/pr/depth
Value class Depth.
Diffstat (limited to 'src')
26 files changed, 254 insertions, 226 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/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/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..03f680525c 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 { @@ -174,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) @@ -554,10 +542,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 +1015,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 +1087,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 @@ -1110,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/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/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 b4ae384594..49b5dae0ea 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)) } } @@ -805,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 _ => @@ -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/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/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..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._ @@ -170,11 +169,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? @@ -188,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 @@ -208,12 +215,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) { @@ -236,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 _ => } @@ -265,12 +267,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 +284,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/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 <singleton> 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 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 |