Bug with sealed classes and when keyword

I suspect there might be a bug with the Kotlin compiler when it comes to sealed classes and the when keyword. I found two things.

Arbitrary sealed classes in ‘when’ clause

This is the content of a kt file:

sealed class SealedA {
    data class SubA(val value: String): SealedA()
    data class SubB(val value: String): SealedA()
}

fun awesomeFunc(obj: SealedA): Unit = when(obj) {
    is SealedA.SubA -> TODO()
    is SealedA.SubB -> TODO()
}

Everything is fine so far.
This is the content of an other file:

sealed class Crap {

}

Now if I modify awesomeFunc and add Crap to the when clause, I expect a compile error because it can never be true. Result after modification:

fun awesomeFunc(obj: SealedA): Unit = when(obj) {
    is SealedA.SubA -> TODO()
    is SealedA.SubB -> TODO()
    is Crap -> TODO() //Should give compile error since this can never be true
}

Matter fact, I can put any sealed class as an option to the when clause and it will work.

To many sealed classes in a file?

This one is harder to reproduce. I had multiple sealed classes in a file. Whenever I added an instance of one of them to a when statement, the compiler insisted I added an else branch. I fixed the problem by moving the sealed class to a new file.

I do not think it is related to sealed classes. It is a small deficiency in static type checker. Indeed, you can’t have a class that simultaneously inherits two separate type hierarchies, but if you replace one of the sealed classes with a sealed interface - it could be possible. Also, the third branch is unreachable in this case. But if you switch order, it could be made reachable. I think it is not a bug per se, but you should report it on youtrack anyway because it could be improved.

1 Like

Personally, I’d expect this to be a Warning telling you that this condition can never be met, just like how having a if(false) gives you a warning, but not a compile-time error

Actually, I think this is really related to sealed classes and OP is right something is wrong here. Note that normally you can’t do is AnotherClass -> TODO(), because the compiler says AnotherClass and SealedA are incompatible. But make AnotherClass sealed (but still unrelated to SealedA) and now it compiles without any problems. I think this is inconsistent and doesn’t really look right.

1 Like