blob: 31a3482ca13f498508dc1bb061f30461eab10e29 [file]
// DUMP_IR
// WITH_STDLIB
// MUTE_LL_FIR
// ^ backend plugins are not executed -> declarations in dependent module are not visible
// MODULE: a
// FILE: src.kt
import org.jetbrains.kotlin.plugin.sandbox.GenerateClassFamily
open class SourceBase {
val srcField: String = "src"
}
// Test (6): source-declared outer that gets a plugin-generated nested class added inside it.
class SourceWithNested
// Test (7): source-declared outer that gets a plugin-generated companion object added inside it.
class SourceWithCompanion
// Tests (9)-(12): source-declared outer classes that get plugin-generated inner classes added.
class SourceOuterPlain
class SourceOuterPlain2
class SourceOuterGeneric<T>
class SourceOuterGenericPaired<T>
// Test (16): source-declared interface used as the supertype of a generated inner class, where the
// outer class's type parameter is captured in the supertype (`InnerBox : Box<T>`).
interface Box<T> {
val value: T
}
@GenerateClassFamily
class Marker
// MODULE: b(a)
// FILE: main.kt
fun box(): String {
// (1) Plain class — generated by the plugin, no generics, extends Any.
val plain = Plain()
if (plain.x != 42) return "FAIL plain.x: ${plain.x}"
if (plain.foo() != "ok") return "FAIL plain.foo: ${plain.foo()}"
// (2) Generic class — exercises type-parameter conversion on the class itself.
val generic = WithGeneric<String>()
if (generic.x != 42) return "FAIL generic.x: ${generic.x}"
if (generic.foo() != "ok") return "FAIL generic.foo: ${generic.foo()}"
// (3) Inherits a source-declared class — declared + inherited members must resolve.
val es = ExtendsSource()
if (es.x != 42) return "FAIL es.x: ${es.x}"
if (es.foo() != "ok") return "FAIL es.foo: ${es.foo()}"
if (es.srcField != "src") return "FAIL es.srcField (inherited from source): ${es.srcField}"
// (4) Inherits another plugin-generated class — declared + inherited members must resolve.
val ep = ExtendsPlain()
if (ep.x != 42) return "FAIL ep.x (inherited from Plain): ${ep.x}"
if (ep.foo() != "ok") return "FAIL ep.foo (inherited from Plain): ${ep.foo()}"
// (5) Sealed class + subclasses — module b needs the inheritor list in metadata so the
// exhaustive `when` below compiles without an `else` branch.
val s: MySealed = SubA()
val tag: String = when (s) {
is SubA -> "a"
is SubB -> "b"
}
if (tag != "a") return "FAIL sealed when: $tag"
if (s.x != 42) return "FAIL sealed inherited x: ${s.x}"
// (6) Generated nested class for a source-declared outer.
val nested = SourceWithNested.Nested()
if (nested.x != 42) return "FAIL nested.x: ${nested.x}"
if (nested.foo() != "ok") return "FAIL nested.foo: ${nested.foo()}"
// (7) Generated companion object for a source-declared outer.
if (SourceWithCompanion.x != 42) return "FAIL companion.x: ${SourceWithCompanion.x}"
// (8) Outer class that's plugin-generated AND has its own nested + companion.
val inner = WithNestedFamily.Inner()
if (inner.x != 42) return "FAIL inner.x: ${inner.x}"
if (WithNestedFamily.fromCompanion() != "from-companion") return "FAIL companion fn"
// (9) Inner class with no generics inside an outer with no generics.
val innerA = SourceOuterPlain().InnerPlain()
if (innerA.x != 42) return "FAIL innerA.x: ${innerA.x}"
if (innerA.foo() != "ok") return "FAIL innerA.foo: ${innerA.foo()}"
// (10) Inner class with no generics inside an outer with generics.
val innerB = SourceOuterGeneric<String>().InnerPlain()
if (innerB.x != 42) return "FAIL innerB.x: ${innerB.x}"
if (innerB.foo() != "ok") return "FAIL innerB.foo: ${innerB.foo()}"
// (11) Inner class with generics inside an outer with no generics.
val innerC = SourceOuterPlain2().InnerGeneric<String>()
if (innerC.x != 42) return "FAIL innerC.x: ${innerC.x}"
if (innerC.foo() != "ok") return "FAIL innerC.foo: ${innerC.foo()}"
// (12) Both inner and outer generic.
val innerD = SourceOuterGenericPaired<Int>().InnerGeneric<String>()
if (innerD.x != 42) return "FAIL innerD.x: ${innerD.x}"
if (innerD.foo() != "ok") return "FAIL innerD.foo: ${innerD.foo()}"
// (13) Inner class inside a plugin-generated outer (both generic).
val withInner = WithInnerFamily<Int>()
val innerE = withInner.Inner<String>()
if (innerE.x != 42) return "FAIL innerE.x: ${innerE.x}"
if (innerE.foo() != "ok") return "FAIL innerE.foo: ${innerE.foo()}"
// (14) Deep generic inner chain: three levels of inner-class generics, all plugin-generated.
val deep = WithDeepInnerFamily<Int>().Inner<String>().DeeplyInner<Double>()
if (deep.x != 42) return "FAIL deep.x: ${deep.x}"
if (deep.foo() != "ok") return "FAIL deep.foo: ${deep.foo()}"
// `self()`'s metadata return type must round-trip with all three type arguments in canonical
// (own-first) order. This explicitly-typed assignment only compiles if the inner-class type
// parameters were registered correctly across the whole enclosing chain.
val deepSelf: WithDeepInnerFamily<Int>.Inner<String>.DeeplyInner<Double> = deep.self()
if (deepSelf.x != 42) return "FAIL deepSelf.x: ${deepSelf.x}"
// (15) Functions on DeeplyInner returning the type parameter at each level of the chain:
// own C (Double), captured B from Inner (String), captured A from WithDeepInnerFamily (Int).
val c: Double = deep.idC(3.14)
if (c != 3.14) return "FAIL deep.idC: $c"
val b: String = deep.idB("hi")
if (b != "hi") return "FAIL deep.idB: $b"
val a: Int = deep.idA(7)
if (a != 7) return "FAIL deep.idA: $a"
// (16) The outer type parameter is captured in the inner class's supertype: InnerBox : Box<T>.
// Using the inner instance through the Box<String> supertype only type-checks if the captured
// type parameter was substituted correctly during IR -> cone conversion of the supertype.
val outerBox = Outer<String>()
val ib: Box<String> = outerBox.InnerBox("boxed")
if (ib.value != "boxed") return "FAIL ib.value: ${ib.value}"
val ib2 = outerBox.InnerBox("direct")
if (ib2.value != "direct") return "FAIL ib2.value: ${ib2.value}"
return "OK"
}