Skip to content

Commit

Permalink
Make -Ytyper-debug output readable.
Browse files Browse the repository at this point in the history
  • Loading branch information
paulp authored and soc committed Jul 17, 2013
1 parent aeb7331 commit 4d6be05
Show file tree
Hide file tree
Showing 26 changed files with 517 additions and 333 deletions.
7 changes: 3 additions & 4 deletions src/compiler/scala/tools/nsc/Global.scala
Expand Up @@ -70,6 +70,9 @@ class Global(var currentSettings: Settings, var reporter: Reporter)

override def settings = currentSettings

/** Switch to turn on detailed type logs */
var printTypings = settings.Ytyperdebug.value

def this(reporter: Reporter) =
this(new Settings(err => reporter.error(null, err)), reporter)

Expand Down Expand Up @@ -417,10 +420,6 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
}
}

/** Switch to turn on detailed type logs */
val printTypings = settings.Ytyperdebug.value
val printInfers = settings.Yinferdebug.value

// phaseName = "parser"
lazy val syntaxAnalyzer = new {
val global: Global.this.type = Global.this
Expand Down
10 changes: 5 additions & 5 deletions src/compiler/scala/tools/nsc/typechecker/Contexts.scala
Expand Up @@ -267,10 +267,6 @@ trait Contexts { self: Analyzer =>
/** Saved type bounds for type parameters which are narrowed in a GADT. */
var savedTypeBounds: List[(Symbol, Type)] = List()

/** Indentation level, in columns, for output under -Ytyper-debug */
var typingIndentLevel: Int = 0
def typingIndent = " " * typingIndentLevel

/** The next enclosing context (potentially `this`) that is owned by a class or method */
def enclClassOrMethod: Context =
if ((owner eq NoSymbol) || (owner.isClass) || (owner.isMethod)) this
Expand All @@ -282,6 +278,11 @@ trait Contexts { self: Analyzer =>
/** ...or an Apply. */
def enclosingApply = nextEnclosing(_.tree.isInstanceOf[Apply])

def siteString = {
def what_s = if (owner.isConstructor) "" else owner.kindString
def where_s = if (owner.isClass) "" else "in " + enclClass.owner.decodedName
List(what_s, owner.decodedName, where_s) filterNot (_ == "") mkString " "
}
//
// Tracking undetermined type parameters for type argument inference.
//
Expand Down Expand Up @@ -445,7 +446,6 @@ trait Contexts { self: Analyzer =>
// Fields that are directly propagated
c.variance = variance
c.diagnostic = diagnostic
c.typingIndentLevel = typingIndentLevel
c.openImplicits = openImplicits
c.contextMode = contextMode // note: ConstructorSuffix, a bit within `mode`, is conditionally overwritten below.
c._reportBuffer = reportBuffer
Expand Down
127 changes: 41 additions & 86 deletions src/compiler/scala/tools/nsc/typechecker/Implicits.scala
Expand Up @@ -31,8 +31,8 @@ trait Implicits {
import global._
import definitions._
import ImplicitsStats._
import typeDebug.{ ptBlock, ptLine }
import global.typer.{ printTyping, deindentTyping, indentTyping, printInference }
import typingStack.{ printTyping }
import typeDebug._

def inferImplicit(tree: Tree, pt: Type, reportAmbiguous: Boolean, isView: Boolean, context: Context): SearchResult =
inferImplicit(tree, pt, reportAmbiguous, isView, context, saveAmbiguousDivergent = true, tree.pos)
Expand Down Expand Up @@ -60,25 +60,13 @@ trait Implicits {
* @return A search result
*/
def inferImplicit(tree: Tree, pt: Type, reportAmbiguous: Boolean, isView: Boolean, context: Context, saveAmbiguousDivergent: Boolean, pos: Position): SearchResult = {
printInference("[infer %s] %s with pt=%s in %s".format(
if (isView) "view" else "implicit",
tree, pt, context.owner.enclClass)
)
printTyping(
ptBlock("infer implicit" + (if (isView) " view" else ""),
"tree" -> tree,
"pt" -> pt,
"undetparams" -> context.outer.undetparams
)
)
indentTyping()

val shouldPrint = printTypings && !context.undetparams.isEmpty
val rawTypeStart = if (Statistics.canEnable) Statistics.startCounter(rawTypeImpl) else null
val findMemberStart = if (Statistics.canEnable) Statistics.startCounter(findMemberImpl) else null
val subtypeStart = if (Statistics.canEnable) Statistics.startCounter(subtypeImpl) else null
val start = if (Statistics.canEnable) Statistics.startTimer(implicitNanos) else null
if (printInfers && !tree.isEmpty && !context.undetparams.isEmpty)
printTyping("typing implicit: %s %s".format(tree, context.undetparamsString))
if (shouldPrint)
typingStack.printTyping(tree, "typing implicit: %s %s".format(tree, context.undetparamsString))
val implicitSearchContext = context.makeImplicit(reportAmbiguous)
val result = new ImplicitSearch(tree, pt, isView, implicitSearchContext, pos).bestImplicit
if (result.isFailure && saveAmbiguousDivergent && implicitSearchContext.hasErrors) {
Expand All @@ -88,15 +76,13 @@ trait Implicits {
})
debuglog("update buffer: " + implicitSearchContext.reportBuffer.errors)
}
printInference("[infer implicit] inferred " + result)
context.undetparams = context.undetparams filterNot result.subst.from.contains

if (Statistics.canEnable) Statistics.stopTimer(implicitNanos, start)
if (Statistics.canEnable) Statistics.stopCounter(rawTypeImpl, rawTypeStart)
if (Statistics.canEnable) Statistics.stopCounter(findMemberImpl, findMemberStart)
if (Statistics.canEnable) Statistics.stopCounter(subtypeImpl, subtypeStart)
deindentTyping()
printTyping("Implicit search yielded: "+ result)

result
}

Expand Down Expand Up @@ -143,6 +129,7 @@ trait Implicits {
private val implicitsCache = new LinkedHashMap[Type, Infoss]
private val infoMapCache = new LinkedHashMap[Symbol, InfoMap]
private val improvesCache = perRunCaches.newMap[(ImplicitInfo, ImplicitInfo), Boolean]()
private val implicitSearchId = { var id = 1 ; () => try id finally id += 1 }

private def isInvalidConversionTarget(tpe: Type): Boolean = tpe match {
case Function1(_, out) => AnyRefClass.tpe <:< out
Expand Down Expand Up @@ -325,27 +312,30 @@ trait Implicits {
* (useful when we infer synthetic stuff and pass EmptyTree in the `tree` argument)
* If it's set to NoPosition, then position-based services will use `tree.pos`
*/
class ImplicitSearch(tree: Tree, pt: Type, isView: Boolean, context0: Context, pos0: Position = NoPosition)
extends Typer(context0) with ImplicitsContextErrors {
printTyping(
ptBlock("new ImplicitSearch",
"tree" -> tree,
"pt" -> pt,
"isView" -> isView,
"context0" -> context0,
"undetparams" -> context.outer.undetparams
)
)
// assert(tree.isEmpty || tree.pos.isDefined, tree)
class ImplicitSearch(tree: Tree, pt: Type, isView: Boolean, context0: Context, pos0: Position = NoPosition) extends Typer(context0) with ImplicitsContextErrors {
val searchId = implicitSearchId()
private def typingLog(what: String, msg: String) =
typingStack.printTyping(tree, f"[search #$searchId] $what $msg")

import infer._
if (Statistics.canEnable) Statistics.incCounter(implicitSearchCount)

/** The type parameters to instantiate */
val undetParams = if (isView) Nil else context.outer.undetparams
val wildPt = approximate(pt)

def undet_s = if (undetParams.isEmpty) "" else undetParams.mkString(" inferring ", ", ", "")
def tree_s = typeDebug ptTree tree
def ctx_s = fullSiteString(context)
typingLog("start", s"`$tree_s`$undet_s, searching for adaptation to pt=$pt $ctx_s")

def pos = if (pos0 != NoPosition) pos0 else tree.pos

def failure(what: Any, reason: String, pos: Position = this.pos): SearchResult = {
if (settings.XlogImplicits)
reporter.echo(pos, what+" is not a valid implicit value for "+pt+" because:\n"+reason)
SearchFailure
}

import infer._
/** Is implicit info `info1` better than implicit info `info2`?
*/
def improves(info1: ImplicitInfo, info2: ImplicitInfo) = {
Expand Down Expand Up @@ -418,14 +408,8 @@ trait Implicits {
overlaps(dtor1, dted1) && (dtor1 =:= dted1 || complexity(dtor1) > complexity(dted1))
}

if (Statistics.canEnable) Statistics.incCounter(implicitSearchCount)

/** The type parameters to instantiate */
val undetParams = if (isView) List() else context.outer.undetparams

/** The expected type with all undetermined type parameters replaced with wildcards. */
def approximate(tp: Type) = deriveTypeWithWildcards(undetParams)(tp)
val wildPt = approximate(pt)

/** Try to construct a typed tree from given implicit info with given
* expected type.
Expand Down Expand Up @@ -582,22 +566,12 @@ trait Implicits {

private def typedImplicit0(info: ImplicitInfo, ptChecked: Boolean, isLocal: Boolean): SearchResult = {
if (Statistics.canEnable) Statistics.incCounter(plausiblyCompatibleImplicits)
printTyping (
ptBlock("typedImplicit0",
"info.name" -> info.name,
"ptChecked" -> ptChecked,
"pt" -> wildPt,
"orig" -> ptBlock("info",
"undetParams" -> undetParams,
"info.pre" -> info.pre
).replaceAll("\\n", "\n ")
)
)

if (ptChecked || matchesPt(info))
typedImplicit1(info, isLocal)
else
SearchFailure
val ok = ptChecked || matchesPt(info) && {
def word = if (isLocal) "local " else ""
typingLog("match", s"$word$info")
true
}
if (ok) typedImplicit1(info, isLocal) else SearchFailure
}

private def typedImplicit1(info: ImplicitInfo, isLocal: Boolean): SearchResult = {
Expand All @@ -618,9 +592,7 @@ trait Implicits {
Select(gen.mkAttributedQualifier(info.pre), implicitMemberName)
}
}
printTyping("typedImplicit1 %s, pt=%s, from implicit %s:%s".format(
typeDebug.ptTree(itree), wildPt, info.name, info.tpe)
)
typingLog("considering", typeDebug.ptTree(itree))

def fail(reason: String): SearchResult = failure(itree, reason)
def fallback = typed1(itree, EXPRmode, wildPt)
Expand All @@ -643,13 +615,10 @@ trait Implicits {

if (Statistics.canEnable) Statistics.incCounter(typedImplicits)

printTyping("typed implicit %s:%s, pt=%s".format(itree1, itree1.tpe, wildPt))
val itree2 = if (isView) (itree1: @unchecked) match { case Apply(fun, _) => fun }
else adapt(itree1, EXPRmode, wildPt)

printTyping("adapted implicit %s:%s to %s".format(
itree1.symbol, itree2.tpe, wildPt)
)
typingStack.showAdapt(itree, itree2, pt, context)

def hasMatchingSymbol(tree: Tree): Boolean = (tree.symbol == info.sym) || {
tree match {
Expand All @@ -669,15 +638,9 @@ trait Implicits {
val tvars = undetParams map freshVar
def ptInstantiated = pt.instantiateTypeParams(undetParams, tvars)

printInference("[search] considering %s (pt contains %s) trying %s against pt=%s".format(
if (undetParams.isEmpty) "no tparams" else undetParams.map(_.name).mkString(", "),
typeVarsInType(ptInstantiated) filterNot (_.isGround) match { case Nil => "no tvars" ; case tvs => tvs.mkString(", ") },
itree2.tpe, pt
))

if (matchesPt(itree2.tpe, ptInstantiated, undetParams)) {
if (tvars.nonEmpty)
printTyping(ptLine("" + info.sym, "tvars" -> tvars, "tvars.constr" -> tvars.map(_.constr)))
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)))
Expand Down Expand Up @@ -729,7 +692,7 @@ trait Implicits {
case None =>
val result = new SearchResult(itree2, subst)
if (Statistics.canEnable) Statistics.incCounter(foundImplicits)
printInference("[success] found %s for pt %s".format(result, ptInstantiated))
typingLog("success", s"inferred value of type $ptInstantiated is $result")
result
}
}
Expand Down Expand Up @@ -868,10 +831,7 @@ trait Implicits {
matches sortBy (x => if (isView) -x.useCountView else -x.useCountArg)
}
if (eligible.nonEmpty)
printInference("[search%s] %s with pt=%s in %s, eligible:\n %s".format(
if (isView) " view" else "",
tree, pt, context.owner.enclClass, eligible.mkString("\n "))
)
printTyping(tree, eligible.size + s" eligible for pt=$pt at ${fullSiteString(context)}")

/** Faster implicit search. Overall idea:
* - prune aggressively
Expand All @@ -898,10 +858,7 @@ trait Implicits {
try improves(i, alt)
catch {
case e: CyclicReference =>
if (printInfers) {
println(i+" discarded because cyclic reference occurred")
e.printStackTrace()
}
debugwarn(s"Discarding $i during implicit search due to cyclic reference")
true
}
})
Expand Down Expand Up @@ -1044,9 +1001,7 @@ trait Implicits {
tp match {
case TypeRef(pre, sym, args) =>
if (sym.isClass) {
if (!((sym.name == tpnme.REFINE_CLASS_NAME) ||
(sym.name startsWith tpnme.ANON_CLASS_NAME) ||
(sym.name == tpnme.ROOT))) {
if (!sym.isAnonOrRefinementClass && !sym.isRoot) {
if (sym.isStatic && !(pending contains sym))
infoMap ++= {
infoMapCache get sym match {
Expand All @@ -1060,7 +1015,7 @@ trait Implicits {
}
else
getClassParts(tp)
args foreach (getParts(_))
args foreach getParts
}
} else if (sym.isAliasType) {
getParts(tp.normalize) // SI-7180 Normalize needed to expand HK type refs
Expand Down Expand Up @@ -1088,9 +1043,9 @@ trait Implicits {

val infoMap = new InfoMap
getParts(tp)(infoMap, new mutable.HashSet(), Set())
printInference(
ptBlock("companionImplicitMap " + tp, infoMap.toSeq.map({ case (k, v) => ("" + k, v.mkString(", ")) }): _*)
)
if (infoMap.nonEmpty)
printTyping(tree, infoMap.size + " implicits in companion scope")

infoMap
}

Expand Down

0 comments on commit 4d6be05

Please sign in to comment.