Skip to content

Commit df0bb26

Browse files
committed
Print failures in boundsViolations, via TypeComparer.explaining
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. [Cherry-picked 5aaea2f][modified]
1 parent 85360f3 commit df0bb26

File tree

3 files changed

+35
-8
lines changed

3 files changed

+35
-8
lines changed

Diff for: compiler/src/dotty/tools/dotc/core/TypeComparer.scala

+8-4
Original file line numberDiff line numberDiff line change
@@ -2945,9 +2945,10 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
29452945

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

29522953
def tracked[T](op: TrackingTypeComparer => T)(using Context): T =
29532954
inSubComparer(trackingTypeComparer)(op)
@@ -3107,6 +3108,9 @@ object TypeComparer {
31073108
def explained[T](op: ExplainingTypeComparer => T, header: String = "Subtype trace:", short: Boolean = false)(using Context): String =
31083109
comparing(_.explained(op, header, short))
31093110

3111+
def explaining[T](op: ExplainingTypeComparer => T, short: Boolean = false)(using Context): T =
3112+
comparing(_.explaining(op, short))
3113+
31103114
def tracked[T](op: TrackingTypeComparer => T)(using Context): T =
31113115
comparing(_.tracked(op))
31123116
}
@@ -3321,7 +3325,7 @@ class ExplainingTypeComparer(initctx: Context, short: Boolean) extends TypeCompa
33213325
override def recur(tp1: Type, tp2: Type): Boolean =
33223326
def moreInfo =
33233327
if Config.verboseExplainSubtype || ctx.settings.verbose.value
3324-
then s" ${tp1.getClass} ${tp2.getClass}"
3328+
then s" ${tp1.className} ${tp2.className}"
33253329
else ""
33263330
val approx = approxState
33273331
def approxStr = if short then "" else approx.show

Diff for: compiler/src/dotty/tools/dotc/core/TypeOps.scala

+15-4
Original file line numberDiff line numberDiff line change
@@ -704,11 +704,22 @@ object TypeOps:
704704
val hiBound = instantiate(bounds.hi, skolemizedArgTypes)
705705
val loBound = instantiate(bounds.lo, skolemizedArgTypes)
706706

707-
def check(using Context) = {
708-
if (!(lo <:< hiBound)) violations += ((arg, "upper", hiBound))
709-
if (!(loBound <:< hi)) violations += ((arg, "lower", loBound))
707+
def check(tp1: Type, tp2: Type, which: String, bound: Type)(using Context) = {
708+
val isSub = TypeComparer.explaining { cmp =>
709+
val isSub = cmp.isSubType(tp1, tp2)
710+
if !isSub then
711+
if !ctx.typerState.constraint.domainLambdas.isEmpty then
712+
typr.println(i"${ctx.typerState.constraint}")
713+
if !ctx.gadt.symbols.isEmpty then
714+
typr.println(i"${ctx.gadt}")
715+
typr.println(cmp.lastTrace(i"checkOverlapsBounds($lo, $hi, $arg, $bounds)($which)"))
716+
//trace.dumpStack()
717+
isSub
718+
}//(using ctx.fresh.setSetting(ctx.settings.verbose, true)) // uncomment to enable moreInfo in ExplainingTypeComparer recur
719+
if !isSub then violations += ((arg, which, bound))
710720
}
711-
check(using checkCtx)
721+
check(lo, hiBound, "upper", hiBound)(using checkCtx)
722+
check(loBound, hi, "lower", loBound)(using checkCtx)
712723
}
713724

714725
def loop(args: List[Tree], boundss: List[TypeBounds]): Unit = args match

Diff for: compiler/src/dotty/tools/dotc/reporting/trace.scala

+12
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,18 @@ object trace extends TraceSyntax:
2727
object log extends TraceSyntax:
2828
inline def isEnabled: true = true
2929
protected val isForced = false
30+
31+
def dumpStack(limit: Int = -1): Unit = {
32+
val out = Console.out
33+
val exc = new Exception("Dump Stack")
34+
var stack = exc.getStackTrace
35+
.filter(e => !e.getClassName.startsWith("dotty.tools.dotc.reporting.TraceSyntax"))
36+
.filter(e => !e.getClassName.startsWith("dotty.tools.dotc.reporting.trace"))
37+
if limit >= 0 then
38+
stack = stack.take(limit)
39+
exc.setStackTrace(stack)
40+
exc.printStackTrace(out)
41+
}
3042
end trace
3143

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

0 commit comments

Comments
 (0)