I am trying to find the cause of this bug in Moshi...
# compiler
t
I am trying to find the cause of this bug in Moshi: https://github.com/square/moshi/issues/615 (more out of interest than need). The issue is that Moshi and Retrofit have different notions of what the generic type actually is. The underlying cause is that
Foo<Nothing?>
(and
Foo<Nothing>
) compile to a raw type. While that is fine for the runtime it means losing generic information where it would be normally available (such as in method signatures). I have found this (https://github.com/JetBrains/kotlin/commit/9acf3e40de2d22318f9d3eda15e5da47117edbc4#diff-efccdee550f101125771902fc631175a) commit that implemented the Nothing -> raw type conversion. I could not find an explanation. Does someone know the reason behind this decision? How could I recover the Nothing generic argument? Is this the only case that compiles to a raw type?
d
cc @bashor
t
Can't you use kotlinpoet-km to get the real type?
t
I can turn the Java
Method
into a
KFunction
and see the
Nothing?
there (I am assuming the
Method.kotlinFunction
looks at the metadata?), but down in the Moshi function all that is left is a
java.lang.reflect.Type
and a raw class (stemming from
Method.getGenericParameterTypes
). Inspecting the metadata there gives only the metadata of the
Foo<T>
class with a generic
T
. That is already slightly more helpful than before, since now I can actually see that the type has a generic argument; I just don't know what it is (unless I am missing it somewhere). I assume a missing generic parameter type can only be
Nothing?
or
Nothing
, but I have no way of confirming that (not to mention cases where multiple generic arguments exist).
u
I suppose the reason for this decision has to do with the fact that there's no type
kotlin.Nothing
in runtime, it's approximated as
java.lang.Void
. Since
Nothing
is a subtype of all types in Kotlin but
Void
doesn't have this property in the JVM, this means potential conflicts of otherwise compatible generic signatures where e.g. covariant return type override is involved: if a superclass method returns
List<Foo>
but subclass returns
List<Nothing>
, we can only generate the latter as a raw type, to prevent javac or Java reflection from complaining. Also,
I assume a missing generic parameter type can only be
Nothing?
or
Nothing
, but I have no way of confirming that (not to mention cases where multiple generic arguments exist).
Unfortunately, it's not the only case, the raw type can also come from Java:
Copy code
class JavaClass {
    static List getRawList() { ... }
}
Copy code
// foo's JVM type is raw List
fun foo() = JavaClass.getRawList()
👍 2