| // DUMP_IR | |
| // WITH_STDLIB | |
| // 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" | |
| } |