Skip to content

Commit

Permalink
Print failures in boundsViolations, via TypeComparer.explaining
Browse files Browse the repository at this point in the history
TypeComparer.explaining is like TypeComparer.explained, but instead of
just returning the trace, returns the result, still allowing the trace
to be accessed via .lastTrace, as exemplified by implementing
TypeComparer.explained in terms of TypeComparer.explaining.

Also add, but leave commented out the call of, a trace.dumpStack, which
is like Thread.dumpStack(), but outputing to System.out, like all our
tracing does - so the two don't interact when unbuffering onto the
terminal.  Also, we can do customisations like filtering out stack
elements, limiting the stack.
  • Loading branch information
dwijnand committed Aug 21, 2024
1 parent 2405109 commit 5aaea2f
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 8 deletions.
12 changes: 8 additions & 4 deletions compiler/src/dotty/tools/dotc/core/TypeComparer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3268,9 +3268,10 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling

/** The trace of comparison operations when performing `op` */
def explained[T](op: ExplainingTypeComparer => T, header: String = "Subtype trace:", short: Boolean)(using Context): String =
val cmp = explainingTypeComparer(short)
inSubComparer(cmp)(op)
cmp.lastTrace(header)
explaining(cmp => { op(cmp); cmp.lastTrace(header) }, short)

def explaining[T](op: ExplainingTypeComparer => T, short: Boolean)(using Context): T =
inSubComparer(explainingTypeComparer(short))(op)

def reduceMatchWith[T](op: MatchReducer => T)(using Context): T =
inSubComparer(matchReducer)(op)
Expand Down Expand Up @@ -3440,6 +3441,9 @@ object TypeComparer {
def explained[T](op: ExplainingTypeComparer => T, header: String = "Subtype trace:", short: Boolean = false)(using Context): String =
comparing(_.explained(op, header, short))

def explaining[T](op: ExplainingTypeComparer => T, short: Boolean = false)(using Context): T =
comparing(_.explaining(op, short))

def reduceMatchWith[T](op: MatchReducer => T)(using Context): T =
comparing(_.reduceMatchWith(op))

Expand Down Expand Up @@ -3873,7 +3877,7 @@ class ExplainingTypeComparer(initctx: Context, short: Boolean) extends TypeCompa
override def recur(tp1: Type, tp2: Type): Boolean =
def moreInfo =
if Config.verboseExplainSubtype || ctx.settings.verbose.value
then s" ${tp1.getClass} ${tp2.getClass}"
then s" ${tp1.className} ${tp2.className}"
else ""
val approx = approxState
def approxStr = if short then "" else approx.show
Expand Down
19 changes: 15 additions & 4 deletions compiler/src/dotty/tools/dotc/core/TypeOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -691,11 +691,22 @@ object TypeOps:
val hiBound = instantiate(bounds.hi, skolemizedArgTypes)
val loBound = instantiate(bounds.lo, skolemizedArgTypes)

def check(using Context) = {
if (!(lo <:< hiBound)) violations += ((arg, "upper", hiBound))
if (!(loBound <:< hi)) violations += ((arg, "lower", loBound))
def check(tp1: Type, tp2: Type, which: String, bound: Type)(using Context) = {
val isSub = TypeComparer.explaining { cmp =>
val isSub = cmp.isSubType(tp1, tp2)
if !isSub then
if !ctx.typerState.constraint.domainLambdas.isEmpty then
typr.println(i"${ctx.typerState.constraint}")
if !ctx.gadt.symbols.isEmpty then
typr.println(i"${ctx.gadt}")
typr.println(cmp.lastTrace(i"checkOverlapsBounds($lo, $hi, $arg, $bounds)($which)"))
//trace.dumpStack()
isSub
}//(using ctx.fresh.setSetting(ctx.settings.verbose, true)) // uncomment to enable moreInfo in ExplainingTypeComparer recur
if !isSub then violations += ((arg, which, bound))
}
check(using checkCtx)
check(lo, hiBound, "upper", hiBound)(using checkCtx)
check(loBound, hi, "lower", loBound)(using checkCtx)
}

def loop(args: List[Tree], boundss: List[TypeBounds]): Unit = args match
Expand Down
12 changes: 12 additions & 0 deletions compiler/src/dotty/tools/dotc/reporting/trace.scala
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,18 @@ object trace extends TraceSyntax:
object log extends TraceSyntax:
inline def isEnabled: true = true
protected val isForced = false

def dumpStack(limit: Int = -1): Unit = {
val out = Console.out
val exc = new Exception("Dump Stack")
var stack = exc.getStackTrace
.filter(e => !e.getClassName.startsWith("dotty.tools.dotc.reporting.TraceSyntax"))
.filter(e => !e.getClassName.startsWith("dotty.tools.dotc.reporting.trace"))
if limit >= 0 then
stack = stack.take(limit)
exc.setStackTrace(stack)
exc.printStackTrace(out)
}
end trace

/** This module is carefully optimized to give zero overhead if Config.tracingEnabled
Expand Down

0 comments on commit 5aaea2f

Please sign in to comment.