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/compiler/scala | |
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/compiler/scala')
14 files changed, 72 insertions, 76 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 |