Noticed some odd behavior around resolving functio...
# announcements
z
Noticed some odd behavior around resolving functions that I think might be a compiler bug, but maybe I’m just missing some rule that actually makes sense. If you have two functions that operate on an interface, and a sub-interface of that interface, when you pass a concrete type to this function the kotlin compiler will resolve the function with the more specific type. However, if this interface takes a type parameter, and the more general overload has a type bound (eg of
Any
), when you pass a value that satisfies the bounds, the compiler suddenly can’t figure out which one to call. So this works:
Copy code
fun <T : Any> StateFlow<T>.thing(): Unit = TODO()
fun <T : Any> Flow<T>.thing(): Unit= TODO()
MutableStateFlow("").thing()
And this:
Copy code
fun <T> StateFlow<T>.thing(): Unit = TODO()
fun <T> Flow<T>.thing(): Unit = TODO()
MutableStateFlow("").thing()
And this:
Copy code
fun <T : Any> StateFlow<T>.thing(): Unit = TODO()
fun <T> Flow<T>.thing(): Unit= TODO()
MutableStateFlow("").thing()
But not this:
Copy code
fun <T> StateFlow<T>.thing(): Unit = TODO()
fun <T : Any> Flow<T>.thing(): Unit = TODO()
MutableStateFlow("").thing()
Seems to happen both with old and new type inference engines.
Casting the type to have a nullable type parameter fixes the error. E.g.
(MutableStateFlow("") as StateFlow<String?>).thing()
This definitely seems like a compiler bug.
m
Here the compiler can't decide which function is more specific. In order to decide, the compiler performs subtyping check: is
StateFlow<T1>
subtype of
Flow<T>
where
T1
is just some type with a supertype of
Any?
and
T
is a type variable with the upperbound of
Any
? If that were true, then the compiler would choose
StateFlow<T>.thing()
as it's receiver would be more specific (its type contains fewer values). But it's not true and the opposite:
Flow<T1>
is also not a subtype of
StateFlow<T>
=> these functions are equally specific
🙏 1
z
Thanks for the explanation. So basically, in the error case, the receiver type is more specific on the first overload, but the generic type is more specific on the second overload, so the math cancels out?
m
Yes