@@ -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