Why is the compiler not able to smart cast the mem...
# getting-started
h
Why is the compiler not able to smart cast the member s to Int in this case:
is Foo.A, is Foo.B
Copy code
public sealed interface Foo {
    public val s: Int?
    
    public data class A(override val s: Int): Foo
    public data class B(override val s: Int): Foo
    public data class C(override val s: Int?): Foo
}

public fun a(foo: Foo) {
    when (foo){
        is Foo.A -> foo.s + foo.s // smart cast to A and s is Int
        is Foo.B -> foo.s + foo.s // smart cast to B and s is Int
        is Foo.C -> (foo.s ?: 0) + (foo.s ?: 0) // smart cast to C, but s is Int?
    }
    when (foo){
        is Foo.A, is Foo.B -> foo.s + foo.s // no smart cast, Foo.s is Int?
        is Foo.C -> (foo.s ?: 0) + (foo.s ?: 0)
    }
}
e
the two overrides are not related to each other. you're expecting structural typing but there's only nominal typing
you could force them to be related with
Copy code
sealed interface Foo2 {
    override val s: Int
}
data class A(override val s: Int) : Foo2
data class B(override val s: Int) : Foo2
h
Yeah, that’s my workaround
But in this case, the compiler inferred the type as `Comparable<*> & Serializable`:
val s = if (true) "" else 42
. So it could also be inferred.
e
that's different. those are two separate codepaths being type-unified, whereas you have a single conditional branch
the compiler does not duplicate the code for each disjunction in your condition