@@ -59,7 +59,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
5959 private var monitored = false
6060
6161 private var maxErrorLevel : Int = - 1
62- private var errorNotes : List [(Int , ErrorNote )] = Nil
62+ protected var errorNotes : List [(Int , ErrorNote )] = Nil
6363
6464 private var needsGc = false
6565
@@ -433,7 +433,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
433433 case _ =>
434434 if isCaptureVarComparison then
435435 return CCState .withCapAsRoot:
436- subCaptures(tp1.captureSet, tp2.captureSet).isOK
436+ subCaptures(tp1.captureSet, tp2.captureSet)
437437 if (tp1 eq NothingType ) || isBottom(tp1) then
438438 return true
439439 }
@@ -541,7 +541,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
541541 case tp1 @ CapturingType (parent1, refs1) =>
542542 def compareCapturing =
543543 if tp2.isAny then true
544- else if subCaptures(refs1, tp2.captureSet).isOK && sameBoxed(tp1, tp2, refs1)
544+ else if subCaptures(refs1, tp2.captureSet) && sameBoxed(tp1, tp2, refs1)
545545 || ! ctx.mode.is(Mode .CheckBoundsOrSelfType ) && tp1.isAlwaysPure
546546 then
547547 val tp2a =
@@ -583,7 +583,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
583583
584584 if isCaptureVarComparison then
585585 return CCState .withCapAsRoot:
586- subCaptures(tp1.captureSet, tp2.captureSet).isOK
586+ subCaptures(tp1.captureSet, tp2.captureSet)
587587
588588 isSubApproxHi(tp1, info2.lo) && (trustBounds || isSubApproxHi(tp1, info2.hi))
589589 || compareGADT
@@ -668,12 +668,12 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
668668 && isSubInfo(info1.resultType, info2.resultType.subst(info2, info1))
669669 case (info1 @ CapturingType (parent1, refs1), info2 : Type )
670670 if info2.stripCapturing.isInstanceOf [MethodOrPoly ] =>
671- subCaptures(refs1, info2.captureSet).isOK && sameBoxed(info1, info2, refs1)
671+ subCaptures(refs1, info2.captureSet) && sameBoxed(info1, info2, refs1)
672672 && isSubInfo(parent1, info2)
673673 case (info1 : Type , CapturingType (parent2, refs2))
674674 if info1.stripCapturing.isInstanceOf [MethodOrPoly ] =>
675675 val refs1 = info1.captureSet
676- (refs1.isAlwaysEmpty || subCaptures(refs1, refs2).isOK ) && sameBoxed(info1, info2, refs1)
676+ (refs1.isAlwaysEmpty || subCaptures(refs1, refs2)) && sameBoxed(info1, info2, refs1)
677677 && isSubInfo(info1, parent2)
678678 case _ =>
679679 isSubType(info1, info2)
@@ -867,12 +867,12 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
867867 // Eamples where this arises is capt-capibility.scala and function-combinators.scala
868868 val singletonOK = tp1 match
869869 case tp1 : SingletonType
870- if subCaptures(tp1.underlying.captureSet, refs2, CaptureSet .VarState .Separate ).isOK =>
870+ if subCaptures(tp1.underlying.captureSet, refs2, CaptureSet .VarState .Separate ) =>
871871 recur(tp1.widen, tp2)
872872 case _ =>
873873 false
874874 singletonOK
875- || subCaptures(refs1, refs2).isOK
875+ || subCaptures(refs1, refs2)
876876 && sameBoxed(tp1, tp2, refs1)
877877 && (recur(tp1.widen.stripCapturing, parent2)
878878 || tp1.isInstanceOf [SingletonType ] && recur(tp1, parent2)
@@ -2830,7 +2830,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
28302830 if frozenConstraint then CaptureSet .VarState .Closed () else CaptureSet .VarState ()
28312831
28322832 protected def subCaptures (refs1 : CaptureSet , refs2 : CaptureSet ,
2833- vs : CaptureSet .VarState = makeVarState())(using Context ): CaptureSet . CompareResult =
2833+ vs : CaptureSet .VarState = makeVarState())(using Context ): Boolean =
28342834 try
28352835 refs1.subCaptures(refs2, vs)
28362836 catch case ex : AssertionError =>
@@ -2843,7 +2843,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
28432843 */
28442844 protected def sameBoxed (tp1 : Type , tp2 : Type , refs1 : CaptureSet )(using Context ): Boolean =
28452845 (tp1.isBoxedCapturing == tp2.isBoxedCapturing)
2846- || refs1.subCaptures(CaptureSet .empty, makeVarState()).isOK
2846+ || refs1.subCaptures(CaptureSet .empty, makeVarState())
28472847
28482848 // ----------- Diagnostics --------------------------------------------------
28492849
@@ -3254,16 +3254,40 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
32543254 * the same class as `note`.
32553255 */
32563256 def addErrorNote (note : ErrorNote ): Unit =
3257- if errorNotes.forall(_._2.getClass != note.getClass ) then
3257+ if errorNotes.forall(_._2.kind != note.kind ) then
32583258 errorNotes = (recCount, note) :: errorNotes
32593259 assert(maxErrorLevel <= recCount)
32603260 maxErrorLevel = recCount
3261+
3262+ private [TypeComparer ] inline
3263+ def isolated [T ](inline op : Boolean , inline mapResult : Boolean => T )(using Context ): T =
3264+ val savedNotes = errorNotes
3265+ val savedLevel = maxErrorLevel
3266+ errorNotes = Nil
3267+ maxErrorLevel = - 1
3268+ try mapResult(op)
3269+ finally
3270+ errorNotes = savedNotes
3271+ maxErrorLevel = savedLevel
3272+
3273+ /** Run `op` on current type comparer, maping its Boolean result to
3274+ * a CompareResult with possible outcomes OK and Fail(...)`. In case
3275+ * of failure pass the accumulated errorNotes of this type comparer to
3276+ * in the Fail value.
3277+ */
3278+ def compareResult (op : => Boolean )(using Context ): CompareResult =
3279+ isolated(op, res =>
3280+ if res then CompareResult .OK else CompareResult .Fail (errorNotes.map(_._2)))
32613281}
32623282
32633283object TypeComparer {
32643284
32653285 /** A base trait for data producing addenda to error messages */
3266- trait ErrorNote
3286+ trait ErrorNote :
3287+ /** A disciminating kind. An error note is not added if it has the same kind
3288+ * as an already existing error note.
3289+ */
3290+ def kind : Class [? ] = getClass
32673291
32683292 /** A richer compare result, returned by `testSubType` and `test`. */
32693293 enum CompareResult :
@@ -3280,7 +3304,6 @@ object TypeComparer {
32803304 else res match
32813305 case ClassInfo (_, cls, _, _, _) => cls.showLocated
32823306 case bounds : TypeBounds => i " type bounds [ $bounds] "
3283- case CaptureSet .CompareResult .OK => " OK"
32843307 case res : printing.Showable => res.show
32853308 case _ => String .valueOf(res).nn
32863309
@@ -3435,7 +3458,7 @@ object TypeComparer {
34353458 def reduceMatchWith [T ](op : MatchReducer => T )(using Context ): T =
34363459 comparing(_.reduceMatchWith(op))
34373460
3438- def subCaptures (refs1 : CaptureSet , refs2 : CaptureSet , vs : CaptureSet .VarState )(using Context ): CaptureSet . CompareResult =
3461+ def subCaptures (refs1 : CaptureSet , refs2 : CaptureSet , vs : CaptureSet .VarState )(using Context ): Boolean =
34393462 comparing(_.subCaptures(refs1, refs2, vs))
34403463
34413464 def inNestedLevel (op : => Boolean )(using Context ): Boolean =
@@ -3444,15 +3467,16 @@ object TypeComparer {
34443467 def addErrorNote (note : ErrorNote )(using Context ): Unit =
34453468 comparer.addErrorNote(note)
34463469
3447- /** Run `op` on current type comparer, maping its Boolean result to
3448- * a CompareResult with possible outcomes OK and Fail(...)`. In case
3449- * of failure pass the accumulated errorNotes of this type comparer to
3450- * in the Fail value.
3451- */
3452- def test (op : => Boolean )(using Context ): CompareResult =
3453- comparing : comparer =>
3454- if op then CompareResult .OK
3455- else CompareResult .Fail (comparer.errorNotes.map(_._2))
3470+ def updateErrorNotes (f : PartialFunction [ErrorNote , ErrorNote ])(using Context ): Unit =
3471+ comparer.errorNotes = comparer.errorNotes.mapConserve: p =>
3472+ val (level, note) = p
3473+ if f.isDefinedAt(note) then (level, f(note)) else p
3474+
3475+ def compareResult (op : => Boolean )(using Context ): CompareResult =
3476+ comparing(_.compareResult(op))
3477+
3478+ inline def noNotes (inline op : Boolean )(using Context ): Boolean =
3479+ comparer.isolated(op, x => x)
34563480}
34573481
34583482object MatchReducer :
@@ -3857,9 +3881,11 @@ class ExplainingTypeComparer(initctx: Context, short: Boolean) extends TypeCompa
38573881 private val b = new StringBuilder
38583882 private var lastForwardGoal : String | Null = null
38593883
3860- private def appendFailure (x : String ) =
3884+ private def appendFailure (notes : List [ ErrorNote ] ) =
38613885 if lastForwardGoal != null then // last was deepest goal that failed
3862- b.append(s " = $x" )
3886+ b.append(s " = false " )
3887+ for case note : printing.Showable <- notes do
3888+ b.append(i " : $note" )
38633889 lastForwardGoal = null
38643890
38653891 override def traceIndented [T ](str : String )(op : => T ): T =
@@ -3875,9 +3901,9 @@ class ExplainingTypeComparer(initctx: Context, short: Boolean) extends TypeCompa
38753901 if short then
38763902 res match
38773903 case false =>
3878- appendFailure(" false " )
3879- case res : CaptureSet . CompareResult if res != CaptureSet . CompareResult . OK =>
3880- appendFailure(show(res) )
3904+ appendFailure(errorNotes.map(_._2) )
3905+ case CompareResult . Fail (notes) =>
3906+ appendFailure(notes )
38813907 case _ =>
38823908 b.length = curLength // don't show successful subtraces
38833909 else
@@ -3927,7 +3953,7 @@ class ExplainingTypeComparer(initctx: Context, short: Boolean) extends TypeCompa
39273953 super .gadtAddBound(sym, b, isUpper)
39283954 }
39293955
3930- override def subCaptures (refs1 : CaptureSet , refs2 : CaptureSet , vs : CaptureSet .VarState )(using Context ): CaptureSet . CompareResult =
3956+ override def subCaptures (refs1 : CaptureSet , refs2 : CaptureSet , vs : CaptureSet .VarState )(using Context ): Boolean =
39313957 traceIndented(i " subcaptures $refs1 <:< $refs2 in ${vs.toString}" ) {
39323958 super .subCaptures(refs1, refs2, vs)
39333959 }
0 commit comments