Consider the following split of a union model into interface and implementation:
sealed interface Model
interface Case0 : Model
interface Case1 : Model
sealed class ModelImpl : Model
object Case0Impl : ModelImpl(), Case0
object Case1Impl : ModelImpl(), Case1
fun createModel(): Model = Case0Impl
And here comes the usage:
fun main() {
val model: Model = createModel()
val res = when(model) {
//...
}
println(res)
}
The when expression must be exhaustive. When triggering completion in IJ, it will insert the following branches:
val res = when(model) {
is Case0 -> TODO()
is Case1 -> TODO()
Case0Impl -> TODO()
Case1Impl -> TODO()
}
But the last two branches matching on the implementation can never be reached. When removing them, IJ is complaining with a non-exhaustive error (but it should be because Model and ModelImpl is sealed). It gets even worse when making the implementation classes private in the file. Then it seems to be impossible to write a non-trivial exhaustive when expression without else branch.
Consider the following code, which compiles without error:
sealed interface Model
interface Case0 : Model
interface Case1 : Model
object Case0Impl : Case0
object Case1Impl : Case1
val res = when(model){
is Case0 -> TODO()
is Case1 -> TODO()
}
However, this code will not compile, stating when is not exhaustive:
sealed interface Model
interface Case0 : Model
interface Case1 : Model
object Case0Impl : Model, Case0
object Case1Impl : Model, Case1
val res = when(model){
is Case0 -> TODO()
is Case1 -> TODO()
}
As such, it seems the compiler will only accept exhaustive when branches that have cases for all classes that directly implement a sealed class or interface.
We can prove this by introducing an extra, unnecessary check for ModeImpl:
val res = when(model){
is Case0 -> TODO()
is Case1 -> TODO()
is ModelImpl -> TODO()
}
Here’s a runnable example if anyone is interested.
sealed interface Model
interface Case0 : Model
interface Case1 : Model
// Try uncommenting to see error
object Case0Impl : Case0 //, Model
object Case1Impl : Case1 //, Model
fun main() {
val model: Model = Case0Impl
val res = when(model){
is Case0 -> "1"
is Case1 -> "2"
}
println(res)
}