Skip to content

Commit 5aaea2f

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.
1 parent 2405109 commit 5aaea2f

File tree

3 files changed

+35
-8
lines changed

3 files changed

+35
-8
lines changed

compiler/src/dotty/tools/dotc/core/TypeComparer.scala

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3268,9 +3268,10 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
32683268

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

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

3444+
def explaining[T](op: ExplainingTypeComparer => T, short: Boolean = false)(using Context): T =
3445+
comparing(_.explaining(op, short))
3446+
34433447
def reduceMatchWith[T](op: MatchReducer => T)(using Context): T =
34443448
comparing(_.reduceMatchWith(op))
34453449

@@ -3873,7 +3877,7 @@ class ExplainingTypeComparer(initctx: Context, short: Boolean) extends TypeCompa
38733877
override def recur(tp1: Type, tp2: Type): Boolean =
38743878
def moreInfo =
38753879
if Config.verboseExplainSubtype || ctx.settings.verbose.value
3876-
then s" ${tp1.getClass} ${tp2.getClass}"
3880+
then s" ${tp1.className} ${tp2.className}"
38773881
else ""
38783882
val approx = approxState
38793883
def approxStr = if short then "" else approx.show

compiler/src/dotty/tools/dotc/core/TypeOps.scala

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -691,11 +691,22 @@ object TypeOps:
691691
val hiBound = instantiate(bounds.hi, skolemizedArgTypes)
692692
val loBound = instantiate(bounds.lo, skolemizedArgTypes)
693693

694-
def check(using Context) = {
695-
if (!(lo <:< hiBound)) violations += ((arg, "upper", hiBound))
696-
if (!(loBound <:< hi)) violations += ((arg, "lower", loBound))
694+
def check(tp1: Type, tp2: Type, which: String, bound: Type)(using Context) = {
695+
val isSub = TypeComparer.explaining { cmp =>
696+
val isSub = cmp.isSubType(tp1, tp2)
697+
if !isSub then
698+
if !ctx.typerState.constraint.domainLambdas.isEmpty then
699+
typr.println(i"${ctx.typerState.constraint}")
700+
if !ctx.gadt.symbols.isEmpty then
701+
typr.println(i"${ctx.gadt}")
702+
typr.println(cmp.lastTrace(i"checkOverlapsBounds($lo, $hi, $arg, $bounds)($which)"))
703+
//trace.dumpStack()
704+
isSub
705+
}//(using ctx.fresh.setSetting(ctx.settings.verbose, true)) // uncomment to enable moreInfo in ExplainingTypeComparer recur
706+
if !isSub then violations += ((arg, which, bound))
697707
}
698-
check(using checkCtx)
708+
check(lo, hiBound, "upper", hiBound)(using checkCtx)
709+
check(loBound, hi, "lower", loBound)(using checkCtx)
699710
}
700711

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

compiler/src/dotty/tools/dotc/reporting/trace.scala

Lines changed: 12 additions & 0 deletions
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)