@@ -60,6 +60,8 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
6060 /** Indicates whether the subtype check used GADT bounds */
6161 private var GADTused : Boolean = false
6262
63+ protected var canWidenAbstract : Boolean = true
64+
6365 private var myInstance : TypeComparer = this
6466 def currentInstance : TypeComparer = myInstance
6567
@@ -757,9 +759,11 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
757759
758760 def tryBaseType (cls2 : Symbol ) = {
759761 val base = nonExprBaseType(tp1, cls2)
760- if (base.exists && (base `ne` tp1))
761- isSubType(base, tp2, if (tp1.isRef(cls2)) approx else approx.addLow) ||
762- base.isInstanceOf [OrType ] && fourthTry
762+ if base.exists && (base ne tp1)
763+ && (! caseLambda.exists || canWidenAbstract || tp1.widen.underlyingClassRef(refinementOK = true ).exists)
764+ then
765+ isSubType(base, tp2, if (tp1.isRef(cls2)) approx else approx.addLow)
766+ || base.isInstanceOf [OrType ] && fourthTry
763767 // if base is a disjunction, this might have come from a tp1 type that
764768 // expands to a match type. In this case, we should try to reduce the type
765769 // and compare the redux. This is done in fourthTry
@@ -776,7 +780,9 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
776780 || narrowGADTBounds(tp1, tp2, approx, isUpper = true ))
777781 && (tp2.isAny || GADTusage (tp1.symbol))
778782
779- isSubType(hi1, tp2, approx.addLow) || compareGADT || tryLiftedToThis1
783+ (! caseLambda.exists || canWidenAbstract) && isSubType(hi1, tp2, approx.addLow)
784+ || compareGADT
785+ || tryLiftedToThis1
780786 case _ =>
781787 // `Mode.RelaxedOverriding` is only enabled when checking Java overriding
782788 // in explicit nulls, and `Null` becomes a bottom type, which allows
@@ -2845,7 +2851,16 @@ object TypeComparer {
28452851 comparing(_.tracked(op))
28462852}
28472853
2854+ object TrackingTypeComparer :
2855+ enum MatchResult :
2856+ case Reduced (tp : Type )
2857+ case Disjoint
2858+ case Stuck
2859+ case NoInstance (param : Name , bounds : TypeBounds )
2860+
28482861class TrackingTypeComparer (initctx : Context ) extends TypeComparer (initctx) {
2862+ import TrackingTypeComparer .*
2863+
28492864 init(initctx)
28502865
28512866 override def trackingTypeComparer = this
@@ -2883,15 +2898,25 @@ class TrackingTypeComparer(initctx: Context) extends TypeComparer(initctx) {
28832898 }
28842899
28852900 def matchCases (scrut : Type , cases : List [Type ])(using Context ): Type = {
2886- def paramInstances = new TypeAccumulator [Array [Type ]] {
2887- def apply (inst : Array [Type ], t : Type ) = t match {
2888- case t @ TypeParamRef (b, n) if b `eq` caseLambda =>
2889- inst(n) = approximation(t, fromBelow = variance >= 0 ).simplified
2890- inst
2901+
2902+ def paramInstances (canApprox : Boolean ) = new TypeAccumulator [Array [Type ]]:
2903+ def apply (insts : Array [Type ], t : Type ) = t match
2904+ case param @ TypeParamRef (b, n) if b eq caseLambda =>
2905+ insts(n) = {
2906+ if canApprox then
2907+ approximation(param, fromBelow = variance >= 0 )
2908+ else constraint.entry(param) match
2909+ case entry : TypeBounds =>
2910+ val lo = fullLowerBound(param)
2911+ val hi = fullUpperBound(param)
2912+ if isSubType(hi, lo) then lo else TypeBounds (lo, hi)
2913+ case inst =>
2914+ assert(inst.exists, i " param = $param\n constraint = $constraint" )
2915+ inst
2916+ }.simplified
2917+ insts
28912918 case _ =>
2892- foldOver(inst, t)
2893- }
2894- }
2919+ foldOver(insts, t)
28952920
28962921 def instantiateParams (inst : Array [Type ]) = new TypeMap {
28972922 def apply (t : Type ) = t match {
@@ -2907,7 +2932,7 @@ class TrackingTypeComparer(initctx: Context) extends TypeComparer(initctx) {
29072932 * None if the match fails and we should consider the following cases
29082933 * because scrutinee and pattern do not overlap
29092934 */
2910- def matchCase (cas : Type ): Option [ Type ] = trace(i " match case $cas vs $scrut" , matchTypes) {
2935+ def matchCase (cas : Type ): MatchResult = trace(i " match case $cas vs $scrut" , matchTypes) {
29112936 val cas1 = cas match {
29122937 case cas : HKTypeLambda =>
29132938 caseLambda = constrained(cas)
@@ -2918,34 +2943,48 @@ class TrackingTypeComparer(initctx: Context) extends TypeComparer(initctx) {
29182943
29192944 val defn .MatchCase (pat, body) = cas1 : @ unchecked
29202945
2921- if (isSubType(scrut, pat))
2922- // `scrut` is a subtype of `pat`: *It's a Match!*
2923- Some {
2924- caseLambda match {
2925- case caseLambda : HKTypeLambda =>
2926- val instances = paramInstances(new Array (caseLambda.paramNames.length), pat)
2927- instantiateParams(instances)(body).simplified
2928- case _ =>
2929- body
2930- }
2931- }
2946+ def matches (canWidenAbstract : Boolean ): Boolean =
2947+ val saved = this .canWidenAbstract
2948+ this .canWidenAbstract = canWidenAbstract
2949+ try necessarySubType(scrut, pat)
2950+ finally this .canWidenAbstract = saved
2951+
2952+ def redux (canApprox : Boolean ): MatchResult =
2953+ caseLambda match
2954+ case caseLambda : HKTypeLambda =>
2955+ val instances = paramInstances(canApprox)(new Array (caseLambda.paramNames.length), pat)
2956+ instances.indices.find(instances(_).isInstanceOf [TypeBounds ]) match
2957+ case Some (i) if ! canApprox =>
2958+ MatchResult .NoInstance (caseLambda.paramNames(i), instances(i).bounds)
2959+ case _ =>
2960+ MatchResult .Reduced (instantiateParams(instances)(body).simplified)
2961+ case _ =>
2962+ MatchResult .Reduced (body)
2963+
2964+ if caseLambda.exists && matches(canWidenAbstract = false ) then
2965+ redux(canApprox = true )
2966+ else if matches(canWidenAbstract = true ) then
2967+ redux(canApprox = false )
29322968 else if (provablyDisjoint(scrut, pat))
29332969 // We found a proof that `scrut` and `pat` are incompatible.
29342970 // The search continues.
2935- None
2971+ MatchResult . Disjoint
29362972 else
2937- Some ( NoType )
2973+ MatchResult . Stuck
29382974 }
29392975
29402976 def recur (remaining : List [Type ]): Type = remaining match
29412977 case cas :: remaining1 =>
29422978 matchCase(cas) match
2943- case None =>
2979+ case MatchResult . Disjoint =>
29442980 recur(remaining1)
2945- case Some ( NoType ) =>
2981+ case MatchResult . Stuck =>
29462982 MatchTypeTrace .stuck(scrut, cas, remaining1)
29472983 NoType
2948- case Some (tp) =>
2984+ case MatchResult .NoInstance (pname, bounds) =>
2985+ MatchTypeTrace .noInstance(scrut, cas, pname, bounds)
2986+ NoType
2987+ case MatchResult .Reduced (tp) =>
29492988 tp
29502989 case Nil =>
29512990 val casesText = MatchTypeTrace .noMatchesText(scrut, cases)
0 commit comments