I'm not sure that hard-to-fail is the right word, but here is the problem that I am facing. And it took me a while to reproduce this with the smallest possible example, so here it is:
class BaseParameterizedType<T>
fun <U: BaseParameterizedType<*>> getSpecific(clazz: KClass<in U>) : U {
TODO()
}
fun example(arg: KClass<out BaseParameterizedType<*>>)) {
getSpecific(arg.innerType)
}
Well, that’s why the above code doesn’t work in "TODO", but if it wasn’t there and if the function returned normally, then it certainly fails with an exception from the null pointer. I tried very hard to understand what was going wrong, so I turned to the decompiled Java code (from kotlin bytecode):
public static final void example(@NotNull KClass arg) {
Intrinsics.checkParameterIsNotNull(arg, "arg");
getSpecific(arg.getInnerType());
throw null;
}
If I change the function signature getSpecific(clz: KClass<in U>) : Uto any of these forms:
getSpecific(clz: KClass<out U>) : UgetSpecific(clz: KClass<U>) : UgetSpecific(clz: KClass<in U>) : BaseParameterizedType<*>
or even with a function example(arg: KClass<out BaseParameterizedType<*>)or example(arg: KClass<BaseParameterizedType<*>>), then the generated code:
public static final void example(@NotNull KClass arg) {
Intrinsics.checkParameterIsNotNull(arg, "arg");
getSpecific(arg.getInnerType());
}
Now, say, on the call site, I change it to:
getSpecific(BaseParameterizedType::class)
throw null. , , - kotlin, , , ?
, , arg.innerType KClass<out BaseParameterizedType<*>>, , KClass<in BaseParameterizedType<*>>, U BaseParamterizedType<*>>. , - .
, throw null . , getSpecific, , .