I encountered a regression(?) bumping JDK from 17 to 21 (applies to Scala 2.13.17 and 3.7.1)
I have some sealed java class
public sealed class Sealed permits A, B {}
final class A extends Sealed {}
final class B extends Sealed {}
pattern matched from the Scala code
val a: Sealed = ???
a match {
case a: A =>
case b: B =>
}
When compiling with JDK 17 no error occurs. But for 21
for Scala 2
It would fail on the following input: Sealed()
for Scala 3
match may not be exhaustive.
It would fail on pattern case: _: Sealed
Has Scala stopped understanding java sealed classes, or has it started checking them better, but I just don’t understand how they work in Java?
2 Likes
a is one 3 types, A, B, or Sealed. you need to check against all 3. Weird that there are instances where just checking 2 would work without at least warning.
I see the warning under JDK 17 with 2.13.17 but not with 3.7.3.
Scala 3 also fails to warn under JDK 25, so the difference is Scala version not JDK.
Confirming that it’s trivial to supply Sealed() and fail:
Exception in thread "main" scala.MatchError: Sealed@4c75cab9 (of class Sealed)
Edit: I did not check whether Scala 3 has different option flags to produce a warning, as that would take all day to track down.
Edit: let me try -Wall. It only warns about unused b because you’re allowed to refine the selector a without incurring a warning.
10 | case b: B => 2
| ^
| unused pattern variable
Omg, that’s right. And scala sealed classes work the same way. Brain fog
public sealed class Sealed permits A, B {}
final class A extends Sealed {}
final class B extends Sealed {}
and
object Test {
def test(a: Sealed): Int =
a match {
case a: A => 1
case b: B => 2
}
def main(args: Array[String]): Unit = println {
test(new Sealed)
}
}
then
➜ snips javac -d /tmp Sealed.java
➜ snips scala-cli run --server=false -S 3.7.3 -Wall -cp /tmp sealed-test.scala
WARNING: A terminally deprecated method in sun.misc.Unsafe has been called
WARNING: sun.misc.Unsafe::objectFieldOffset has been called by scala.runtime.LazyVals$ (file:/home/amarki/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/scala3-library_3/3.7.3/scala3-library_3-3.7.3.jar)
WARNING: Please consider reporting this to the maintainers of class scala.runtime.LazyVals$
WARNING: sun.misc.Unsafe::objectFieldOffset will be removed in a future release
-- [E198] Unused Symbol Warning: /home/amarki/snips/sealed-test.scala:6:11 -----
6 | case b: B => 2
| ^
| unused pattern variable
1 warning found
Exception in thread "main" scala.MatchError: Sealed@4c75cab9 (of class Sealed)
at Test$.test(sealed-test.scala:6)
at Test$.main(sealed-test.scala:10)
at Test.main(sealed-test.scala)
I don’t see an exhaustivity warning.
Scala-only:
sealed class Sealed
final class A extends Sealed
final class B extends Sealed
object Test {
def test(a: Sealed): Int =
a match {
case a: A => 1
case b: B => 2
}
def main(args: Array[String]): Unit = println {
test(new Sealed)
}
}
then
➜ snips scala-cli run --server=false -S 3.7.3 -Wall sealed-scala.scala
WARNING: A terminally deprecated method in sun.misc.Unsafe has been called
WARNING: sun.misc.Unsafe::objectFieldOffset has been called by scala.runtime.LazyVals$ (file:/home/amarki/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/scala3-library_3/3.7.3/scala3-library_3-3.7.3.jar)
WARNING: Please consider reporting this to the maintainers of class scala.runtime.LazyVals$
WARNING: sun.misc.Unsafe::objectFieldOffset will be removed in a future release
-- [E198] Unused Symbol Warning: /home/amarki/snips/sealed-scala.scala:11:11 ---
11 | case b: B => 2
| ^
| unused pattern variable
-- [E029] Pattern Match Exhaustivity Warning: /home/amarki/snips/sealed-scala.scala:9:4
9 | a match {
| ^
| match may not be exhaustive.
|
| It would fail on pattern case: _: Sealed
|
| longer explanation available when compiling with `-explain`
2 warnings found
Exception in thread "main" scala.MatchError: Sealed@4c75cab9 (of class Sealed)
at Test$.test(sealed-scala.scala:11)
at Test$.main(sealed-scala.scala:15)
at Test.main(sealed-scala.scala)
but Scala 2 warns for both cases
➜ snips scala-cli run --server=false -S 2.13.17 -Wunused -cp /tmp sealed-test.scala
/home/amarki/snips/sealed-test.scala:6: warning: pattern var b in method test is never used
case b: B => 2
^
/home/amarki/snips/sealed-test.scala:4: warning: match may not be exhaustive.
It would fail on the following input: Sealed()
a match {
^
2 warnings
Exception in thread "main" scala.MatchError: Sealed@52d455b8 (of class Sealed)
at Test$.test(sealed-test.scala:4)
at Test$.main(sealed-test.scala:10)
at Test.main(sealed-test.scala)
with the same result for Scala-only.
This is for my reference.
1 Like