Generics in when statement don't get smart-casted?

Suppose you have a Foo<RESULT> interface, and a class FooA : Foo<Boolean>.

When smart-casting myFoo to be of type FooA (and thus, of type Foo<Boolean>), it’d be nice if the compiler could also infer that RESULT, within the scope of that smart-cast, is of type Boolean.

Here’s a minimal code-sample. It includes explicit casts; I would love it if the compiler could infer that these casts aren’t necessary, so I could remove them.

https://pl.kotl.in/UieCCJo0T

Any reason this cast needs to be explicit, or is it just something the compiler doesn’t support (and is it something we could consider supporting in the future)?

I don’t have time to look into this carefully right now, but isn’t there a variance issue? If Boolean were open, couldn’t (some subclass of) a FooA actually extend Foo<someSubclassOfBoolean>?

Hmm, so if you had

open class FooA<RESULT : CharSequence> : Foo<RESULT>
class FooAImpl : FooA<String>()

Couldn’t you still smart-cast the result type to CharSequence in a context where you know that myFoo is of type FooA?

Maybe there’s an issue with contravariance or something? I haven’t looked too deeply into that case.

If the property of the result type is mutable, then casting it to CharSequence would be unsafe. You would be able to assign any CharSequence to it, whereas in fact only String is allowed in your last example.

Marking the type variable as “out RESULT” would theoretically solve this unsafeness in your last example. Though I don’t know whether the compiler is smart enough to smart cast then.

Another way to make it safe is using non-open classes. That is, I don’t see why your original example could be unsafe. Still, the compiler was not smart enough.

1 Like