-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve warning for wildcard matching only null under the explicit nulls flag (scala#21577) #21623
Conversation
97faede
to
d7a439e
Compare
The reason why there is a warning for the "unreachable wildcard except null" cases is: this kind of cases we normally don't write. If there is an extra wildcard case at the end, it much match with For example, if
For |
Another issue which can be improved: class A
class B
def f(s: A | B) = s match
case _: A => 0
case null => 1
case _: B => 2
case _ => 3 If we compile without explicit nulls, it says the last wildcard case is "Unreachable case except for null". If we change to It should be unreachable from the begining. |
I did some refactoring to def checkReachability(m: Match)(using Context): Unit = trace(i"checkReachability($m)"):
val selTyp = toUnderlying(m.selector.tpe).dealias
val isNullable = selTyp.isInstanceOf[FlexibleType] || selTyp.classSymbol.isNullableClass
val targetSpace = trace(i"targetSpace($selTyp)"):
if isNullable && !ctx.mode.is(Mode.SafeNulls)
then project(OrType(selTyp, ConstantType(Constant(null)), soft = false))
else project(selTyp)
@tailrec def recur(cases: List[CaseDef], prevs: List[Space], deferred: List[Tree]): Unit =
cases match
case Nil =>
case CaseDef(pat, guard, _) :: rest =>
val curr = trace(i"project($pat)")(project(pat))
val covered = trace("covered")(simplify(intersect(curr, targetSpace)))
val prev = trace("prev")(simplify(Or(prevs)))
if prev == Empty && covered == Empty then // defer until a case is reachable
recur(rest, prevs, pat :: deferred)
else
for pat <- deferred.reverseIterator
do report.warning(MatchCaseUnreachable(), pat.srcPos)
if pat != EmptyTree // rethrow case of catch uses EmptyTree
&& !pat.symbol.isAllOf(SyntheticCase, butNot=Method) // ExpandSAMs default cases use SyntheticCase
&& isSubspace(covered, prev)
then
val nullOnly = isNullable && rest.isEmpty && isWildcardArg(pat)
val msg = if nullOnly then MatchCaseOnlyNullWarning() else MatchCaseUnreachable()
report.warning(msg, pat.srcPos)
val newPrev = if guard.isEmpty then covered :: prevs else prevs
recur(rest, newPrev, Nil)
recur(m.cases, Nil, Nil)
end checkReachability I think you also need to add a case to case tp: FlexibleType => List(tp.underlying, ConstantType(Constant(null))) and a case to case tp: FlexibleType => tp.derivedFlexibleType(toUnderlying(tp.underlying)) A flexible type is considered "nullable" as it may contain null value, and it is key to keep the flexible type in the space. I don't think |
…cala#21577) Adds a more detailed warning message when a wildcard case is only reachable by null under explict nulls flag. Fixes scala#21577
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great
Improve warning for wildcard matching only null under the explicit nulls flag
Fixes #21577
I have signed the CLA