| // WITH_STDLIB |
| // WORKS_WHEN_VALUE_CLASS |
| // ISSUE: KT-86123 |
| |
| // Tests that callable reference class deduplication handles generic type parameters correctly |
| // when they have different upper bounds (nullable vs non-nullable, primitive-wrapping value class, etc.) |
| |
| OPTIONAL_JVM_INLINE_ANNOTATION |
| value class W(val x: Long) |
| |
| // T has implicit bound Any? (nullable) => erases to anyNType |
| fun <T> captureNullableBound(t: T): () -> String = { t.toString() } |
| |
| // T : Any (non-nullable) => erases to anyNType (Any is a reference type) |
| fun <T : Any> captureNonNullBound(t: T): () -> String = { t.toString() } |
| |
| // T : W (value class bound wrapping primitive) => erases to W (unboxed) |
| fun <T : W> captureValueClassBound(t: T): () -> String = { t.toString() } |
| |
| // Two different type parameter names with same bound should merge |
| fun <A> captureA(a: A): () -> String = { a.toString() } |
| fun <B> captureB(b: B): () -> String = { b.toString() } |
| |
| fun box(): String { |
| // Nullable bound captures |
| val n1 = captureNullableBound("hello") |
| val n2 = captureNullableBound(42) |
| val n3 = captureNullableBound<String?>(null) |
| if (n1() != "hello") return "FAIL n1: ${n1()}" |
| if (n2() != "42") return "FAIL n2: ${n2()}" |
| if (n3() != "null") return "FAIL n3: ${n3()}" |
| |
| // Non-null bound captures |
| val nn1 = captureNonNullBound("world") |
| val nn2 = captureNonNullBound(99) |
| if (nn1() != "world") return "FAIL nn1: ${nn1()}" |
| if (nn2() != "99") return "FAIL nn2: ${nn2()}" |
| |
| // Value class bound captures |
| val v1 = captureValueClassBound(W(77)) |
| if (v1() != "W(x=77)") return "FAIL v1: ${v1()}" |
| |
| // Different type parameter names, same bound => should merge correctly |
| val a = captureA("from A") |
| val b = captureB("from B") |
| if (a() != "from A") return "FAIL a: ${a()}" |
| if (b() != "from B") return "FAIL b: ${b()}" |
| |
| return "OK" |
| } |