KT-26765: Support 'call' for constructors with inline class parameters
This commit is contained in:
@@ -18,6 +18,7 @@ package kotlin.reflect.jvm.internal
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.resolve.jvm.shouldHideConstructorDueToInlineClassTypeValueParameters
|
||||
import java.lang.reflect.Constructor
|
||||
import java.lang.reflect.Member
|
||||
import java.lang.reflect.Method
|
||||
@@ -76,7 +77,7 @@ internal class KFunctionImpl private constructor(
|
||||
|
||||
when (member) {
|
||||
is Constructor<*> ->
|
||||
createConstructorCaller(member)
|
||||
createConstructorCaller(member, descriptor)
|
||||
is Method -> when {
|
||||
!Modifier.isStatic(member.modifiers) ->
|
||||
createInstanceMethodCaller(member)
|
||||
@@ -112,7 +113,7 @@ internal class KFunctionImpl private constructor(
|
||||
|
||||
when (member) {
|
||||
is Constructor<*> ->
|
||||
createConstructorCaller(member)
|
||||
createConstructorCaller(member, descriptor)
|
||||
is Method -> when {
|
||||
// Note that static $default methods for @JvmStatic functions are generated differently in objects and companion objects.
|
||||
// In objects, $default's signature does _not_ contain the additional object instance parameter,
|
||||
@@ -140,8 +141,19 @@ internal class KFunctionImpl private constructor(
|
||||
private fun createInstanceMethodCaller(member: Method) =
|
||||
if (isBound) CallerImpl.Method.BoundInstance(member, boundReceiver) else CallerImpl.Method.Instance(member)
|
||||
|
||||
private fun createConstructorCaller(member: Constructor<*>) =
|
||||
if (isBound) CallerImpl.BoundConstructor(member, boundReceiver) else CallerImpl.Constructor(member)
|
||||
private fun createConstructorCaller(member: Constructor<*>, descriptor: FunctionDescriptor): CallerImpl<Constructor<*>> {
|
||||
return if (shouldHideConstructorDueToInlineClassTypeValueParameters(descriptor)) {
|
||||
if (isBound)
|
||||
CallerImpl.AccessorForHiddenBoundConstructor(member, boundReceiver)
|
||||
else
|
||||
CallerImpl.AccessorForHiddenConstructor(member)
|
||||
} else {
|
||||
if (isBound)
|
||||
CallerImpl.BoundConstructor(member, boundReceiver)
|
||||
else
|
||||
CallerImpl.Constructor(member)
|
||||
}
|
||||
}
|
||||
|
||||
override val arity: Int get() = caller.arity
|
||||
|
||||
|
||||
@@ -55,6 +55,32 @@ internal sealed class CallerImpl<out M : Member>(
|
||||
}
|
||||
}
|
||||
|
||||
class AccessorForHiddenConstructor(
|
||||
constructor: ReflectConstructor<*>
|
||||
) : CallerImpl<ReflectConstructor<*>>(
|
||||
constructor, constructor.declaringClass, null,
|
||||
constructor.genericParameterTypes.dropLast()
|
||||
) {
|
||||
override fun call(args: Array<*>): Any? {
|
||||
checkArguments(args)
|
||||
return member.newInstance(*args, null)
|
||||
}
|
||||
}
|
||||
|
||||
class AccessorForHiddenBoundConstructor(
|
||||
constructor: ReflectConstructor<*>,
|
||||
private val boundReceiver: Any?
|
||||
) : CallerImpl<ReflectConstructor<*>>(
|
||||
constructor, constructor.declaringClass,
|
||||
null,
|
||||
constructor.genericParameterTypes.dropFirstAndLast()
|
||||
), BoundCaller {
|
||||
override fun call(args: Array<*>): Any? {
|
||||
checkArguments(args)
|
||||
return member.newInstance(boundReceiver, *args, null)
|
||||
}
|
||||
}
|
||||
|
||||
sealed class Method(
|
||||
method: ReflectMethod,
|
||||
requiresInstance: Boolean = !Modifier.isStatic(method.modifiers),
|
||||
@@ -211,5 +237,13 @@ internal sealed class CallerImpl<out M : Member>(
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
inline fun <reified T> Array<out T>.dropFirst(): Array<T> =
|
||||
if (size <= 1) emptyArray() else copyOfRange(1, size) as Array<T>
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
inline fun <reified T> Array<out T>.dropLast(): Array<T> =
|
||||
if (size <= 1) emptyArray() else copyOfRange(0, size - 1) as Array<T>
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
inline fun <reified T> Array<out T>.dropFirstAndLast(): Array<T> =
|
||||
if (size <= 2) emptyArray() else copyOfRange(1, size - 1) as Array<T>
|
||||
}
|
||||
}
|
||||
|
||||
+22
-6
@@ -52,6 +52,9 @@ internal class InlineClassAwareCaller<out M : Member>(
|
||||
-1
|
||||
}
|
||||
|
||||
descriptor is ConstructorDescriptor ->
|
||||
if (caller is BoundCaller) -1 else 0
|
||||
|
||||
descriptor.dispatchReceiverParameter != null && caller !is BoundCaller -> {
|
||||
// If we have an unbound reference to the inline class member,
|
||||
// its receiver (which is passed as argument 0) should also be unboxed.
|
||||
@@ -70,7 +73,12 @@ internal class InlineClassAwareCaller<out M : Member>(
|
||||
val extensionReceiverType = descriptor.extensionReceiverParameter?.type
|
||||
if (extensionReceiverType != null) {
|
||||
kotlinParameterTypes.add(extensionReceiverType)
|
||||
} else if (descriptor !is ConstructorDescriptor) {
|
||||
} else if (descriptor is ConstructorDescriptor) {
|
||||
val constructedClass = descriptor.constructedClass
|
||||
if (constructedClass.isInner) {
|
||||
kotlinParameterTypes.add((constructedClass.containingDeclaration as ClassDescriptor).defaultType)
|
||||
}
|
||||
} else {
|
||||
val containingDeclaration = descriptor.containingDeclaration
|
||||
if (containingDeclaration is ClassDescriptor && containingDeclaration.isInline) {
|
||||
kotlinParameterTypes.add(containingDeclaration.defaultType)
|
||||
@@ -162,13 +170,21 @@ internal fun KotlinType.toInlineClass(): Class<*>? {
|
||||
return null
|
||||
}
|
||||
|
||||
private val CallableMemberDescriptor.expectedReceiverType
|
||||
get() =
|
||||
extensionReceiverParameter?.type
|
||||
?: (containingDeclaration as? ClassDescriptor)?.defaultType.takeIf { dispatchReceiverParameter != null }
|
||||
private val CallableMemberDescriptor.expectedReceiverType: KotlinType?
|
||||
get() {
|
||||
val extensionReceiver = extensionReceiverParameter
|
||||
val dispatchReceiver = dispatchReceiverParameter
|
||||
return when {
|
||||
extensionReceiver != null -> extensionReceiver.type
|
||||
dispatchReceiver == null -> null
|
||||
this is ConstructorDescriptor -> dispatchReceiver.type
|
||||
else -> (containingDeclaration as? ClassDescriptor)?.defaultType
|
||||
}
|
||||
}
|
||||
|
||||
internal fun Any?.coerceToExpectedReceiverType(descriptor: CallableMemberDescriptor): Any? {
|
||||
val unboxMethod = descriptor.expectedReceiverType?.toInlineClass()?.getUnboxMethod(descriptor) ?: return this
|
||||
val expectedReceiverType = descriptor.expectedReceiverType
|
||||
val unboxMethod = expectedReceiverType?.toInlineClass()?.getUnboxMethod(descriptor) ?: return this
|
||||
|
||||
return unboxMethod.invoke(this)
|
||||
}
|
||||
Reference in New Issue
Block a user