@@ -65,6 +65,8 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
6565
6666 private var useNecessaryEither = false
6767
68+ private var ignoreNulls = false
69+
6870 /** Is a subtype check in progress? In that case we may not
6971 * permanently instantiate type variables, because the corresponding
7072 * constraint might still be retracted and the instantiation should
@@ -133,12 +135,24 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
133135 }
134136 }
135137
138+ def topLevelSubTypeIgnoringNulls (tp1 : Type , tp2 : Type ): Boolean =
139+ val saved = ignoreNulls
140+ ignoreNulls = true
141+ try topLevelSubType(tp1, tp2)
142+ finally ignoreNulls = saved
143+
136144 def necessarySubType (tp1 : Type , tp2 : Type ): Boolean =
137145 val saved = useNecessaryEither
138146 useNecessaryEither = true
139147 try topLevelSubType(tp1, tp2)
140148 finally useNecessaryEither = saved
141149
150+ def necessarySubTypeIgnoringNulls (tp1 : Type , tp2 : Type ): Boolean =
151+ val saved = useNecessaryEither
152+ useNecessaryEither = true
153+ try topLevelSubTypeIgnoringNulls(tp1, tp2)
154+ finally useNecessaryEither = saved
155+
142156 def testSubType (tp1 : Type , tp2 : Type ): CompareResult =
143157 GADTused = false
144158 if ! topLevelSubType(tp1, tp2) then CompareResult .Fail
@@ -333,7 +347,11 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
333347 case AndType (tp21, tp22) =>
334348 recur(tp1, tp21) && recur(tp1, tp22)
335349 case OrType (tp21, tp22) =>
336- if (tp21.stripTypeVar eq tp22.stripTypeVar) recur(tp1, tp21)
350+ if ignoreNulls && tp22.isNullType then
351+ tp1.isNullType || recur(tp1, tp21)
352+ else if ignoreNulls && tp21.isNullType then
353+ tp1.isNullType || recur(tp1, tp22)
354+ else if tp21.stripTypeVar eq tp22.stripTypeVar then recur(tp1, tp21)
337355 else secondTry
338356 case TypeErasure .ErasedValueType (tycon1, underlying2) =>
339357 def compareErasedValueType = tp1 match {
@@ -463,10 +481,12 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
463481 case OrType (tp1, tp2) => containsAnd(tp1) || containsAnd(tp2)
464482 case _ => false
465483
466- widenOK
467- || joinOK
468- || (tp1.isSoft || constrainRHSVars(tp2)) && recur(tp11, tp2) && recur(tp12, tp2)
469- || containsAnd(tp1) && recur(tp1.join, tp2)
484+ if ignoreNulls && tp12.isNullType then recur(tp11, tp2)
485+ else if ignoreNulls && tp11.isNullType then recur(tp12, tp2)
486+ else widenOK
487+ || joinOK
488+ || (tp1.isSoft || constrainRHSVars(tp2)) && recur(tp11, tp2) && recur(tp12, tp2)
489+ || containsAnd(tp1) && recur(tp1.join, tp2)
470490 case tp1 : MatchType =>
471491 val reduced = tp1.reduced
472492 if (reduced.exists) recur(reduced, tp2) else thirdTry
@@ -632,6 +652,10 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
632652 case Some (b) => return b
633653 case _ =>
634654
655+ if ignoreNulls then
656+ if tp22.isNullType then return recur(tp1, tp21)
657+ if tp21.isNullType then return recur(tp1, tp22)
658+
635659 // The next clause handles a situation like the one encountered in i2745.scala.
636660 // We have:
637661 //
@@ -754,7 +778,9 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
754778 isSubType(hi1, tp2, approx.addLow) || compareGADT || tryLiftedToThis1
755779 case _ =>
756780 def isNullable (tp : Type ): Boolean = tp.widenDealias match {
757- case tp : TypeRef => tp.symbol.isNullableClass
781+ case tp : TypeRef =>
782+ if ignoreNulls then tp.symbol.isNullableClassAfterErasure
783+ else tp.symbol.isNullableClass
758784 case tp : RefinedOrRecType => isNullable(tp.parent)
759785 case tp : AppliedType => isNullable(tp.tycon)
760786 case AndType (tp1, tp2) => isNullable(tp1) && isNullable(tp2)
@@ -2550,9 +2576,15 @@ object TypeComparer {
25502576 def topLevelSubType (tp1 : Type , tp2 : Type )(using Context ): Boolean =
25512577 comparing(_.topLevelSubType(tp1, tp2))
25522578
2579+ def topLevelSubTypeIgnoringNulls (tp1 : Type , tp2 : Type )(using Context ): Boolean =
2580+ comparing(_.topLevelSubTypeIgnoringNulls(tp1, tp2))
2581+
25532582 def necessarySubType (tp1 : Type , tp2 : Type )(using Context ): Boolean =
25542583 comparing(_.necessarySubType(tp1, tp2))
25552584
2585+ def necessarySubTypeIgnoringNulls (tp1 : Type , tp2 : Type )(using Context ): Boolean =
2586+ comparing(_.necessarySubTypeIgnoringNulls(tp1, tp2))
2587+
25562588 def isSubType (tp1 : Type , tp2 : Type )(using Context ): Boolean =
25572589 comparing(_.isSubType(tp1, tp2))
25582590
0 commit comments