I recently discussed an idea that could solve this on the kotlin slack.
data class Test<?null>(
val foo: Foo<?null>, // nullable depending on class parameter
val bar: Bar, // never null
val baz: Baz:? // allways nullable
)
val test1 = Test<?>(getFooOrNull(), Bar(), null)
val test2 = Test<!>(Foo(), Bar(), null)
test1.foo?.doSomething()
test2.foo.doSomething()
The idea is to have a generic parameter that just contains nullability data. That way your code could look something like
fun foo<?null, T: String>(bar: T<?null>): T<?null> = TODO()
The current syntax is terrible so if anyone has a better idea it would be great
You can introduce an overload for the non-null type. It will choose that one as it is more specific. The only issue there is that you must specify an @JvmName annotation for either (the non-null version preferably) as the JVM doesn’t see the difference in signature - it is valid Kotlin, for Kotlin the signature is different). Alternatively, you may be able to use contracts to handle this instead.
It would be interesting to see if you can come up with a contract to solve this. I had the same idea some time ago, but couldn’t figure it out (or simply it wasn’t / isn’t possible), and I’ve ended up with the overload approach.
So far the overload approach is the only solution, because currently contracts only allow you to specify the nullability of the function parameters based on the return value of the function and not the other way around which is what we would need.