Generic types
A C# generic class reached through at least one closed instantiation (Box<int>, Pairing<string, int>) becomes a real Kotlin generic class, Box<T>, not a monomorphized family like BoxOfInt. This is ADR-072.
A generated instance is a handle wrapper like any other bound C# object: Box<Int> implements AutoCloseable and frees itself when unreachable, so use { } works the same way. See Objects and handles for the lifetime rules.
Members of the generic class, including one that never mentions the type parameter (describe() above), keep working per instantiation, and the class stays polymorphic over T, which is the whole point of not monomorphizing:
Construction
A public C# constructor becomes a fake top-level Kotlin constructor named like the type (Box(value)), one overload per unambiguous instantiation. When two instantiations of the same definition would erase to the same non-null Kotlin parameter list, such as Box<String> and Box<String?> both erasing to (String), both lose their fake constructor. This is a Gradle build warning (skipped_ambiguous_generic_constructor), not a reverse-ir.json diagnostic. An instantiation with no fake constructor is still reachable through any bound factory or member that returns it:
A second type parameter carries its name straight from metadata:
Limitations
A type argument must be a primitive,
string(nullable or not), a bound enum, or a bound class or interface handle. Anything else, including another generic instantiation, a struct, or a BCL generic such asList<int>orDictionary<string, int>, excludes the whole instantiation (skipped_generic_type_argument, orskipped_unbound_generic_instantiationfor a BCL type whose definition lives outside the bound assemblies).No Kotlin type-parameter constraints are emitted:
where T : classdoes not become<T : Any>. You can writeBox<Double>in Kotlin even though no such instantiation is bound; there is no witness or factory for it, so the failure surfaces the first time you try to obtain one, at compile time.A bare type parameter annotated nullable (
T? Peek()) is not representable per instantiation and is skipped (skipped_nullable_type_parameter); the rest of the class still binds.Only generic classes bind. Generic interfaces stay excluded (
skipped_generic_interface; see The bridgeable subset), and generic methods (T Identity<T>(T)) stayskipped_open_genericpermanently, unless a caller can pin the type argument.A generic definition with zero discovered instantiations emits nothing at all: no Kotlin type, no registration, just an
info_uninstantiated_generic_typenote.