mirror of
https://github.com/jlengrand/kotlin.git
synced 2026-05-11 15:53:46 +00:00
Both for callables obtained via reflection API (KClass.members etc) and for callables obtained via ::-references, the instance parameter is now the class which was used to construct the type at the left-hand side of the reference, NOT the class where the callable is originally declared as is known at compile-time. The reason is to reduce the difference in behavior of KCallable.call vs FunctionN.invoke: the latter always required the subclass instance for a fake override, and it's reasonable that the former would require it as well. Note that in Java reflection, behavior could differ in a similar case. For a simple fake override, Class.getMethod would return the method declared in the base class and that method will accept instances of the base class in invoke. However, it's difficult to rely on this behavior because if there's a bridge for a fake override in the derived class (e.g. when overridden members have different signatures), the returned Method object is accepting the derived class as the receiver. This just confirms the fact that Java reflection operates on a different level of abstraction, namely JVM methods in .class files, which is not applicable to our use cases directly. Another reason not to replicate Java reflection's behavior is the uncertainty as to which member is returned in case there are several in the hierarchy for a given fake override: see the "otherwise one of the methods is chosen arbitrarily" note in javadoc on Class.getMethod. #KT-24170 Fixed
26 lines
573 B
Kotlin
Vendored
26 lines
573 B
Kotlin
Vendored
// IGNORE_BACKEND: JS_IR, JS, NATIVE
|
|
// WITH_REFLECT
|
|
|
|
import kotlin.test.assertNotEquals
|
|
|
|
open class A<T> {
|
|
fun foo(t: T) {}
|
|
}
|
|
|
|
open class B<U> : A<U>()
|
|
|
|
class C : B<String>()
|
|
|
|
fun box(): String {
|
|
val afoo = A::class.members.single { it.name == "foo" }
|
|
val bfoo = B::class.members.single { it.name == "foo" }
|
|
val cfoo = C::class.members.single { it.name == "foo" }
|
|
|
|
assertNotEquals(afoo, bfoo)
|
|
assertNotEquals(afoo.hashCode(), bfoo.hashCode())
|
|
assertNotEquals(bfoo, cfoo)
|
|
assertNotEquals(bfoo.hashCode(), cfoo.hashCode())
|
|
|
|
return "OK"
|
|
}
|