Goal: support run-time access to types passed to functions, as if they were reified (currently limited to inline functions only).
A type parameter of a function can be marked as reified
:
inline fun <reified T> foo() {}
Definition A well-formed type is called runtime-available if
- it has the form
C
, whereC
is a classifier (object, class or trait) that has either no type parameters, or all its type parameters arereified
, with the exception for classNothing
, - it has the form
G<A1, ..., An>
, whereG
is a classifier withn
type parameters, and for every type parameterTi
at least one of the following conditions hold:Ti
is areified
type parameter and the corresponding type argumentAi
is a runtime-available type,Ai
is a star-projection (e.g. forList<*>
,A1
is a star-projection);
- it has the form
T
, andT
is areified
type parameter.
Examples:
- Runtime-available types:
String
,Array<String>
,List<*>
; - Non-runtime-available types:
Nothing
,List<String>
,List<T>
(for anyT
) - Conditional:
T
is runtime-available iff the type parameterT
isreified
, same forArray<T>
Only runtime-available types are allowed as
- right-hand arguments for
is
,!is
,as
,as?
- arguments for
reified
type parameters of calls (for types any arguments are allowed, i.e.Array<List<String>>
is still a valid type).
As a consequence, if T
is a reified
type parameter, the following constructs are allowed:
x is T
,x !is T
x as T
,x as? T
- reflection access on
T
:javaClass<T>()
,T::class
(when supported)
Restrictions regarding reified type parameters:
- Only a type parameter of an
inline
function can be markedreified
- The built-in class
Array
is the only class whose type parameter is markedreified
. Other classes are not allowed to declarereified
type parameters. - Only a runtime-available type can be passed as an argument to a
reified
type parameter
Notes:
- No warning is issued on
inline
functions declaring no inlinable parameters of function types, but having areified
type parameter declared.
In inline functions, occurrences of a reified
type parameter T
are replaced with the actual type argument.
If actual type argument is a primitive type, it's wrapper will be used within reified bytecode.
open class TypeLiteral<T> {
val type: Type
get() = (javaClass.getGenericSuperclass() as ParameterizedType).getActualTypeArguments()[0]
}
inline fun <reified T> typeLiteral(): TypeLiteral<T> = object : TypeLiteral<T>() {} // here T is replaced with the actual type
typeLiteral<String>().type // returns 'class java.lang.String'
typeLiteral<Int>().type // returns 'class java.lang.Integer'
typeLiteral<Array<String>>().type // returns '[Ljava.lang.String;'
typeLiteral<List<*>>().type // returns 'java.util.List<?>'