Skip to content

Commit 2182af4

Browse files
dwijnandWojciechMazur
authored andcommitted
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]
1 parent d9c8048 commit 2182af4

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
@@ -3133,9 +3133,10 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
31333133

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

31403141
def reduceMatchWith[T](op: MatchReducer => T)(using Context): T =
31413142
inSubComparer(matchReducer)(op)
@@ -3305,6 +3306,9 @@ object TypeComparer {
33053306
def explained[T](op: ExplainingTypeComparer => T, header: String = "Subtype trace:", short: Boolean = false)(using Context): String =
33063307
comparing(_.explained(op, header, short))
33073308

3309+
def explaining[T](op: ExplainingTypeComparer => T, short: Boolean = false)(using Context): T =
3310+
comparing(_.explaining(op, short))
3311+
33083312
def reduceMatchWith[T](op: MatchReducer => T)(using Context): T =
33093313
comparing(_.reduceMatchWith(op))
33103314

@@ -3729,7 +3733,7 @@ class ExplainingTypeComparer(initctx: Context, short: Boolean) extends TypeCompa
37293733
override def recur(tp1: Type, tp2: Type): Boolean =
37303734
def moreInfo =
37313735
if Config.verboseExplainSubtype || ctx.settings.verbose.value
3732-
then s" ${tp1.getClass} ${tp2.getClass}"
3736+
then s" ${tp1.className} ${tp2.className}"
37333737
else ""
37343738
val approx = approxState
37353739
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)