@@ -116,6 +116,7 @@ object SpaceEngine {
116
116
def isSubspace (a : Space , b : Space )(using Context ): Boolean = a.isSubspace(b)
117
117
def canDecompose (typ : Typ )(using Context ): Boolean = typ.canDecompose
118
118
def decompose (typ : Typ )(using Context ): List [Typ ] = typ.decompose
119
+ def nullSpace (using Context ): Space = Typ (ConstantType (Constant (null )), decomposed = false )
119
120
120
121
/** Simplify space such that a space equal to `Empty` becomes `Empty` */
121
122
def computeSimplify (space : Space )(using Context ): Space = trace(i " simplify( $space) " )(space match {
@@ -336,6 +337,13 @@ object SpaceEngine {
336
337
case pat : Ident if isBackquoted(pat) =>
337
338
Typ (pat.tpe, decomposed = false )
338
339
340
+ case Ident (nme.WILDCARD ) =>
341
+ val tp = pat.tpe.stripAnnots.widenSkolem
342
+ val isNullable = tp.isInstanceOf [FlexibleType ] || tp.classSymbol.isNullableClass
343
+ val tpSpace = Typ (erase(tp, isValue = true ), decomposed = false )
344
+ if isNullable then Or (tpSpace :: nullSpace :: Nil )
345
+ else tpSpace
346
+
339
347
case Ident (_) | Select (_, _) =>
340
348
Typ (erase(pat.tpe.stripAnnots.widenSkolem, isValue = true ), decomposed = false )
341
349
@@ -667,7 +675,7 @@ object SpaceEngine {
667
675
case tp => (tp, Nil )
668
676
val (tp, typeArgs) = getAppliedClass(tpOriginal)
669
677
// This function is needed to get the arguments of the types that will be applied to the class.
670
- // This is necessary because if the arguments of the types contain Nothing,
678
+ // This is necessary because if the arguments of the types contain Nothing,
671
679
// then this can affect whether the class will be taken into account during the exhaustiveness check
672
680
def getTypeArgs (parent : Symbol , child : Symbol , typeArgs : List [Type ]): List [Type ] =
673
681
val superType = child.typeRef.superType
@@ -930,7 +938,7 @@ object SpaceEngine {
930
938
if isNullable && ! ctx.mode.is(Mode .SafeNulls )
931
939
then project(OrType (selTyp, ConstantType (Constant (null )), soft = false ))
932
940
else project(selTyp)
933
-
941
+ var hadNullOnly = false
934
942
@ tailrec def recur (cases : List [CaseDef ], prevs : List [Space ], deferred : List [Tree ]): Unit =
935
943
cases match
936
944
case Nil =>
@@ -946,11 +954,19 @@ object SpaceEngine {
946
954
947
955
if pat != EmptyTree // rethrow case of catch uses EmptyTree
948
956
&& ! pat.symbol.isAllOf(SyntheticCase , butNot= Method ) // ExpandSAMs default cases use SyntheticCase
949
- && isSubspace(covered, prev)
950
957
then
951
- val nullOnly = isNullable && rest.isEmpty && isWildcardArg(pat)
952
- val msg = if nullOnly then MatchCaseOnlyNullWarning () else MatchCaseUnreachable ()
953
- report.warning(msg, pat.srcPos)
958
+ if isSubspace(covered, prev) then
959
+ report.warning(MatchCaseUnreachable (), pat.srcPos)
960
+ else if isNullable && ! hadNullOnly && isWildcardArg(pat)
961
+ && isSubspace(covered, Or (prev :: nullSpace :: Nil )) then
962
+ // Issue OnlyNull warning only if:
963
+ // 1. The target space is nullable;
964
+ // 2. OnlyNull warning has not been issued before;
965
+ // 3. The pattern is a wildcard pattern;
966
+ // 4. The pattern is not covered by the previous cases,
967
+ // but covered by the previous cases with null.
968
+ hadNullOnly = true
969
+ report.warning(MatchCaseOnlyNullWarning (), pat.srcPos)
954
970
955
971
// in redundancy check, take guard as false in order to soundly approximate
956
972
val newPrev = if guard.isEmpty then covered :: prevs else prevs
0 commit comments