Java generics have type erasure. This makes it hard for JVM languages to implement reified generics. Some languages like Scala do, some languages like Kotlin do not.
This unchecked cast is really unchecked, hence the warning. Without reified generics you can't do a proper check, and the compiler will only do the typecheck at the boundary of generic and non-generic code, at runtime. Because your example doesn't really have a non-generic part, no such typecheck is done. The is
expression doesn't require the left hand side to be of any specific type, so even the runtime check is omitted, just like in Java.
Consider the following example where the return value is stored in a variable:
fun main(args: Array<String>) {
var t = TEST<Int, String>()
var k = t.returns("12") // runtime error here
print(k is Int)
}
@Suppress("UNCHECKED_CAST")
class TEST<out T, in R> {
fun returns(r: R): T {
return r as T
}
}
...
Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Number
at MainKt.main(main.kt:3)
Kotlin uses Java-s type checker in many places. If you consider the equvivalent Java code, it behaves the same way:
public class JMain {
public static void main(String[] args) {
TEST<Integer, String> t = new TEST<>();
System.out.println(t.returns("12") instanceof Integer); // false
}
static class TEST<T, R> {
@SuppressWarnings("unchecked")
public T returns(R r) {
return (T)r;
}
}
}