Support 'call' for references to inline class members

This includes overriding and non-overriding functions and properties.

 #KT-26748
This commit is contained in:
Dmitry Petrov
2018-10-16 17:39:30 +03:00
parent 5003388d38
commit 94e1701089
13 changed files with 483 additions and 17 deletions
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
import org.jetbrains.kotlin.resolve.isInlineClass
import org.jetbrains.kotlin.resolve.isInlineClassType
import org.jetbrains.kotlin.types.KotlinType
import java.lang.reflect.Member
@@ -49,15 +50,34 @@ internal class InlineClassAwareCaller<out M : Member>(
// and in that case the number of expected arguments is one less than usual, hence -1
-1
}
descriptor.dispatchReceiverParameter != null && caller !is BoundCaller -> 1
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.
if (descriptor.containingDeclaration.isInlineClass())
0
else
1
}
else -> 0
}
val extraArgumentsTail = if (isDefault) 2 else 0
val kotlinParameterTypes =
listOfNotNull(descriptor.extensionReceiverParameter?.type) +
descriptor.valueParameters.map(ValueParameterDescriptor::getType)
val kotlinParameterTypes: List<KotlinType> = ArrayList<KotlinType>().also { kotlinParameterTypes ->
val extensionReceiverType = descriptor.extensionReceiverParameter?.type
if (extensionReceiverType != null) {
kotlinParameterTypes.add(extensionReceiverType)
} else {
val containingDeclaration = descriptor.containingDeclaration
if (containingDeclaration is ClassDescriptor && containingDeclaration.isInline) {
kotlinParameterTypes.add(containingDeclaration.defaultType)
}
}
descriptor.valueParameters.mapTo(kotlinParameterTypes, ValueParameterDescriptor::getType)
}
val expectedArgsSize = kotlinParameterTypes.size + shift + extraArgumentsTail
if (arity != expectedArgsSize) {
throw KotlinReflectionInternalError(
@@ -116,10 +136,14 @@ internal fun <M : Member> CallerImpl<M>.createInlineClassAwareCallerIfNeeded(
val needsInlineAwareCaller =
descriptor.valueParameters.any { it.type.isInlineClassType() } ||
descriptor.returnType?.isInlineClassType() == true ||
(this !is BoundCaller && descriptor.extensionReceiverParameter?.type?.isInlineClassType() == true)
this !is BoundCaller && descriptor.hasInlineClassReceiver()
return if (needsInlineAwareCaller) InlineClassAwareCaller(descriptor, this, isDefault) else this
}
private fun CallableMemberDescriptor.hasInlineClassReceiver() =
expectedReceiverType?.isInlineClassType() == true
internal fun Class<*>.getUnboxMethod(descriptor: CallableMemberDescriptor): Method = try {
getDeclaredMethod("unbox" + JvmAbi.IMPL_SUFFIX_FOR_INLINE_CLASS_MEMBERS)
} catch (e: NoSuchMethodException) {
@@ -137,12 +161,13 @@ internal fun KotlinType.toInlineClass(): Class<*>? {
return null
}
internal fun Any?.coerceToExpectedReceiverType(descriptor: CallableMemberDescriptor): Any? {
val expectedReceiverType =
descriptor.extensionReceiverParameter?.type
?: (descriptor.containingDeclaration as? ClassDescriptor)?.defaultType
private val CallableMemberDescriptor.expectedReceiverType
get() =
extensionReceiverParameter?.type
?: (containingDeclaration as? ClassDescriptor)?.defaultType.takeIf { dispatchReceiverParameter != null }
val unboxMethod = expectedReceiverType?.toInlineClass()?.getUnboxMethod(descriptor) ?: return this
internal fun Any?.coerceToExpectedReceiverType(descriptor: CallableMemberDescriptor): Any? {
val unboxMethod = descriptor.expectedReceiverType?.toInlineClass()?.getUnboxMethod(descriptor) ?: return this
return unboxMethod.invoke(this)
}