@@ -290,12 +290,27 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
290
290
private val scalaNilType = ctx.requiredModuleRef(" scala.collection.immutable.Nil" )
291
291
private val scalaConsType = ctx.requiredClassRef(" scala.collection.immutable.::" )
292
292
293
- private val nullType = ConstantType (Constant (null ))
294
- private val nullSpace = Typ (nullType)
293
+ private val constantNullType = ConstantType (Constant (null ))
294
+ private val constantNullSpace = Typ (constantNullType)
295
+
296
+ /** Does the given tree stand for the literal `null`? */
297
+ def isNullLit (tree : Tree ): Boolean = tree match {
298
+ case Literal (Constant (null )) => true
299
+ case _ => false
300
+ }
301
+
302
+ /** Does the given space contain just the value `null`? */
303
+ def isNullSpace (space : Space ): Boolean = space match {
304
+ case Typ (tpe, _) => tpe =:= constantNullType || tpe.isNullType
305
+ case Or (spaces) => spaces.forall(isNullSpace)
306
+ case _ => false
307
+ }
295
308
296
309
override def intersectUnrelatedAtomicTypes (tp1 : Type , tp2 : Type ): Space = {
297
- // Precondition: !isSubType(tp1, tp2) && !isSubType(tp2, tp1)
298
- if (tp1 == nullType || tp2 == nullType) {
310
+ // Precondition: !isSubType(tp1, tp2) && !isSubType(tp2, tp1).
311
+ if (ctx.settings.YexplicitNulls .value) {
312
+ // No additional checks required: since subtyping already reflects nullability.
313
+ } else if (tp1.isNullType || tp2.isNullType) {
299
314
// Since projections of types don't include null, intersection with null is empty.
300
315
return Empty
301
316
}
@@ -327,7 +342,7 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
327
342
Typ (ConstantType (c), false )
328
343
case _ : BackquotedIdent => Typ (pat.tpe, false )
329
344
case Ident (nme.WILDCARD ) =>
330
- Or (Typ (pat.tpe.stripAnnots, false ) :: nullSpace :: Nil )
345
+ Or (Typ (pat.tpe.stripAnnots, false ) :: constantNullSpace :: Nil )
331
346
case Ident (_) | Select (_, _) =>
332
347
Typ (pat.tpe.stripAnnots, false )
333
348
case Alternative (trees) => Or (trees.map(project(_)))
@@ -406,7 +421,11 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
406
421
/** Is `tp1` a subtype of `tp2`? */
407
422
def isSubType (tp1 : Type , tp2 : Type ): Boolean = {
408
423
debug.println(TypeComparer .explained(implicit ctx => tp1 <:< tp2))
409
- val res = (tp1 != nullType || tp2 == nullType) && tp1 <:< tp2
424
+ val res = if (ctx.settings.YexplicitNulls .value) {
425
+ tp1 <:< tp2
426
+ } else {
427
+ (tp1 != constantNullType || tp2 == constantNullType) && tp1 <:< tp2
428
+ }
410
429
res
411
430
}
412
431
@@ -630,7 +649,9 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
630
649
631
650
def doShow (s : Space , mergeList : Boolean = false ): String = s match {
632
651
case Empty => " "
633
- case Typ (c : ConstantType , _) => c.value.value.toString
652
+ case Typ (c : ConstantType , _) =>
653
+ val v = c.value.value
654
+ if (v == null ) " null" else v.toString
634
655
case Typ (tp : TermRef , _) => tp.symbol.showName
635
656
case Typ (tp, decomposed) =>
636
657
val sym = tp.widen.classSymbol
@@ -731,11 +752,14 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
731
752
732
753
if (! redundancyCheckable(sel)) return
733
754
734
- val targetSpace =
755
+ val targetSpace = if (ctx.settings.YexplicitNulls .value) {
756
+ Typ (selTyp, true )
757
+ } else {
735
758
if (selTyp.classSymbol.isPrimitiveValueClass)
736
759
Typ (selTyp, true )
737
760
else
738
- Or (Typ (selTyp, true ) :: nullSpace :: Nil )
761
+ Or (Typ (selTyp, true ) :: constantNullSpace :: Nil )
762
+ }
739
763
740
764
// in redundancy check, take guard as false in order to soundly approximate
741
765
def projectPrevCases (cases : List [CaseDef ]): Space =
@@ -744,11 +768,6 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
744
768
else Empty
745
769
}.reduce((a, b) => Or (List (a, b)))
746
770
747
- def isNull (tree : Tree ): Boolean = tree match {
748
- case Literal (Constant (null )) => true
749
- case _ => false
750
- }
751
-
752
771
(1 until cases.length).foreach { i =>
753
772
val prevs = projectPrevCases(cases.take(i))
754
773
@@ -765,18 +784,27 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
765
784
766
785
// `covered == Empty` may happen for primitive types with auto-conversion
767
786
// see tests/patmat/reader.scala tests/patmat/byte.scala
768
- if (covered == Empty ) covered = curr
787
+ if (covered == Empty && ! isNullLit(pat) ) covered = curr
769
788
770
789
if (isSubspace(covered, prevs)) {
771
790
ctx.warning(MatchCaseUnreachable (), pat.sourcePos)
772
791
}
773
792
774
793
// if last case is `_` and only matches `null`, produce a warning
775
- if (i == cases.length - 1 && ! isNull(pat) ) {
776
- simplify(minus(covered, prevs)) match {
777
- case Typ (`nullType`, _) =>
778
- ctx.warning(MatchCaseOnlyNullWarning (), pat.sourcePos)
779
- case _ =>
794
+ if (i == cases.length - 1 && ! isNullLit(pat) ) {
795
+ val simpl = simplify(minus(covered, prevs))
796
+ if (ctx.settings.YexplicitNulls .value) {
797
+ simpl match {
798
+ case space if isNullSpace(space) =>
799
+ ctx.warning(MatchCaseOnlyNullWarning (), pat.sourcePos)
800
+ case _ =>
801
+ }
802
+ } else {
803
+ simpl match {
804
+ case Typ (`constantNullType`, _) =>
805
+ ctx.warning(MatchCaseOnlyNullWarning (), pat.sourcePos)
806
+ case _ =>
807
+ }
780
808
}
781
809
}
782
810
}
0 commit comments