Unbox bound receiver if inline class type expected

This commit is contained in:
Dmitry Petrov
2018-10-16 12:35:15 +03:00
parent 9c7c0c8952
commit 5003388d38
3 changed files with 50 additions and 35 deletions
@@ -37,7 +37,7 @@ internal class KFunctionImpl private constructor(
name: String,
private val signature: String,
descriptorInitialValue: FunctionDescriptor?,
private val boundReceiver: Any? = CallableReference.NO_RECEIVER
private val rawBoundReceiver: Any? = CallableReference.NO_RECEIVER
) : KCallableImpl<Any?>(), KFunction<Any?>, FunctionBase<Any?>, FunctionWithAllInvokes {
constructor(container: KDeclarationContainerImpl, name: String, signature: String, boundReceiver: Any?)
: this(container, name, signature, null, boundReceiver)
@@ -49,7 +49,7 @@ internal class KFunctionImpl private constructor(
descriptor
)
override val isBound: Boolean get() = boundReceiver != CallableReference.NO_RECEIVER
override val isBound: Boolean get() = rawBoundReceiver != CallableReference.NO_RECEIVER
override val descriptor: FunctionDescriptor by ReflectProperties.lazySoft(descriptorInitialValue) {
container.findFunctionDescriptor(name, signature)
@@ -132,6 +132,9 @@ internal class KFunctionImpl private constructor(
}?.createInlineClassAwareCallerIfNeeded(descriptor, isDefault = true)
}
private val boundReceiver
get() = rawBoundReceiver.coerceToExpectedReceiverType(descriptor)
private fun createStaticMethodCaller(member: Method) =
if (isBound) CallerImpl.Method.BoundStatic(member, boundReceiver) else CallerImpl.Method.Static(member)
@@ -163,7 +166,7 @@ internal class KFunctionImpl private constructor(
override fun equals(other: Any?): Boolean {
val that = other.asKFunctionImpl() ?: return false
return container == that.container && name == that.name && signature == that.signature && boundReceiver == that.boundReceiver
return container == that.container && name == that.name && signature == that.signature && rawBoundReceiver == that.rawBoundReceiver
}
override fun hashCode(): Int =
@@ -21,17 +21,14 @@ import kotlin.reflect.KMutableProperty
import kotlin.reflect.KProperty
import kotlin.reflect.full.IllegalPropertyDelegateAccessException
import kotlin.reflect.jvm.internal.JvmPropertySignature.*
import kotlin.reflect.jvm.internal.calls.Caller
import kotlin.reflect.jvm.internal.calls.CallerImpl
import kotlin.reflect.jvm.internal.calls.ThrowingCaller
import kotlin.reflect.jvm.internal.calls.createInlineClassAwareCallerIfNeeded
import kotlin.reflect.jvm.internal.calls.*
internal abstract class KPropertyImpl<out R> private constructor(
override val container: KDeclarationContainerImpl,
override val name: String,
val signature: String,
descriptorInitialValue: PropertyDescriptor?,
val boundReceiver: Any?
private val rawBoundReceiver: Any?
) : KCallableImpl<R>(), KProperty<R> {
constructor(container: KDeclarationContainerImpl, name: String, signature: String, boundReceiver: Any?) : this(
container, name, signature, null, boundReceiver
@@ -45,7 +42,10 @@ internal abstract class KPropertyImpl<out R> private constructor(
CallableReference.NO_RECEIVER
)
override val isBound: Boolean get() = boundReceiver != CallableReference.NO_RECEIVER
val boundReceiver
get() = rawBoundReceiver.coerceToExpectedReceiverType(descriptor)
override val isBound: Boolean get() = rawBoundReceiver != CallableReference.NO_RECEIVER
private val _javaField = ReflectProperties.lazySoft {
val jvmSignature = RuntimeTypeMapper.mapPropertySignature(descriptor)
@@ -115,7 +115,7 @@ internal abstract class KPropertyImpl<out R> private constructor(
override fun equals(other: Any?): Boolean {
val that = other.asKPropertyImpl() ?: return false
return container == that.container && name == that.name && signature == that.signature && boundReceiver == that.boundReceiver
return container == that.container && name == that.name && signature == that.signature && rawBoundReceiver == that.rawBoundReceiver
}
override fun hashCode(): Int =
@@ -174,6 +174,8 @@ internal abstract class KPropertyImpl<out R> private constructor(
}
}
internal val KPropertyImpl.Accessor<*, *>.boundReceiver
get() = property.boundReceiver
private fun KPropertyImpl.Accessor<*, *>.computeCallerForAccessor(isGetter: Boolean): Caller<*> {
if (KDeclarationContainerImpl.LOCAL_PROPERTY_SIGNATURE.matches(property.signature)) {
@@ -189,10 +191,10 @@ private fun KPropertyImpl.Accessor<*, *>.computeCallerForAccessor(isGetter: Bool
fun computeFieldCaller(field: Field): CallerImpl<Field> = when {
property.descriptor.isJvmFieldPropertyInCompanionObject() || !Modifier.isStatic(field.modifiers) ->
if (isGetter)
if (isBound) CallerImpl.FieldGetter.BoundInstance(field, property.boundReceiver)
if (isBound) CallerImpl.FieldGetter.BoundInstance(field, boundReceiver)
else CallerImpl.FieldGetter.Instance(field)
else
if (isBound) CallerImpl.FieldSetter.BoundInstance(field, isNotNullProperty(), property.boundReceiver)
if (isBound) CallerImpl.FieldSetter.BoundInstance(field, isNotNullProperty(), boundReceiver)
else CallerImpl.FieldSetter.Instance(field, isNotNullProperty())
isJvmStaticProperty() ->
if (isGetter)
@@ -229,13 +231,13 @@ private fun KPropertyImpl.Accessor<*, *>.computeCallerForAccessor(isGetter: Bool
property.javaField ?: throw KotlinReflectionInternalError("No accessors or field is found for property $property")
)
!Modifier.isStatic(accessor.modifiers) ->
if (isBound) CallerImpl.Method.BoundInstance(accessor, property.boundReceiver)
if (isBound) CallerImpl.Method.BoundInstance(accessor, boundReceiver)
else CallerImpl.Method.Instance(accessor)
isJvmStaticProperty() ->
if (isBound) CallerImpl.Method.BoundJvmStaticInObject(accessor)
else CallerImpl.Method.JvmStaticInObject(accessor)
else ->
if (isBound) CallerImpl.Method.BoundStatic(accessor, property.boundReceiver)
if (isBound) CallerImpl.Method.BoundStatic(accessor, boundReceiver)
else CallerImpl.Method.Static(accessor)
}
}
@@ -248,7 +250,7 @@ private fun KPropertyImpl.Accessor<*, *>.computeCallerForAccessor(isGetter: Bool
else jvmSignature.setterMethod ?: throw KotlinReflectionInternalError(
"No source found for setter of Java method property: ${jvmSignature.getterMethod}"
)
if (isBound) CallerImpl.Method.BoundInstance(method, property.boundReceiver)
if (isBound) CallerImpl.Method.BoundInstance(method, boundReceiver)
else CallerImpl.Method.Instance(method)
}
is MappedKotlinProperty -> {
@@ -261,7 +263,7 @@ private fun KPropertyImpl.Accessor<*, *>.computeCallerForAccessor(isGetter: Bool
assert(!Modifier.isStatic(accessor.modifiers)) { "Mapped property cannot have a static accessor: $property" }
return if (isBound) CallerImpl.Method.BoundInstance(accessor, property.boundReceiver)
return if (isBound) CallerImpl.Method.BoundInstance(accessor, boundReceiver)
else CallerImpl.Method.Instance(accessor)
}
}.createInlineClassAwareCallerIfNeeded(descriptor)
@@ -74,7 +74,7 @@ internal class InlineClassAwareCaller<out M : Member>(
val unbox = Array(expectedArgsSize) { i ->
if (i in argumentRange) {
kotlinParameterTypes[i - shift].toInlineClass()?.getUnboxMethod()
kotlinParameterTypes[i - shift].toInlineClass()?.getUnboxMethod(descriptor)
} else null
}
@@ -103,27 +103,10 @@ internal class InlineClassAwareCaller<out M : Member>(
}
private fun Class<*>.getBoxMethod(): Method = try {
getDeclaredMethod("box" + JvmAbi.IMPL_SUFFIX_FOR_INLINE_CLASS_MEMBERS, getUnboxMethod().returnType)
getDeclaredMethod("box" + JvmAbi.IMPL_SUFFIX_FOR_INLINE_CLASS_MEMBERS, getUnboxMethod(descriptor).returnType)
} catch (e: NoSuchMethodException) {
throw KotlinReflectionInternalError("No box method found in inline class: $this (calling $descriptor)")
}
private fun Class<*>.getUnboxMethod(): Method = try {
getDeclaredMethod("unbox" + JvmAbi.IMPL_SUFFIX_FOR_INLINE_CLASS_MEMBERS)
} catch (e: NoSuchMethodException) {
throw KotlinReflectionInternalError("No unbox method found in inline class: $this (calling $descriptor)")
}
private fun KotlinType.toInlineClass(): Class<*>? {
val descriptor = constructor.declarationDescriptor
if (descriptor is ClassDescriptor && descriptor.isInline) {
return descriptor.toJavaClass() ?: throw KotlinReflectionInternalError(
"Class object for the class ${descriptor.name} cannot be found (classId=${descriptor.classId})"
)
}
return null
}
}
internal fun <M : Member> CallerImpl<M>.createInlineClassAwareCallerIfNeeded(
@@ -136,3 +119,30 @@ internal fun <M : Member> CallerImpl<M>.createInlineClassAwareCallerIfNeeded(
(this !is BoundCaller && descriptor.extensionReceiverParameter?.type?.isInlineClassType() == true)
return if (needsInlineAwareCaller) InlineClassAwareCaller(descriptor, this, isDefault) else this
}
internal fun Class<*>.getUnboxMethod(descriptor: CallableMemberDescriptor): Method = try {
getDeclaredMethod("unbox" + JvmAbi.IMPL_SUFFIX_FOR_INLINE_CLASS_MEMBERS)
} catch (e: NoSuchMethodException) {
throw KotlinReflectionInternalError("No unbox method found in inline class: $this (calling $descriptor)")
}
internal fun KotlinType.toInlineClass(): Class<*>? {
val descriptor = constructor.declarationDescriptor
if (descriptor is ClassDescriptor && descriptor.isInline) {
return descriptor.toJavaClass() ?: throw KotlinReflectionInternalError(
"Class object for the class ${descriptor.name} cannot be found (classId=${descriptor.classId})"
)
}
return null
}
internal fun Any?.coerceToExpectedReceiverType(descriptor: CallableMemberDescriptor): Any? {
val expectedReceiverType =
descriptor.extensionReceiverParameter?.type
?: (descriptor.containingDeclaration as? ClassDescriptor)?.defaultType
val unboxMethod = expectedReceiverType?.toInlineClass()?.getUnboxMethod(descriptor) ?: return this
return unboxMethod.invoke(this)
}