From 94e1701089d63cf90c3682c64d8af69fe84fab68 Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Tue, 16 Oct 2018 17:39:30 +0300 Subject: [PATCH] Support 'call' for references to inline class members This includes overriding and non-overriding functions and properties. #KT-26748 --- .../kotlin/codegen/ClosureCodegen.java | 4 +- .../codegen/PropertyReferenceCodegen.kt | 11 +-- .../nonOverridingFunOfInlineClass.kt | 35 ++++++++ .../nonOverridingVarOfInlineClass.kt | 81 ++++++++++++++++++ .../overridingFunOfInlineClass.kt | 39 +++++++++ .../overridingVarOfInlineClass.kt | 85 +++++++++++++++++++ .../reflection/callBy/inlineClassMembers.kt | 75 ++++++++++++++++ .../codegen/BlackBoxCodegenTestGenerated.java | 25 ++++++ .../LightAnalysisModeTestGenerated.java | 25 ++++++ .../ir/IrBlackBoxCodegenTestGenerated.java | 25 ++++++ .../internal/calls/InlineClassAwareCaller.kt | 45 +++++++--- .../IrJsCodegenBoxTestGenerated.java | 25 ++++++ .../semantics/JsCodegenBoxTestGenerated.java | 25 ++++++ 13 files changed, 483 insertions(+), 17 deletions(-) create mode 100644 compiler/testData/codegen/box/reflection/call/inlineClasses/nonOverridingFunOfInlineClass.kt create mode 100644 compiler/testData/codegen/box/reflection/call/inlineClasses/nonOverridingVarOfInlineClass.kt create mode 100644 compiler/testData/codegen/box/reflection/call/inlineClasses/overridingFunOfInlineClass.kt create mode 100644 compiler/testData/codegen/box/reflection/call/inlineClasses/overridingVarOfInlineClass.kt create mode 100644 compiler/testData/codegen/box/reflection/callBy/inlineClassMembers.kt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ClosureCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ClosureCodegen.java index f6a02b0f66c..4aff78a2599 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ClosureCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ClosureCodegen.java @@ -391,8 +391,8 @@ public class ClosureCodegen extends MemberCodegen { DeclarationDescriptor container = descriptor.getContainingDeclaration(); if (container instanceof ClassDescriptor) { - // TODO: getDefaultType() here is wrong and won't work for arrays - putJavaLangClassInstance(iv, state.getTypeMapper().mapType(((ClassDescriptor) container).getDefaultType())); + // TODO: would it work for arrays? + putJavaLangClassInstance(iv, state.getTypeMapper().mapClass((ClassDescriptor) container)); } else if (container instanceof PackageFragmentDescriptor) { iv.aconst(state.getTypeMapper().mapOwner(descriptor)); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyReferenceCodegen.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyReferenceCodegen.kt index 1783148b999..f51e6c6df5b 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyReferenceCodegen.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyReferenceCodegen.kt @@ -28,12 +28,9 @@ import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.psi.KtElement -import org.jetbrains.kotlin.resolve.DescriptorFactory -import org.jetbrains.kotlin.resolve.DescriptorUtils -import org.jetbrains.kotlin.resolve.PropertyImportedFromObject +import org.jetbrains.kotlin.resolve.* import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny -import org.jetbrains.kotlin.resolve.isUnderlyingPropertyOfInlineClass import org.jetbrains.kotlin.resolve.jvm.AsmTypes.* import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature @@ -252,7 +249,11 @@ class PropertyReferenceCodegen( else -> error("Unsupported callable reference: $callable") } val declaration = DescriptorUtils.unwrapFakeOverride(accessor).original - val method = state.typeMapper.mapAsmMethod(declaration) + val method = + if (callable.containingDeclaration.isInlineClass()) + state.typeMapper.mapSignatureForInlineErasedClassSkipGeneric(declaration).asmMethod + else + state.typeMapper.mapAsmMethod(declaration) return method.name + method.descriptor } diff --git a/compiler/testData/codegen/box/reflection/call/inlineClasses/nonOverridingFunOfInlineClass.kt b/compiler/testData/codegen/box/reflection/call/inlineClasses/nonOverridingFunOfInlineClass.kt new file mode 100644 index 00000000000..2b6b2eb93f9 --- /dev/null +++ b/compiler/testData/codegen/box/reflection/call/inlineClasses/nonOverridingFunOfInlineClass.kt @@ -0,0 +1,35 @@ +// IGNORE_BACKEND: JS_IR, JS, NATIVE, JVM_IR +// WITH_REFLECT +import kotlin.test.assertEquals + +inline class Z(val x: Int) { + fun test(a: String, b: S) = "$x$a${b.x}" +} + +inline class L(val x: Long) { + fun test(a: String, b: S) = "$x$a${b.x}" +} + +inline class S(val x: String) { + fun test(a: String, b: S) = "$x$a${b.x}" +} + +inline class A(val x: Any) { + fun test(a: String, b: S) = "$x$a${b.x}" +} + +fun box(): String { + assertEquals("42-+", Z::test.call(Z(42), "-", S("+"))) + assertEquals("42-+", Z(42)::test.call("-", S("+"))) + + assertEquals("42-+", L::test.call(L(42L), "-", S("+"))) + assertEquals("42-+", L(42L)::test.call("-", S("+"))) + + assertEquals("42-+", S::test.call(S("42"), "-", S("+"))) + assertEquals("42-+", S("42")::test.call("-", S("+"))) + + assertEquals("42-+", A::test.call(A("42"), "-", S("+"))) + assertEquals("42-+", A("42")::test.call("-", S("+"))) + + return "OK" +} diff --git a/compiler/testData/codegen/box/reflection/call/inlineClasses/nonOverridingVarOfInlineClass.kt b/compiler/testData/codegen/box/reflection/call/inlineClasses/nonOverridingVarOfInlineClass.kt new file mode 100644 index 00000000000..ba7fa1208a6 --- /dev/null +++ b/compiler/testData/codegen/box/reflection/call/inlineClasses/nonOverridingVarOfInlineClass.kt @@ -0,0 +1,81 @@ +// IGNORE_BACKEND: JS_IR, JS, NATIVE, JVM_IR +// WITH_REFLECT +import kotlin.test.assertEquals + +var global = S("") + +inline class Z(val x: Int) { + var test: S + get() = S("${global.x}$x") + set(value) { + global = S("${value.x}$x") + } +} + +inline class L(val x: Long) { + var test: S + get() = S("${global.x}$x") + set(value) { + global = S("${value.x}$x") + } +} + +inline class S(val x: String) { + var test: S + get() = S("${global.x}$x") + set(value) { + global = S("${value.x}$x") + } +} + +inline class A(val x: Any) { + var test: S + get() = S("${global.x}$x") + set(value) { + global = S("${value.x}$x") + } +} + +fun box(): String { + global = S("") + assertEquals(S("42"), Z::test.call(Z(42))) + assertEquals(S("42"), Z(42)::test.call()) + assertEquals(S("42"), Z::test.getter.call(Z(42))) + assertEquals(S("42"), Z(42)::test.getter.call()) + Z::test.setter.call(Z(42), S("Z-")) + assertEquals(S("Z-42"), global) + Z(42)::test.setter.call(S("Z+")) + assertEquals(S("Z+42"), global) + + global = S("") + assertEquals(S("42"), L::test.call(L(42L))) + assertEquals(S("42"), L(42L)::test.call()) + assertEquals(S("42"), L::test.getter.call(L(42L))) + assertEquals(S("42"), L(42L)::test.getter.call()) + L::test.setter.call(L(42L), S("L-")) + assertEquals(S("L-42"), global) + L(42L)::test.setter.call(S("L+")) + assertEquals(S("L+42"), global) + + global = S("") + assertEquals(S("42"), S::test.call(S("42"))) + assertEquals(S("42"), S("42")::test.call()) + assertEquals(S("42"), S::test.getter.call(S("42"))) + assertEquals(S("42"), S("42")::test.getter.call()) + S::test.setter.call(S("42"), S("S-")) + assertEquals(S("S-42"), global) + S("42")::test.setter.call(S("S+")) + assertEquals(S("S+42"), global) + + global = S("") + assertEquals(S("42"), A::test.call(A(42))) + assertEquals(S("42"), A(42)::test.call()) + assertEquals(S("42"), A::test.getter.call(A(42))) + assertEquals(S("42"), A(42)::test.getter.call()) + A::test.setter.call(A(42), S("A-")) + assertEquals(S("A-42"), global) + A(42)::test.setter.call(S("A+")) + assertEquals(S("A+42"), global) + + return "OK" +} diff --git a/compiler/testData/codegen/box/reflection/call/inlineClasses/overridingFunOfInlineClass.kt b/compiler/testData/codegen/box/reflection/call/inlineClasses/overridingFunOfInlineClass.kt new file mode 100644 index 00000000000..79e892c9be5 --- /dev/null +++ b/compiler/testData/codegen/box/reflection/call/inlineClasses/overridingFunOfInlineClass.kt @@ -0,0 +1,39 @@ +// IGNORE_BACKEND: JS_IR, JS, NATIVE, JVM_IR +// WITH_REFLECT +import kotlin.test.assertEquals + +interface ITest { + fun test(a: String, b: S): String +} + +inline class Z(val x: Int) : ITest { + override fun test(a: String, b: S) = "$x$a${b.x}" +} + +inline class L(val x: Long) : ITest { + override fun test(a: String, b: S) = "$x$a${b.x}" +} + +inline class S(val x: String) : ITest { + override fun test(a: String, b: S) = "$x$a${b.x}" +} + +inline class A(val x: Any) : ITest { + override fun test(a: String, b: S) = "$x$a${b.x}" +} + +fun box(): String { + assertEquals("42-+", Z::test.call(Z(42), "-", S("+"))) + assertEquals("42-+", Z(42)::test.call("-", S("+"))) + + assertEquals("42-+", L::test.call(L(42L), "-", S("+"))) + assertEquals("42-+", L(42L)::test.call("-", S("+"))) + + assertEquals("42-+", S::test.call(S("42"), "-", S("+"))) + assertEquals("42-+", S("42")::test.call("-", S("+"))) + + assertEquals("42-+", A::test.call(A("42"), "-", S("+"))) + assertEquals("42-+", A("42")::test.call("-", S("+"))) + + return "OK" +} diff --git a/compiler/testData/codegen/box/reflection/call/inlineClasses/overridingVarOfInlineClass.kt b/compiler/testData/codegen/box/reflection/call/inlineClasses/overridingVarOfInlineClass.kt new file mode 100644 index 00000000000..db5148152b2 --- /dev/null +++ b/compiler/testData/codegen/box/reflection/call/inlineClasses/overridingVarOfInlineClass.kt @@ -0,0 +1,85 @@ +// IGNORE_BACKEND: JS_IR, JS, NATIVE, JVM_IR +// WITH_REFLECT +import kotlin.test.assertEquals + +var global = S("") + +interface ITest { + var test: S +} + +inline class Z(val x: Int) : ITest { + override var test: S + get() = S("${global.x}$x") + set(value) { + global = S("${value.x}$x") + } +} + +inline class L(val x: Long) : ITest { + override var test: S + get() = S("${global.x}$x") + set(value) { + global = S("${value.x}$x") + } +} + +inline class S(val x: String) : ITest { + override var test: S + get() = S("${global.x}$x") + set(value) { + global = S("${value.x}$x") + } +} + +inline class A(val x: Any) : ITest { + override var test: S + get() = S("${global.x}$x") + set(value) { + global = S("${value.x}$x") + } +} + +fun box(): String { + global = S("") + assertEquals(S("42"), Z::test.call(Z(42))) + assertEquals(S("42"), Z(42)::test.call()) + assertEquals(S("42"), Z::test.getter.call(Z(42))) + assertEquals(S("42"), Z(42)::test.getter.call()) + Z::test.setter.call(Z(42), S("Z-")) + assertEquals(S("Z-42"), global) + Z(42)::test.setter.call(S("Z+")) + assertEquals(S("Z+42"), global) + + global = S("") + assertEquals(S("42"), L::test.call(L(42L))) + assertEquals(S("42"), L(42L)::test.call()) + assertEquals(S("42"), L::test.getter.call(L(42L))) + assertEquals(S("42"), L(42L)::test.getter.call()) + L::test.setter.call(L(42L), S("L-")) + assertEquals(S("L-42"), global) + L(42L)::test.setter.call(S("L+")) + assertEquals(S("L+42"), global) + + global = S("") + assertEquals(S("42"), S::test.call(S("42"))) + assertEquals(S("42"), S("42")::test.call()) + assertEquals(S("42"), S::test.getter.call(S("42"))) + assertEquals(S("42"), S("42")::test.getter.call()) + S::test.setter.call(S("42"), S("S-")) + assertEquals(S("S-42"), global) + S("42")::test.setter.call(S("S+")) + assertEquals(S("S+42"), global) + + global = S("") + assertEquals(S("42"), A::test.call(A(42))) + assertEquals(S("42"), A(42)::test.call()) + assertEquals(S("42"), A::test.getter.call(A(42))) + assertEquals(S("42"), A(42)::test.getter.call()) + A::test.setter.call(A(42), S("A-")) + assertEquals(S("A-42"), global) + A(42)::test.setter.call(S("A+")) + assertEquals(S("A+42"), global) + + return "OK" +} diff --git a/compiler/testData/codegen/box/reflection/callBy/inlineClassMembers.kt b/compiler/testData/codegen/box/reflection/callBy/inlineClassMembers.kt new file mode 100644 index 00000000000..fcc4f759866 --- /dev/null +++ b/compiler/testData/codegen/box/reflection/callBy/inlineClassMembers.kt @@ -0,0 +1,75 @@ +// IGNORE_BACKEND: JS_IR, JS, NATIVE, JVM_IR +// WITH_REFLECT +import kotlin.test.assertEquals + +interface IFoo { + fun fooFun(z: Z): Z + var fooVar: Z +} + +var global = Z(0) + + +inline class Z(val x: Int) : IFoo { + + override fun fooFun(z: Z): Z = Z(z.x + x) + + override var fooVar: Z + get() = Z(global.x + x) + set(value) { + global = Z(value.x + x) + } + + fun barFun(z: Z): Z = Z(z.x * 100 + x) + + var barVar: Z + get() = Z(global.x * 100 + x) + set(value) { + global = Z(value.x * 100 + x) + } +} + + +fun box(): String { + val fooFunR = Z::fooFun + assertEquals(Z(53), fooFunR.callBy(mapOf(fooFunR.parameters[0] to Z(42), fooFunR.parameters[1] to Z(11)))) + + val fooFunBR = Z(42)::fooFun + assertEquals(Z(142), fooFunBR.callBy(mapOf(fooFunBR.parameters[0] to Z(100)))) + + global = Z(0) + val fooVarR = Z::fooVar + assertEquals(Z(42), fooVarR.callBy(mapOf(fooVarR.parameters[0] to Z(42)))) + assertEquals(Z(42), fooVarR.getter.callBy(mapOf(fooVarR.getter.parameters[0] to Z(42)))) + fooVarR.setter.callBy(mapOf(fooVarR.setter.parameters[0] to Z(42), fooVarR.setter.parameters[1] to Z(1))) + assertEquals(Z(43), global) + + global = Z(100) + val fooVarBR = Z(42)::fooVar + assertEquals(Z(142), fooVarBR.callBy(mapOf())) + assertEquals(Z(142), fooVarBR.getter.callBy(mapOf())) + fooVarBR.setter.callBy(mapOf(fooVarBR.setter.parameters[0] to Z(1))) + assertEquals(Z(43), global) + + val barFunR = Z::barFun + assertEquals(Z(1142), barFunR.callBy(mapOf(barFunR.parameters[0] to Z(42), barFunR.parameters[1] to Z(11)))) + + val barFunBR = Z(42)::barFun + assertEquals(Z(2242), barFunBR.callBy(mapOf(barFunBR.parameters[0] to Z(22)))) + + global = Z(1) + val barVarR = Z::barVar + assertEquals(Z(142), barVarR.callBy(mapOf(barVarR.parameters[0] to Z(42)))) + assertEquals(Z(142), barVarR.getter.callBy(mapOf(barVarR.getter.parameters[0] to Z(42)))) + barVarR.setter.callBy(mapOf(barVarR.setter.parameters[0] to Z(42), barVarR.setter.parameters[1] to Z(3))) + assertEquals(Z(342), global) + + global = Z(2) + val barVarBR = Z(42)::barVar + assertEquals(Z(242), barVarBR.callBy(mapOf())) + assertEquals(Z(242), barVarBR.getter.callBy(mapOf())) + barVarBR.setter.callBy(mapOf(barVarBR.setter.parameters[0] to Z(4))) + assertEquals(Z(442), global) + + return "OK" +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 51d20175b90..ea00c7c7487 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -18545,6 +18545,26 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/jvmStaticFunction.kt"); } + @TestMetadata("nonOverridingFunOfInlineClass.kt") + public void testNonOverridingFunOfInlineClass() throws Exception { + runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/nonOverridingFunOfInlineClass.kt"); + } + + @TestMetadata("nonOverridingVarOfInlineClass.kt") + public void testNonOverridingVarOfInlineClass() throws Exception { + runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/nonOverridingVarOfInlineClass.kt"); + } + + @TestMetadata("overridingFunOfInlineClass.kt") + public void testOverridingFunOfInlineClass() throws Exception { + runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/overridingFunOfInlineClass.kt"); + } + + @TestMetadata("overridingVarOfInlineClass.kt") + public void testOverridingVarOfInlineClass() throws Exception { + runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/overridingVarOfInlineClass.kt"); + } + @TestMetadata("properties.kt") public void testProperties() throws Exception { runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/properties.kt"); @@ -18599,6 +18619,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/reflection/callBy/inlineClassFunctionsAndConstructors.kt"); } + @TestMetadata("inlineClassMembers.kt") + public void testInlineClassMembers() throws Exception { + runTest("compiler/testData/codegen/box/reflection/callBy/inlineClassMembers.kt"); + } + @TestMetadata("jvmStaticInCompanionObject.kt") public void testJvmStaticInCompanionObject() throws Exception { runTest("compiler/testData/codegen/box/reflection/callBy/jvmStaticInCompanionObject.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 2c38fb480c5..62138ce6307 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -18545,6 +18545,26 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/jvmStaticFunction.kt"); } + @TestMetadata("nonOverridingFunOfInlineClass.kt") + public void testNonOverridingFunOfInlineClass() throws Exception { + runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/nonOverridingFunOfInlineClass.kt"); + } + + @TestMetadata("nonOverridingVarOfInlineClass.kt") + public void testNonOverridingVarOfInlineClass() throws Exception { + runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/nonOverridingVarOfInlineClass.kt"); + } + + @TestMetadata("overridingFunOfInlineClass.kt") + public void testOverridingFunOfInlineClass() throws Exception { + runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/overridingFunOfInlineClass.kt"); + } + + @TestMetadata("overridingVarOfInlineClass.kt") + public void testOverridingVarOfInlineClass() throws Exception { + runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/overridingVarOfInlineClass.kt"); + } + @TestMetadata("properties.kt") public void testProperties() throws Exception { runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/properties.kt"); @@ -18599,6 +18619,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/reflection/callBy/inlineClassFunctionsAndConstructors.kt"); } + @TestMetadata("inlineClassMembers.kt") + public void testInlineClassMembers() throws Exception { + runTest("compiler/testData/codegen/box/reflection/callBy/inlineClassMembers.kt"); + } + @TestMetadata("jvmStaticInCompanionObject.kt") public void testJvmStaticInCompanionObject() throws Exception { runTest("compiler/testData/codegen/box/reflection/callBy/jvmStaticInCompanionObject.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index e6980bbcf49..bcfbdf2fe9e 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -18550,6 +18550,26 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/jvmStaticFunction.kt"); } + @TestMetadata("nonOverridingFunOfInlineClass.kt") + public void testNonOverridingFunOfInlineClass() throws Exception { + runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/nonOverridingFunOfInlineClass.kt"); + } + + @TestMetadata("nonOverridingVarOfInlineClass.kt") + public void testNonOverridingVarOfInlineClass() throws Exception { + runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/nonOverridingVarOfInlineClass.kt"); + } + + @TestMetadata("overridingFunOfInlineClass.kt") + public void testOverridingFunOfInlineClass() throws Exception { + runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/overridingFunOfInlineClass.kt"); + } + + @TestMetadata("overridingVarOfInlineClass.kt") + public void testOverridingVarOfInlineClass() throws Exception { + runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/overridingVarOfInlineClass.kt"); + } + @TestMetadata("properties.kt") public void testProperties() throws Exception { runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/properties.kt"); @@ -18604,6 +18624,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/reflection/callBy/inlineClassFunctionsAndConstructors.kt"); } + @TestMetadata("inlineClassMembers.kt") + public void testInlineClassMembers() throws Exception { + runTest("compiler/testData/codegen/box/reflection/callBy/inlineClassMembers.kt"); + } + @TestMetadata("jvmStaticInCompanionObject.kt") public void testJvmStaticInCompanionObject() throws Exception { runTest("compiler/testData/codegen/box/reflection/callBy/jvmStaticInCompanionObject.kt"); diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/calls/InlineClassAwareCaller.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/calls/InlineClassAwareCaller.kt index 3e1e33f4b1b..abf1142a0cc 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/calls/InlineClassAwareCaller.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/calls/InlineClassAwareCaller.kt @@ -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( // 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 = ArrayList().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 CallerImpl.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) } \ No newline at end of file diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrJsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrJsCodegenBoxTestGenerated.java index a997e60c037..ba8d220f200 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrJsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrJsCodegenBoxTestGenerated.java @@ -16650,6 +16650,26 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/jvmStaticFunction.kt"); } + @TestMetadata("nonOverridingFunOfInlineClass.kt") + public void testNonOverridingFunOfInlineClass() throws Exception { + runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/nonOverridingFunOfInlineClass.kt"); + } + + @TestMetadata("nonOverridingVarOfInlineClass.kt") + public void testNonOverridingVarOfInlineClass() throws Exception { + runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/nonOverridingVarOfInlineClass.kt"); + } + + @TestMetadata("overridingFunOfInlineClass.kt") + public void testOverridingFunOfInlineClass() throws Exception { + runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/overridingFunOfInlineClass.kt"); + } + + @TestMetadata("overridingVarOfInlineClass.kt") + public void testOverridingVarOfInlineClass() throws Exception { + runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/overridingVarOfInlineClass.kt"); + } + @TestMetadata("properties.kt") public void testProperties() throws Exception { runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/properties.kt"); @@ -16704,6 +16724,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { runTest("compiler/testData/codegen/box/reflection/callBy/inlineClassFunctionsAndConstructors.kt"); } + @TestMetadata("inlineClassMembers.kt") + public void testInlineClassMembers() throws Exception { + runTest("compiler/testData/codegen/box/reflection/callBy/inlineClassMembers.kt"); + } + @TestMetadata("jvmStaticInCompanionObject.kt") public void testJvmStaticInCompanionObject() throws Exception { runTest("compiler/testData/codegen/box/reflection/callBy/jvmStaticInCompanionObject.kt"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index f27cc0537f5..fd6a77fc7fd 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -17695,6 +17695,26 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/jvmStaticFunction.kt"); } + @TestMetadata("nonOverridingFunOfInlineClass.kt") + public void testNonOverridingFunOfInlineClass() throws Exception { + runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/nonOverridingFunOfInlineClass.kt"); + } + + @TestMetadata("nonOverridingVarOfInlineClass.kt") + public void testNonOverridingVarOfInlineClass() throws Exception { + runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/nonOverridingVarOfInlineClass.kt"); + } + + @TestMetadata("overridingFunOfInlineClass.kt") + public void testOverridingFunOfInlineClass() throws Exception { + runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/overridingFunOfInlineClass.kt"); + } + + @TestMetadata("overridingVarOfInlineClass.kt") + public void testOverridingVarOfInlineClass() throws Exception { + runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/overridingVarOfInlineClass.kt"); + } + @TestMetadata("properties.kt") public void testProperties() throws Exception { runTest("compiler/testData/codegen/box/reflection/call/inlineClasses/properties.kt"); @@ -17749,6 +17769,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { runTest("compiler/testData/codegen/box/reflection/callBy/inlineClassFunctionsAndConstructors.kt"); } + @TestMetadata("inlineClassMembers.kt") + public void testInlineClassMembers() throws Exception { + runTest("compiler/testData/codegen/box/reflection/callBy/inlineClassMembers.kt"); + } + @TestMetadata("jvmStaticInCompanionObject.kt") public void testJvmStaticInCompanionObject() throws Exception { runTest("compiler/testData/codegen/box/reflection/callBy/jvmStaticInCompanionObject.kt");