@@ -926,36 +926,36 @@ object SpaceEngine {
926926 then project(OrType (selTyp, ConstantType (Constant (null )), soft = false ))
927927 else project(selTyp)
928928
929- @ tailrec def recur (cases : List [CaseDef ], prevs : List [Space ], deferred : List [Tree ]): Unit =
929+ @ tailrec def recur (cases : List [CaseDef ], prevs : List [Space ], deferred : List [Tree ], nullCovered : Boolean ): Unit =
930930 cases match
931931 case Nil =>
932- case CaseDef (pat, guard, _) :: rest =>
933- val curr = trace(i " project( $pat) " )(project(pat))
932+ case (c @ CaseDef (pat, guard, _)) :: rest =>
933+ val patNullable = Nullables .matchesNull(c)
934+ val curr = trace(i " project( $pat) " )(
935+ if patNullable
936+ then Or (List (project(pat), Typ (ConstantType (Constant (null )))))
937+ else project(pat))
934938 val covered = trace(" covered" )(simplify(intersect(curr, targetSpace)))
935939 val prev = trace(" prev" )(simplify(Or (prevs)))
936940 if prev == Empty && covered == Empty then // defer until a case is reachable
937- recur(rest, prevs, pat :: deferred)
941+ recur(rest, prevs, pat :: deferred, nullCovered )
938942 else
939943 for pat <- deferred.reverseIterator
940944 do report.warning(MatchCaseUnreachable (), pat.srcPos)
941945
942946 if pat != EmptyTree // rethrow case of catch uses EmptyTree
943947 && ! pat.symbol.isAllOf(SyntheticCase , butNot= Method ) // ExpandSAMs default cases use SyntheticCase
944- && isSubspace(covered, prev)
948+ && isSubspace(covered, Or ( List ( prev, Typ ( ConstantType ( Constant ( null ))))) )
945949 then
946- val nullOnly = isNullable && isWildcardArg(pat) && ! mayCoverNull( prev)
947- val msg = if nullOnly then MatchCaseOnlyNullWarning () else MatchCaseUnreachable ( )
948- report.warning(msg , pat.srcPos)
950+ val nullOnly = isNullable && isWildcardArg(pat) && ! nullCovered && ! isSubspace(covered, prev) && ( ! ctx.explicitNulls || selTyp. isInstanceOf [ FlexibleType ] )
951+ if nullOnly then report.warning( MatchCaseOnlyNullWarning () , pat.srcPos )
952+ else if (isSubspace(covered, prev)) then report.warning(MatchCaseUnreachable () , pat.srcPos)
949953
950954 // in redundancy check, take guard as false in order to soundly approximate
951- val newPrev = if (guard.isEmpty)
952- then if (isWildcardArg(pat))
953- then Typ (ConstantType (Constant (null ))) :: covered :: prevs
954- else covered :: prevs
955- else prevs
956- recur(rest, newPrev, Nil )
957-
958- recur(m.cases, Nil , Nil )
955+ val newPrev = if (guard.isEmpty) then covered :: prevs else prevs
956+ recur(rest, newPrev, Nil , nullCovered || (guard.isEmpty && patNullable))
957+
958+ recur(m.cases, Nil , Nil , false )
959959 end checkReachability
960960
961961 def checkMatch (m : Match )(using Context ): Unit =
0 commit comments