Support 'call' for primary value of an inline class

Getter of a primary value of an inline class belongs to the box class.
Its arguments should not be unboxed when the method is called.
However, its result might require boxing if it's an inline class value.

When we have an internal primary value, there's no getter method.
In fact, we can use box/unbox methods for inline class directly
(don't forget to box the result, it may be an inline class type value).

 #KT-26748
This commit is contained in:
Dmitry Petrov
2018-11-08 16:27:32 +03:00
parent 78ee48e1cd
commit 99d8f2eb0c
15 changed files with 369 additions and 36 deletions
@@ -256,7 +256,7 @@ class PropertyReferenceCodegen(
}
val declaration = DescriptorUtils.unwrapFakeOverride(accessor).original
val method =
if (callable.containingDeclaration.isInlineClass())
if (callable.containingDeclaration.isInlineClass() && !declaration.isGetterOfUnderlyingPropertyOfInlineClass())
state.typeMapper.mapSignatureForInlineErasedClassSkipGeneric(declaration).asmMethod
else
state.typeMapper.mapAsmMethod(declaration)
@@ -17,9 +17,11 @@
package org.jetbrains.kotlin.codegen.context
import org.jetbrains.kotlin.codegen.OwnerKind
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.resolve.isGetterOfUnderlyingPropertyOfInlineClass
import org.jetbrains.kotlin.resolve.isInlineClass
import org.jetbrains.org.objectweb.asm.Type
@@ -34,13 +36,19 @@ object CodegenContextUtil {
@JvmStatic
fun isImplementationOwner(owner: CodegenContext<*>, descriptor: DeclarationDescriptor): Boolean {
if (descriptor.containingDeclaration?.isInlineClass() == true) {
if (descriptor is CallableDescriptor && descriptor.containingDeclaration.isInlineClass()) {
val isInErasedMethod = owner.contextKind == OwnerKind.ERASED_INLINE_CLASS
if (descriptor.isGetterOfUnderlyingPropertyOfInlineClass()) {
return !isInErasedMethod
}
when (descriptor) {
is FunctionDescriptor -> return isInErasedMethod
is PropertyDescriptor -> return !isInErasedMethod
}
}
return owner !is MultifileClassFacadeContext
}
}
@@ -0,0 +1,39 @@
// IGNORE_BACKEND: JS_IR, JS, NATIVE, JVM_IR
// WITH_REFLECT
import kotlin.test.assertEquals
inline class Z(internal val x: Int)
inline class Z2(internal val x: Z)
inline class L(internal val x: Long)
inline class L2(internal val x: L)
inline class A(internal val x: Any?)
inline class A2(internal val x: A)
fun box(): String {
assertEquals(42, Z::x.call(Z(42)))
assertEquals(42, Z(42)::x.call())
assertEquals(1234L, L::x.call(L(1234L)))
assertEquals(1234L, L(1234L)::x.call())
assertEquals("abc", A::x.call(A("abc")))
assertEquals("abc", A("abc")::x.call())
assertEquals(null, A::x.call(A(null)))
assertEquals(null, A(null)::x.call())
assertEquals(Z(42), Z2::x.call(Z2(Z(42))))
assertEquals(Z(42), Z2(Z(42))::x.call())
assertEquals(L(1234L), L2::x.call(L2(L(1234L))))
assertEquals(L(1234L), L2(L(1234L))::x.call())
assertEquals(A("abc"), A2::x.call(A2(A("abc"))))
assertEquals(A("abc"), A2(A("abc"))::x.call())
assertEquals(A(null), A2::x.call(A2(A(null))))
assertEquals(A(null), A2(A(null))::x.call())
return "OK"
}
@@ -0,0 +1,39 @@
// IGNORE_BACKEND: JS_IR, JS, NATIVE, JVM_IR
// WITH_REFLECT
import kotlin.test.assertEquals
inline class Z(val x: Int)
inline class Z2(val x: Z)
inline class L(val x: Long)
inline class L2(val x: L)
inline class A(val x: Any?)
inline class A2(val x: A)
fun box(): String {
assertEquals(42, Z::x.call(Z(42)))
assertEquals(42, Z(42)::x.call())
assertEquals(1234L, L::x.call(L(1234L)))
assertEquals(1234L, L(1234L)::x.call())
assertEquals("abc", A::x.call(A("abc")))
assertEquals("abc", A("abc")::x.call())
assertEquals(null, A::x.call(A(null)))
assertEquals(null, A(null)::x.call())
assertEquals(Z(42), Z2::x.call(Z2(Z(42))))
assertEquals(Z(42), Z2(Z(42))::x.call())
assertEquals(L(1234L), L2::x.call(L2(L(1234L))))
assertEquals(L(1234L), L2(L(1234L))::x.call())
assertEquals(A("abc"), A2::x.call(A2(A("abc"))))
assertEquals(A("abc"), A2(A("abc"))::x.call())
assertEquals(A(null), A2::x.call(A2(A(null))))
assertEquals(A(null), A2(A(null))::x.call())
return "OK"
}
@@ -0,0 +1,39 @@
// IGNORE_BACKEND: JVM_IR, JS_IR, JS, NATIVE
// WITH_REFLECT
import kotlin.reflect.jvm.*
import kotlin.test.assertEquals
inline class Z1(val publicX: Int) {
companion object {
val publicXRef = Z1::publicX
val publicXBoundRef = Z1(42)::publicX
}
}
inline class Z2(internal val internalX: Int) {
companion object {
val internalXRef = Z2::internalX
val internalXBoundRef = Z2(42)::internalX
}
}
inline class Z3(private val privateX: Int) {
companion object {
val privateXRef = Z3::privateX
val privateXBoundRef = Z3(42)::privateX
}
}
fun box(): String {
assertEquals("getPublicX", Z1.publicXRef.javaGetter!!.name)
assertEquals("getPublicX", Z1.publicXBoundRef.javaGetter!!.name)
assertEquals(null, Z2.internalXRef.javaGetter)
assertEquals(null, Z2.internalXBoundRef.javaGetter)
assertEquals(null, Z3.privateXRef.javaGetter)
assertEquals(null, Z3.privateXBoundRef.javaGetter)
return "OK"
}
@@ -0,0 +1,60 @@
// IGNORE_BACKEND: JVM_IR, JS_IR, JS, NATIVE
// WITH_REFLECT
import kotlin.reflect.KCallable
import kotlin.reflect.jvm.*
import kotlin.test.assertEquals
inline class Z1(val publicX: Int) {
companion object {
val publicXRef = Z1::publicX
val publicXBoundRef = Z1(42)::publicX
}
}
inline class Z2(internal val internalX: Int) {
companion object {
val internalXRef = Z2::internalX
val internalXBoundRef = Z2(42)::internalX
}
}
inline class Z3(private val privateX: Int) {
companion object {
val privateXRef = Z3::privateX
val privateXBoundRef = Z3(42)::privateX
}
}
inline class ZZ(val x: Z1)
fun KCallable<*>.getJavaTypesOfParams() = parameters.map { it.type.javaType }.toString()
fun KCallable<*>.getJavaTypeOfResult() = returnType.javaType.toString()
fun box(): String {
assertEquals("[class Z1]", Z1.publicXRef.getJavaTypesOfParams())
assertEquals("int", Z1.publicXRef.getJavaTypeOfResult())
assertEquals("[]", Z1.publicXBoundRef.getJavaTypesOfParams())
assertEquals("int", Z1.publicXBoundRef.getJavaTypeOfResult())
assertEquals("[class Z2]", Z2.internalXRef.getJavaTypesOfParams())
assertEquals("int", Z2.internalXRef.getJavaTypeOfResult())
assertEquals("[]", Z2.internalXBoundRef.getJavaTypesOfParams())
assertEquals("int", Z2.internalXBoundRef.getJavaTypeOfResult())
assertEquals("[class Z3]", Z3.privateXRef.getJavaTypesOfParams())
assertEquals("int", Z3.privateXRef.getJavaTypeOfResult())
assertEquals("[]", Z3.privateXBoundRef.getJavaTypesOfParams())
assertEquals("int", Z3.privateXBoundRef.getJavaTypeOfResult())
assertEquals("[class ZZ]", ZZ::x.getJavaTypesOfParams())
// KT-28170
assertEquals("int", ZZ::x.getJavaTypeOfResult())
return "OK"
}
@@ -19313,6 +19313,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/inlineClassConstructor.kt");
}
@TestMetadata("internalPrimaryValOfInlineClass.kt")
public void testInternalPrimaryValOfInlineClass() throws Exception {
runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/internalPrimaryValOfInlineClass.kt");
}
@TestMetadata("jvmStaticFieldInObject.kt")
public void testJvmStaticFieldInObject() throws Exception {
runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/jvmStaticFieldInObject.kt");
@@ -19343,6 +19348,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/overridingVarOfInlineClass.kt");
}
@TestMetadata("primaryValOfInlineClass.kt")
public void testPrimaryValOfInlineClass() throws Exception {
runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/primaryValOfInlineClass.kt");
}
@TestMetadata("properties.kt")
public void testProperties() throws Exception {
runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/properties.kt");
@@ -20150,6 +20160,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/reflection/mapping/functions.kt");
}
@TestMetadata("inlineClassPrimaryVal.kt")
public void testInlineClassPrimaryVal() throws Exception {
runTest("compiler/testData/codegen/box/reflection/mapping/inlineClassPrimaryVal.kt");
}
@TestMetadata("inlineReifiedFun.kt")
public void testInlineReifiedFun() throws Exception {
runTest("compiler/testData/codegen/box/reflection/mapping/inlineReifiedFun.kt");
@@ -20293,6 +20308,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/reflection/mapping/types/inlineClassInSignature.kt");
}
@TestMetadata("inlineClassPrimaryVal.kt")
public void testInlineClassPrimaryVal() throws Exception {
runTest("compiler/testData/codegen/box/reflection/mapping/types/inlineClassPrimaryVal.kt");
}
@TestMetadata("innerGenericTypeArgument.kt")
public void testInnerGenericTypeArgument() throws Exception {
runTest("compiler/testData/codegen/box/reflection/mapping/types/innerGenericTypeArgument.kt");
@@ -19313,6 +19313,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/inlineClassConstructor.kt");
}
@TestMetadata("internalPrimaryValOfInlineClass.kt")
public void testInternalPrimaryValOfInlineClass() throws Exception {
runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/internalPrimaryValOfInlineClass.kt");
}
@TestMetadata("jvmStaticFieldInObject.kt")
public void testJvmStaticFieldInObject() throws Exception {
runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/jvmStaticFieldInObject.kt");
@@ -19343,6 +19348,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/overridingVarOfInlineClass.kt");
}
@TestMetadata("primaryValOfInlineClass.kt")
public void testPrimaryValOfInlineClass() throws Exception {
runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/primaryValOfInlineClass.kt");
}
@TestMetadata("properties.kt")
public void testProperties() throws Exception {
runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/properties.kt");
@@ -20150,6 +20160,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/reflection/mapping/functions.kt");
}
@TestMetadata("inlineClassPrimaryVal.kt")
public void testInlineClassPrimaryVal() throws Exception {
runTest("compiler/testData/codegen/box/reflection/mapping/inlineClassPrimaryVal.kt");
}
@TestMetadata("inlineReifiedFun.kt")
public void testInlineReifiedFun() throws Exception {
runTest("compiler/testData/codegen/box/reflection/mapping/inlineReifiedFun.kt");
@@ -20293,6 +20308,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/reflection/mapping/types/inlineClassInSignature.kt");
}
@TestMetadata("inlineClassPrimaryVal.kt")
public void testInlineClassPrimaryVal() throws Exception {
runTest("compiler/testData/codegen/box/reflection/mapping/types/inlineClassPrimaryVal.kt");
}
@TestMetadata("innerGenericTypeArgument.kt")
public void testInnerGenericTypeArgument() throws Exception {
runTest("compiler/testData/codegen/box/reflection/mapping/types/innerGenericTypeArgument.kt");
@@ -19318,6 +19318,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/inlineClassConstructor.kt");
}
@TestMetadata("internalPrimaryValOfInlineClass.kt")
public void testInternalPrimaryValOfInlineClass() throws Exception {
runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/internalPrimaryValOfInlineClass.kt");
}
@TestMetadata("jvmStaticFieldInObject.kt")
public void testJvmStaticFieldInObject() throws Exception {
runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/jvmStaticFieldInObject.kt");
@@ -19348,6 +19353,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/overridingVarOfInlineClass.kt");
}
@TestMetadata("primaryValOfInlineClass.kt")
public void testPrimaryValOfInlineClass() throws Exception {
runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/primaryValOfInlineClass.kt");
}
@TestMetadata("properties.kt")
public void testProperties() throws Exception {
runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/properties.kt");
@@ -20155,6 +20165,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/reflection/mapping/functions.kt");
}
@TestMetadata("inlineClassPrimaryVal.kt")
public void testInlineClassPrimaryVal() throws Exception {
runTest("compiler/testData/codegen/box/reflection/mapping/inlineClassPrimaryVal.kt");
}
@TestMetadata("inlineReifiedFun.kt")
public void testInlineReifiedFun() throws Exception {
runTest("compiler/testData/codegen/box/reflection/mapping/inlineReifiedFun.kt");
@@ -20298,6 +20313,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/reflection/mapping/types/inlineClassInSignature.kt");
}
@TestMetadata("inlineClassPrimaryVal.kt")
public void testInlineClassPrimaryVal() throws Exception {
runTest("compiler/testData/codegen/box/reflection/mapping/types/inlineClassPrimaryVal.kt");
}
@TestMetadata("innerGenericTypeArgument.kt")
public void testInnerGenericTypeArgument() throws Exception {
runTest("compiler/testData/codegen/box/reflection/mapping/types/innerGenericTypeArgument.kt");
@@ -58,6 +58,9 @@ fun KotlinType.isNullableUnderlyingType(): Boolean {
return TypeUtils.isNullableType(underlyingType)
}
fun CallableDescriptor.isGetterOfUnderlyingPropertyOfInlineClass() =
this is PropertyGetterDescriptor && correspondingProperty.isUnderlyingPropertyOfInlineClass()
fun VariableDescriptor.isUnderlyingPropertyOfInlineClass(): Boolean {
val containingDeclaration = this.containingDeclaration
if (!containingDeclaration.isInlineClass()) return false
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil
import org.jetbrains.kotlin.resolve.DescriptorFactory
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.isUnderlyingPropertyOfInlineClass
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPropertyDescriptor
import org.jetbrains.kotlin.types.TypeUtils
import java.lang.reflect.Field
@@ -226,9 +227,20 @@ private fun KPropertyImpl.Accessor<*, *>.computeCallerForAccessor(isGetter: Bool
}
when {
accessor == null -> computeFieldCaller(
property.javaField ?: throw KotlinReflectionInternalError("No accessors or field is found for property $property")
)
accessor == null -> {
if (property.descriptor.isUnderlyingPropertyOfInlineClass() &&
property.descriptor.visibility == Visibilities.INTERNAL
) {
val unboxMethod = property.descriptor.containingDeclaration.toInlineClass()?.getUnboxMethod(property.descriptor)
?: throw KotlinReflectionInternalError("Underlying property of inline class $property should have a field")
if (isBound) InternalUnderlyingValOfInlineClass.Bound(unboxMethod, boundReceiver)
else InternalUnderlyingValOfInlineClass.Unbound(unboxMethod)
} else {
val javaField = property.javaField
?: throw KotlinReflectionInternalError("No accessors or field is found for property $property")
computeFieldCaller(javaField)
}
}
!Modifier.isStatic(accessor.modifiers) ->
if (isBound) CallerImpl.Method.BoundInstance(accessor, boundReceiver)
else CallerImpl.Method.Instance(accessor)
@@ -5,14 +5,13 @@
package kotlin.reflect.jvm.internal.calls
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
import org.jetbrains.kotlin.resolve.isGetterOfUnderlyingPropertyOfInlineClass
import org.jetbrains.kotlin.resolve.isInlineClass
import org.jetbrains.kotlin.resolve.isInlineClassType
import org.jetbrains.kotlin.resolve.isUnderlyingPropertyOfInlineClass
import org.jetbrains.kotlin.types.KotlinType
import java.lang.reflect.Member
import java.lang.reflect.Method
@@ -24,9 +23,9 @@ import kotlin.reflect.jvm.internal.toJavaClass
* A caller that is used whenever the declaration has inline classes in its parameter types or return type.
* Each argument of an inline class type is unboxed, and the return value (if it's of an inline class type) is boxed.
*/
internal class InlineClassAwareCaller<out M : Member>(
internal class InlineClassAwareCaller<out M : Member?>(
private val descriptor: CallableMemberDescriptor,
private val caller: CallerImpl<M>,
private val caller: Caller<M>,
private val isDefault: Boolean
) : Caller<M> {
override val member: M
@@ -45,6 +44,15 @@ internal class InlineClassAwareCaller<out M : Member>(
}
private val data: BoxUnboxData by lazy(LazyThreadSafetyMode.PUBLICATION) {
val box = descriptor.returnType!!.toInlineClass()?.getBoxMethod(descriptor)
if (descriptor.isGetterOfUnderlyingPropertyOfInlineClass()) {
// Getter of the underlying val of an inline class is always called on a boxed receiver,
// no argument boxing/unboxing is required.
// However, its result might require boxing if it is an inline class type.
return@lazy BoxUnboxData(IntRange.EMPTY, emptyArray(), box)
}
val shift = when {
caller is CallerImpl.Method.BoundStatic -> {
// Bound reference to a static method is only possible for a top level extension function/property,
@@ -107,8 +115,6 @@ internal class InlineClassAwareCaller<out M : Member>(
} else null
}
val box = descriptor.returnType!!.toInlineClass()?.getBoxMethod()
BoxUnboxData(argumentRange, unbox, box)
}
@@ -130,20 +136,15 @@ internal class InlineClassAwareCaller<out M : Member>(
return box?.invoke(null, result) ?: result
}
private fun Class<*>.getBoxMethod(): Method = try {
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)")
}
}
internal fun <M : Member> CallerImpl<M>.createInlineClassAwareCallerIfNeeded(
internal fun <M : Member?> Caller<M>.createInlineClassAwareCallerIfNeeded(
descriptor: CallableMemberDescriptor,
isDefault: Boolean = false
): Caller<M> {
val needsInlineAwareCaller =
descriptor.valueParameters.any { it.type.isInlineClassType() } ||
val needsInlineAwareCaller: Boolean =
descriptor.isGetterOfUnderlyingPropertyOfInlineClass() ||
descriptor.valueParameters.any { it.type.isInlineClassType() } ||
descriptor.returnType?.isInlineClassType() == true ||
this !is BoundCaller && descriptor.hasInlineClassReceiver()
@@ -153,22 +154,28 @@ internal fun <M : Member> CallerImpl<M>.createInlineClassAwareCallerIfNeeded(
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) {
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})"
)
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)")
}
return null
}
internal fun Class<*>.getBoxMethod(descriptor: CallableMemberDescriptor): Method =
try {
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)")
}
internal fun KotlinType.toInlineClass(): Class<*>? =
constructor.declarationDescriptor.toInlineClass()
internal fun DeclarationDescriptor?.toInlineClass(): Class<*>? =
if (this is ClassDescriptor && isInline)
toJavaClass() ?: throw KotlinReflectionInternalError("Class object for the class $name cannot be found (classId=$classId)")
else
null
private val CallableMemberDescriptor.expectedReceiverType: KotlinType?
get() {
@@ -183,6 +190,8 @@ private val CallableMemberDescriptor.expectedReceiverType: KotlinType?
}
internal fun Any?.coerceToExpectedReceiverType(descriptor: CallableMemberDescriptor): Any? {
if (descriptor is PropertyDescriptor && descriptor.isUnderlyingPropertyOfInlineClass()) return this
val expectedReceiverType = descriptor.expectedReceiverType
val unboxMethod = expectedReceiverType?.toInlineClass()?.getUnboxMethod(descriptor) ?: return this
@@ -0,0 +1,44 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package kotlin.reflect.jvm.internal.calls
import java.lang.reflect.Type
import kotlin.reflect.jvm.internal.calls.CallerImpl.Companion.dropFirst
import java.lang.reflect.Method as ReflectMethod
internal sealed class InternalUnderlyingValOfInlineClass(
private val unboxMethod: ReflectMethod,
final override val parameterTypes: List<Type>
) : Caller<ReflectMethod?> {
final override val member: ReflectMethod? get() = null
final override val returnType: Type =
unboxMethod.returnType
protected fun callMethod(instance: Any?, args: Array<*>): Any? {
return unboxMethod.invoke(instance, *args)
}
class Unbound(
unboxMethod: ReflectMethod
) : InternalUnderlyingValOfInlineClass(unboxMethod, listOf(unboxMethod.declaringClass)) {
override fun call(args: Array<*>): Any? {
checkArguments(args)
return callMethod(args[0], args.dropFirst())
}
}
class Bound(
unboxMethod: ReflectMethod,
private val boundReceiver: Any?
) : InternalUnderlyingValOfInlineClass(unboxMethod, emptyList()), BoundCaller {
override fun call(args: Array<*>): Any? {
checkArguments(args)
return callMethod(boundReceiver, args)
}
}
}
@@ -16843,6 +16843,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/inlineClassConstructor.kt");
}
@TestMetadata("internalPrimaryValOfInlineClass.kt")
public void testInternalPrimaryValOfInlineClass() throws Exception {
runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/internalPrimaryValOfInlineClass.kt");
}
@TestMetadata("jvmStaticFieldInObject.kt")
public void testJvmStaticFieldInObject() throws Exception {
runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/jvmStaticFieldInObject.kt");
@@ -16873,6 +16878,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/overridingVarOfInlineClass.kt");
}
@TestMetadata("primaryValOfInlineClass.kt")
public void testPrimaryValOfInlineClass() throws Exception {
runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/primaryValOfInlineClass.kt");
}
@TestMetadata("properties.kt")
public void testProperties() throws Exception {
runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/properties.kt");
@@ -17888,6 +17888,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/inlineClassConstructor.kt");
}
@TestMetadata("internalPrimaryValOfInlineClass.kt")
public void testInternalPrimaryValOfInlineClass() throws Exception {
runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/internalPrimaryValOfInlineClass.kt");
}
@TestMetadata("jvmStaticFieldInObject.kt")
public void testJvmStaticFieldInObject() throws Exception {
runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/jvmStaticFieldInObject.kt");
@@ -17918,6 +17923,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/overridingVarOfInlineClass.kt");
}
@TestMetadata("primaryValOfInlineClass.kt")
public void testPrimaryValOfInlineClass() throws Exception {
runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/primaryValOfInlineClass.kt");
}
@TestMetadata("properties.kt")
public void testProperties() throws Exception {
runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/properties.kt");