@@ -59,7 +59,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
59
59
private var monitored = false
60
60
61
61
private var maxErrorLevel : Int = - 1
62
- private var errorNotes : List [(Int , ErrorNote )] = Nil
62
+ protected var errorNotes : List [(Int , ErrorNote )] = Nil
63
63
64
64
private var needsGc = false
65
65
@@ -433,7 +433,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
433
433
case _ =>
434
434
if isCaptureVarComparison then
435
435
return CCState .withCapAsRoot:
436
- subCaptures(tp1.captureSet, tp2.captureSet).isOK
436
+ subCaptures(tp1.captureSet, tp2.captureSet)
437
437
if (tp1 eq NothingType ) || isBottom(tp1) then
438
438
return true
439
439
}
@@ -541,7 +541,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
541
541
case tp1 @ CapturingType (parent1, refs1) =>
542
542
def compareCapturing =
543
543
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)
545
545
|| ! ctx.mode.is(Mode .CheckBoundsOrSelfType ) && tp1.isAlwaysPure
546
546
then
547
547
val tp2a =
@@ -583,7 +583,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
583
583
584
584
if isCaptureVarComparison then
585
585
return CCState .withCapAsRoot:
586
- subCaptures(tp1.captureSet, tp2.captureSet).isOK
586
+ subCaptures(tp1.captureSet, tp2.captureSet)
587
587
588
588
isSubApproxHi(tp1, info2.lo) && (trustBounds || isSubApproxHi(tp1, info2.hi))
589
589
|| compareGADT
@@ -668,12 +668,12 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
668
668
&& isSubInfo(info1.resultType, info2.resultType.subst(info2, info1))
669
669
case (info1 @ CapturingType (parent1, refs1), info2 : Type )
670
670
if info2.stripCapturing.isInstanceOf [MethodOrPoly ] =>
671
- subCaptures(refs1, info2.captureSet).isOK && sameBoxed(info1, info2, refs1)
671
+ subCaptures(refs1, info2.captureSet) && sameBoxed(info1, info2, refs1)
672
672
&& isSubInfo(parent1, info2)
673
673
case (info1 : Type , CapturingType (parent2, refs2))
674
674
if info1.stripCapturing.isInstanceOf [MethodOrPoly ] =>
675
675
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)
677
677
&& isSubInfo(info1, parent2)
678
678
case _ =>
679
679
isSubType(info1, info2)
@@ -867,12 +867,12 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
867
867
// Eamples where this arises is capt-capibility.scala and function-combinators.scala
868
868
val singletonOK = tp1 match
869
869
case tp1 : SingletonType
870
- if subCaptures(tp1.underlying.captureSet, refs2, CaptureSet .VarState .Separate ).isOK =>
870
+ if subCaptures(tp1.underlying.captureSet, refs2, CaptureSet .VarState .Separate ) =>
871
871
recur(tp1.widen, tp2)
872
872
case _ =>
873
873
false
874
874
singletonOK
875
- || subCaptures(refs1, refs2).isOK
875
+ || subCaptures(refs1, refs2)
876
876
&& sameBoxed(tp1, tp2, refs1)
877
877
&& (recur(tp1.widen.stripCapturing, parent2)
878
878
|| tp1.isInstanceOf [SingletonType ] && recur(tp1, parent2)
@@ -2830,7 +2830,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
2830
2830
if frozenConstraint then CaptureSet .VarState .Closed () else CaptureSet .VarState ()
2831
2831
2832
2832
protected def subCaptures (refs1 : CaptureSet , refs2 : CaptureSet ,
2833
- vs : CaptureSet .VarState = makeVarState())(using Context ): CaptureSet . CompareResult =
2833
+ vs : CaptureSet .VarState = makeVarState())(using Context ): Boolean =
2834
2834
try
2835
2835
refs1.subCaptures(refs2, vs)
2836
2836
catch case ex : AssertionError =>
@@ -2843,7 +2843,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
2843
2843
*/
2844
2844
protected def sameBoxed (tp1 : Type , tp2 : Type , refs1 : CaptureSet )(using Context ): Boolean =
2845
2845
(tp1.isBoxedCapturing == tp2.isBoxedCapturing)
2846
- || refs1.subCaptures(CaptureSet .empty, makeVarState()).isOK
2846
+ || refs1.subCaptures(CaptureSet .empty, makeVarState())
2847
2847
2848
2848
// ----------- Diagnostics --------------------------------------------------
2849
2849
@@ -3254,16 +3254,40 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
3254
3254
* the same class as `note`.
3255
3255
*/
3256
3256
def addErrorNote (note : ErrorNote ): Unit =
3257
- if errorNotes.forall(_._2.getClass != note.getClass ) then
3257
+ if errorNotes.forall(_._2.kind != note.kind ) then
3258
3258
errorNotes = (recCount, note) :: errorNotes
3259
3259
assert(maxErrorLevel <= recCount)
3260
3260
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)))
3261
3281
}
3262
3282
3263
3283
object TypeComparer {
3264
3284
3265
3285
/** 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
3267
3291
3268
3292
/** A richer compare result, returned by `testSubType` and `test`. */
3269
3293
enum CompareResult :
@@ -3280,7 +3304,6 @@ object TypeComparer {
3280
3304
else res match
3281
3305
case ClassInfo (_, cls, _, _, _) => cls.showLocated
3282
3306
case bounds : TypeBounds => i " type bounds [ $bounds] "
3283
- case CaptureSet .CompareResult .OK => " OK"
3284
3307
case res : printing.Showable => res.show
3285
3308
case _ => String .valueOf(res).nn
3286
3309
@@ -3435,7 +3458,7 @@ object TypeComparer {
3435
3458
def reduceMatchWith [T ](op : MatchReducer => T )(using Context ): T =
3436
3459
comparing(_.reduceMatchWith(op))
3437
3460
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 =
3439
3462
comparing(_.subCaptures(refs1, refs2, vs))
3440
3463
3441
3464
def inNestedLevel (op : => Boolean )(using Context ): Boolean =
@@ -3444,15 +3467,16 @@ object TypeComparer {
3444
3467
def addErrorNote (note : ErrorNote )(using Context ): Unit =
3445
3468
comparer.addErrorNote(note)
3446
3469
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)
3456
3480
}
3457
3481
3458
3482
object MatchReducer :
@@ -3857,9 +3881,11 @@ class ExplainingTypeComparer(initctx: Context, short: Boolean) extends TypeCompa
3857
3881
private val b = new StringBuilder
3858
3882
private var lastForwardGoal : String | Null = null
3859
3883
3860
- private def appendFailure (x : String ) =
3884
+ private def appendFailure (notes : List [ ErrorNote ] ) =
3861
3885
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" )
3863
3889
lastForwardGoal = null
3864
3890
3865
3891
override def traceIndented [T ](str : String )(op : => T ): T =
@@ -3875,9 +3901,9 @@ class ExplainingTypeComparer(initctx: Context, short: Boolean) extends TypeCompa
3875
3901
if short then
3876
3902
res match
3877
3903
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 )
3881
3907
case _ =>
3882
3908
b.length = curLength // don't show successful subtraces
3883
3909
else
@@ -3927,7 +3953,7 @@ class ExplainingTypeComparer(initctx: Context, short: Boolean) extends TypeCompa
3927
3953
super .gadtAddBound(sym, b, isUpper)
3928
3954
}
3929
3955
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 =
3931
3957
traceIndented(i " subcaptures $refs1 <:< $refs2 in ${vs.toString}" ) {
3932
3958
super .subCaptures(refs1, refs2, vs)
3933
3959
}
0 commit comments