[IR] Support reflection for MFVC
Signed-off-by: Evgeniy.Zhelenskiy <Evgeniy.Zhelenskiy@jetbrains.com>
#KT-1179
diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirLightTreeBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirLightTreeBlackBoxCodegenTestGenerated.java
index 2180694..978d241 100644
--- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirLightTreeBlackBoxCodegenTestGenerated.java
+++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirLightTreeBlackBoxCodegenTestGenerated.java
@@ -43521,6 +43521,100 @@
}
}
}
+
+ @Nested
+ @TestMetadata("compiler/testData/codegen/box/reflection/call/valueClasses")
+ @TestDataPath("$PROJECT_ROOT")
+ public class ValueClasses {
+ @Test
+ public void testAllFilesPresentInValueClasses() throws Exception {
+ KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/reflection/call/valueClasses"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
+ }
+
+ @Test
+ @TestMetadata("constructorWithMfvcParameters.kt")
+ public void testConstructorWithMfvcParameters() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/call/valueClasses/constructorWithMfvcParameters.kt");
+ }
+
+ @Test
+ @TestMetadata("fieldAccessors.kt")
+ public void testFieldAccessors() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/call/valueClasses/fieldAccessors.kt");
+ }
+
+ @Test
+ @TestMetadata("functionsWithMfvcParameters.kt")
+ public void testFunctionsWithMfvcParameters() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/call/valueClasses/functionsWithMfvcParameters.kt");
+ }
+
+ @Test
+ @TestMetadata("internalPrimaryValOfMfvc.kt")
+ public void testInternalPrimaryValOfMfvc() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/call/valueClasses/internalPrimaryValOfMfvc.kt");
+ }
+
+ @Test
+ @TestMetadata("jvmStaticFieldInObject.kt")
+ public void testJvmStaticFieldInObject() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/call/valueClasses/jvmStaticFieldInObject.kt");
+ }
+
+ @Test
+ @TestMetadata("jvmStaticFunction.kt")
+ public void testJvmStaticFunction() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/call/valueClasses/jvmStaticFunction.kt");
+ }
+
+ @Test
+ @TestMetadata("mfvcConstructor.kt")
+ public void testMfvcConstructor() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/call/valueClasses/mfvcConstructor.kt");
+ }
+
+ @Test
+ @TestMetadata("nonOverridingFunOfMfvc.kt")
+ public void testNonOverridingFunOfMfvc() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/call/valueClasses/nonOverridingFunOfMfvc.kt");
+ }
+
+ @Test
+ @TestMetadata("nonOverridingVarOfMfvc.kt")
+ public void testNonOverridingVarOfMfvc() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/call/valueClasses/nonOverridingVarOfMfvc.kt");
+ }
+
+ @Test
+ @TestMetadata("overridingFunOfMfvc.kt")
+ public void testOverridingFunOfMfvc() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/call/valueClasses/overridingFunOfMfvc.kt");
+ }
+
+ @Test
+ @TestMetadata("overridingVarOfMfvc.kt")
+ public void testOverridingVarOfMfvc() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/call/valueClasses/overridingVarOfMfvc.kt");
+ }
+
+ @Test
+ @TestMetadata("primaryValOfMfvc.kt")
+ public void testPrimaryValOfMfvc() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/call/valueClasses/primaryValOfMfvc.kt");
+ }
+
+ @Test
+ @TestMetadata("properties.kt")
+ public void testProperties() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/call/valueClasses/properties.kt");
+ }
+
+ @Test
+ @TestMetadata("suspendFunction.kt")
+ public void testSuspendFunction() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/call/valueClasses/suspendFunction.kt");
+ }
+ }
}
@Nested
@@ -43641,6 +43735,24 @@
}
@Test
+ @TestMetadata("mfvcDefaultArguments.kt")
+ public void testMfvcDefaultArguments() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/callBy/mfvcDefaultArguments.kt");
+ }
+
+ @Test
+ @TestMetadata("mfvcFunctionsAndConstructors.kt")
+ public void testMfvcFunctionsAndConstructors() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/callBy/mfvcFunctionsAndConstructors.kt");
+ }
+
+ @Test
+ @TestMetadata("mfvcMembers.kt")
+ public void testMfvcMembers() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/callBy/mfvcMembers.kt");
+ }
+
+ @Test
@TestMetadata("nonDefaultParameterOmitted.kt")
public void testNonDefaultParameterOmitted() throws Exception {
runTest("compiler/testData/codegen/box/reflection/callBy/nonDefaultParameterOmitted.kt");
@@ -44485,6 +44597,12 @@
}
@Test
+ @TestMetadata("reflectOnDefaultWithMfvcArgument.kt")
+ public void testReflectOnDefaultWithMfvcArgument() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/lambdaClasses/reflectOnDefaultWithMfvcArgument.kt");
+ }
+
+ @Test
@TestMetadata("reflectOnLambdaInArrayConstructor.kt")
public void testReflectOnLambdaInArrayConstructor() throws Exception {
runTest("compiler/testData/codegen/box/reflection/lambdaClasses/reflectOnLambdaInArrayConstructor.kt");
@@ -44555,6 +44673,12 @@
}
@Test
+ @TestMetadata("constructorWithMfvcParameters.kt")
+ public void testConstructorWithMfvcParameters() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/mapping/constructorWithMfvcParameters.kt");
+ }
+
+ @Test
@TestMetadata("extensionProperty.kt")
public void testExtensionProperty() throws Exception {
runTest("compiler/testData/codegen/box/reflection/mapping/extensionProperty.kt");
@@ -44816,6 +44940,18 @@
}
@Test
+ @TestMetadata("mfvcInSignature.kt")
+ public void testMfvcInSignature() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/mapping/types/mfvcInSignature.kt");
+ }
+
+ @Test
+ @TestMetadata("mfvcPrimaryVal.kt")
+ public void testMfvcPrimaryVal() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/mapping/types/mfvcPrimaryVal.kt");
+ }
+
+ @Test
@TestMetadata("overrideAnyWithPrimitive.kt")
public void testOverrideAnyWithPrimitive() throws Exception {
runTest("compiler/testData/codegen/box/reflection/mapping/types/overrideAnyWithPrimitive.kt");
@@ -44881,6 +45017,28 @@
runTest("compiler/testData/codegen/box/reflection/mapping/types/withNullability.kt");
}
}
+
+ @Nested
+ @TestMetadata("compiler/testData/codegen/box/reflection/mapping/valueClasses")
+ @TestDataPath("$PROJECT_ROOT")
+ public class ValueClasses {
+ @Test
+ public void testAllFilesPresentInValueClasses() throws Exception {
+ KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/reflection/mapping/valueClasses"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
+ }
+
+ @Test
+ @TestMetadata("mfvcPrimaryVal.kt")
+ public void testMfvcPrimaryVal() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/mapping/valueClasses/mfvcPrimaryVal.kt");
+ }
+
+ @Test
+ @TestMetadata("suspendFunctionWithMfvcInSignature.kt")
+ public void testSuspendFunctionWithMfvcInSignature() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/mapping/valueClasses/suspendFunctionWithMfvcInSignature.kt");
+ }
+ }
}
@Nested
@@ -45095,6 +45253,12 @@
}
@Test
+ @TestMetadata("mfvc.kt")
+ public void testMfvc() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/modifiers/mfvc.kt");
+ }
+
+ @Test
@TestMetadata("properties.kt")
public void testProperties() throws Exception {
runTest("compiler/testData/codegen/box/reflection/modifiers/properties.kt");
@@ -45905,6 +46069,12 @@
}
@Test
+ @TestMetadata("mfvc.kt")
+ public void testMfvc() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/typeOf/mfvc.kt");
+ }
+
+ @Test
@TestMetadata("multipleLayers.kt")
public void testMultipleLayers() throws Exception {
runTest("compiler/testData/codegen/box/reflection/typeOf/multipleLayers.kt");
@@ -46014,6 +46184,12 @@
}
@Test
+ @TestMetadata("mfvc.kt")
+ public void testMfvc() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/typeOf/noReflect/mfvc.kt");
+ }
+
+ @Test
@TestMetadata("mutableCollections_after.kt")
public void testMutableCollections_after() throws Exception {
runTest("compiler/testData/codegen/box/reflection/typeOf/noReflect/mutableCollections_after.kt");
diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirPsiBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirPsiBlackBoxCodegenTestGenerated.java
index 5ae50c5e..d1611ba 100644
--- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirPsiBlackBoxCodegenTestGenerated.java
+++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirPsiBlackBoxCodegenTestGenerated.java
@@ -43521,6 +43521,100 @@
}
}
}
+
+ @Nested
+ @TestMetadata("compiler/testData/codegen/box/reflection/call/valueClasses")
+ @TestDataPath("$PROJECT_ROOT")
+ public class ValueClasses {
+ @Test
+ public void testAllFilesPresentInValueClasses() throws Exception {
+ KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/reflection/call/valueClasses"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
+ }
+
+ @Test
+ @TestMetadata("constructorWithMfvcParameters.kt")
+ public void testConstructorWithMfvcParameters() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/call/valueClasses/constructorWithMfvcParameters.kt");
+ }
+
+ @Test
+ @TestMetadata("fieldAccessors.kt")
+ public void testFieldAccessors() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/call/valueClasses/fieldAccessors.kt");
+ }
+
+ @Test
+ @TestMetadata("functionsWithMfvcParameters.kt")
+ public void testFunctionsWithMfvcParameters() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/call/valueClasses/functionsWithMfvcParameters.kt");
+ }
+
+ @Test
+ @TestMetadata("internalPrimaryValOfMfvc.kt")
+ public void testInternalPrimaryValOfMfvc() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/call/valueClasses/internalPrimaryValOfMfvc.kt");
+ }
+
+ @Test
+ @TestMetadata("jvmStaticFieldInObject.kt")
+ public void testJvmStaticFieldInObject() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/call/valueClasses/jvmStaticFieldInObject.kt");
+ }
+
+ @Test
+ @TestMetadata("jvmStaticFunction.kt")
+ public void testJvmStaticFunction() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/call/valueClasses/jvmStaticFunction.kt");
+ }
+
+ @Test
+ @TestMetadata("mfvcConstructor.kt")
+ public void testMfvcConstructor() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/call/valueClasses/mfvcConstructor.kt");
+ }
+
+ @Test
+ @TestMetadata("nonOverridingFunOfMfvc.kt")
+ public void testNonOverridingFunOfMfvc() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/call/valueClasses/nonOverridingFunOfMfvc.kt");
+ }
+
+ @Test
+ @TestMetadata("nonOverridingVarOfMfvc.kt")
+ public void testNonOverridingVarOfMfvc() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/call/valueClasses/nonOverridingVarOfMfvc.kt");
+ }
+
+ @Test
+ @TestMetadata("overridingFunOfMfvc.kt")
+ public void testOverridingFunOfMfvc() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/call/valueClasses/overridingFunOfMfvc.kt");
+ }
+
+ @Test
+ @TestMetadata("overridingVarOfMfvc.kt")
+ public void testOverridingVarOfMfvc() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/call/valueClasses/overridingVarOfMfvc.kt");
+ }
+
+ @Test
+ @TestMetadata("primaryValOfMfvc.kt")
+ public void testPrimaryValOfMfvc() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/call/valueClasses/primaryValOfMfvc.kt");
+ }
+
+ @Test
+ @TestMetadata("properties.kt")
+ public void testProperties() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/call/valueClasses/properties.kt");
+ }
+
+ @Test
+ @TestMetadata("suspendFunction.kt")
+ public void testSuspendFunction() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/call/valueClasses/suspendFunction.kt");
+ }
+ }
}
@Nested
@@ -43641,6 +43735,24 @@
}
@Test
+ @TestMetadata("mfvcDefaultArguments.kt")
+ public void testMfvcDefaultArguments() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/callBy/mfvcDefaultArguments.kt");
+ }
+
+ @Test
+ @TestMetadata("mfvcFunctionsAndConstructors.kt")
+ public void testMfvcFunctionsAndConstructors() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/callBy/mfvcFunctionsAndConstructors.kt");
+ }
+
+ @Test
+ @TestMetadata("mfvcMembers.kt")
+ public void testMfvcMembers() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/callBy/mfvcMembers.kt");
+ }
+
+ @Test
@TestMetadata("nonDefaultParameterOmitted.kt")
public void testNonDefaultParameterOmitted() throws Exception {
runTest("compiler/testData/codegen/box/reflection/callBy/nonDefaultParameterOmitted.kt");
@@ -44485,6 +44597,12 @@
}
@Test
+ @TestMetadata("reflectOnDefaultWithMfvcArgument.kt")
+ public void testReflectOnDefaultWithMfvcArgument() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/lambdaClasses/reflectOnDefaultWithMfvcArgument.kt");
+ }
+
+ @Test
@TestMetadata("reflectOnLambdaInArrayConstructor.kt")
public void testReflectOnLambdaInArrayConstructor() throws Exception {
runTest("compiler/testData/codegen/box/reflection/lambdaClasses/reflectOnLambdaInArrayConstructor.kt");
@@ -44555,6 +44673,12 @@
}
@Test
+ @TestMetadata("constructorWithMfvcParameters.kt")
+ public void testConstructorWithMfvcParameters() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/mapping/constructorWithMfvcParameters.kt");
+ }
+
+ @Test
@TestMetadata("extensionProperty.kt")
public void testExtensionProperty() throws Exception {
runTest("compiler/testData/codegen/box/reflection/mapping/extensionProperty.kt");
@@ -44816,6 +44940,18 @@
}
@Test
+ @TestMetadata("mfvcInSignature.kt")
+ public void testMfvcInSignature() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/mapping/types/mfvcInSignature.kt");
+ }
+
+ @Test
+ @TestMetadata("mfvcPrimaryVal.kt")
+ public void testMfvcPrimaryVal() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/mapping/types/mfvcPrimaryVal.kt");
+ }
+
+ @Test
@TestMetadata("overrideAnyWithPrimitive.kt")
public void testOverrideAnyWithPrimitive() throws Exception {
runTest("compiler/testData/codegen/box/reflection/mapping/types/overrideAnyWithPrimitive.kt");
@@ -44881,6 +45017,28 @@
runTest("compiler/testData/codegen/box/reflection/mapping/types/withNullability.kt");
}
}
+
+ @Nested
+ @TestMetadata("compiler/testData/codegen/box/reflection/mapping/valueClasses")
+ @TestDataPath("$PROJECT_ROOT")
+ public class ValueClasses {
+ @Test
+ public void testAllFilesPresentInValueClasses() throws Exception {
+ KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/reflection/mapping/valueClasses"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
+ }
+
+ @Test
+ @TestMetadata("mfvcPrimaryVal.kt")
+ public void testMfvcPrimaryVal() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/mapping/valueClasses/mfvcPrimaryVal.kt");
+ }
+
+ @Test
+ @TestMetadata("suspendFunctionWithMfvcInSignature.kt")
+ public void testSuspendFunctionWithMfvcInSignature() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/mapping/valueClasses/suspendFunctionWithMfvcInSignature.kt");
+ }
+ }
}
@Nested
@@ -45095,6 +45253,12 @@
}
@Test
+ @TestMetadata("mfvc.kt")
+ public void testMfvc() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/modifiers/mfvc.kt");
+ }
+
+ @Test
@TestMetadata("properties.kt")
public void testProperties() throws Exception {
runTest("compiler/testData/codegen/box/reflection/modifiers/properties.kt");
@@ -45905,6 +46069,12 @@
}
@Test
+ @TestMetadata("mfvc.kt")
+ public void testMfvc() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/typeOf/mfvc.kt");
+ }
+
+ @Test
@TestMetadata("multipleLayers.kt")
public void testMultipleLayers() throws Exception {
runTest("compiler/testData/codegen/box/reflection/typeOf/multipleLayers.kt");
@@ -46014,6 +46184,12 @@
}
@Test
+ @TestMetadata("mfvc.kt")
+ public void testMfvc() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/typeOf/noReflect/mfvc.kt");
+ }
+
+ @Test
@TestMetadata("mutableCollections_after.kt")
public void testMutableCollections_after() throws Exception {
runTest("compiler/testData/codegen/box/reflection/typeOf/noReflect/mutableCollections_after.kt");
diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmMultiFieldValueClassLowering.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmMultiFieldValueClassLowering.kt
index 7b2d4ad..79c96ea 100644
--- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmMultiFieldValueClassLowering.kt
+++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmMultiFieldValueClassLowering.kt
@@ -105,15 +105,14 @@
return expressions.subList(0, expressions.size - repeatable.size) to repeatable
}
- private fun IrBuilderWithScope.castedToNotNull(expression: IrExpression) =
- if (expression.type.isNullable()) irImplicitCast(expression, expression.type.makeNotNull()) else expression
-
fun IrBlockBuilder.addReplacement(expression: IrSetValue, safe: Boolean): IrExpression? {
oldValueSymbol2NewValueSymbol[expression.symbol]?.let {
return irSet(it.owner, expression.value).also { irSet -> +irSet }
}
val instance = oldSymbol2MfvcNodeInstance[expression.symbol] ?: return null
- val values: List<IrExpression> = makeFlattenedExpressionsWithGivenSafety(instance.node, safe, castedToNotNull(expression.value))
+ val values: List<IrExpression> = makeFlattenedExpressionsWithGivenSafety(
+ instance.node, safe, castExpressionToNotNullTypeIfNeeded(expression.value, instance.type)
+ )
val setterExpressions = instance.makeSetterExpressions(this, values)
expression2MfvcNodeInstanceAccessor[setterExpressions] = MfvcNodeInstanceAccessor.Setter(instance, values)
+setterExpressions
@@ -166,7 +165,9 @@
accessType = AccessType.AlwaysPrivate,
saveVariable = ::variablesSaver
)
- val values: List<IrExpression> = makeFlattenedExpressionsWithGivenSafety(node, safe, castedToNotNull(expression.value))
+ val values: List<IrExpression> = makeFlattenedExpressionsWithGivenSafety(
+ node, safe, castExpressionToNotNullTypeIfNeeded(expression.value, node.type)
+ )
val setterExpressions = instance.makeSetterExpressions(this, values)
expression2MfvcNodeInstanceAccessor[setterExpressions] = MfvcNodeInstanceAccessor.Setter(instance, values)
+setterExpressions
@@ -318,6 +319,12 @@
if (replacingDeclaration in possibleExtraBoxUsageGenerated) removeAllExtraBoxes()
} as IrBlockBody
+ is IrField -> replacingDeclaration.initializer = replacingDeclaration.initializer?.makeBodyWithAddedVariables(
+ context, variablesToAdd[replacingDeclaration] ?: emptySet(), replacingDeclaration.symbol
+ )?.apply {
+ if (replacingDeclaration in possibleExtraBoxUsageGenerated) removeAllExtraBoxes()
+ } as IrExpressionBody?
+
else -> Unit
}
}
@@ -326,13 +333,15 @@
irClass.primaryConstructor?.let {
replacements.getReplacementForRegularClassConstructor(it)?.let { replacement -> addBindingsFor(it, replacement) }
}
- val propertiesOrFields = collectPropertiesOrFieldsAfterLowering(irClass)
- val oldBackingFields = propertiesOrFields.mapNotNull { propertyOrField ->
- val property = (propertyOrField as? IrPropertyOrIrField.Property)?.property ?: return@mapNotNull null
- property.backingField?.let { property to it }
- }.toMap()
- val propertiesOrFieldsReplacement =
- collectRegularClassMfvcPropertiesOrFieldsReplacement(propertiesOrFields) // resets backing fields
+ val propertiesOrFields = collectPropertiesOrFieldsAfterLowering(irClass, context)
+ val oldBackingFields = buildMap {
+ for (propertyOrField in propertiesOrFields) {
+ val property = (propertyOrField as? IrPropertyOrIrField.Property)?.property ?: continue
+ val field = property.backingField ?: continue
+ put(property, field)
+ }
+ }
+ val propertiesOrFieldsReplacement = collectRegularClassMfvcPropertiesOrFieldsReplacement(propertiesOrFields)
val fieldsToRemove = propertiesOrFieldsReplacement.keys.mapNotNull {
when (it) {
@@ -390,12 +399,15 @@
context.irFactory.createAnonymousInitializer(
startOffset = UNDEFINED_OFFSET,
endOffset = UNDEFINED_OFFSET, origin = IrDeclarationOrigin.GENERATED_MULTI_FIELD_VALUE_CLASS_MEMBER,
- symbol = IrAnonymousInitializerSymbolImpl()
+ symbol = IrAnonymousInitializerSymbolImpl(),
+ isStatic = element.isStatic,
).apply {
parent = irClass
body = context.createJvmIrBuilder(symbol).irBlockBody {
+irSetField(
- irClass.thisReceiver!!.takeUnless { element.isStatic }?.let { irGet(it) }, element, initializer.expression,
+ receiver = irClass.thisReceiver!!.takeUnless { element.isStatic }?.let { irGet(it) },
+ field = element,
+ value = initializer.expression.patchDeclarationParents(irClass),
origin = UNSAFE_MFVC_SET_ORIGIN
)
}
@@ -800,18 +812,18 @@
}
override fun visitFunctionReference(expression: IrFunctionReference): IrExpression {
- val originalFunction = expression.symbol.owner
- if (originalFunction.getReplacement() == null) return super.visitFunctionReference(expression)
- return makeNewLambda(originalFunction, expression, makeBody = { wrapper ->
- with(context.createJvmIrBuilder(wrapper.symbol)) {
- irExprBody(irCall(originalFunction).apply {
- passTypeArgumentsFrom(wrapper)
- for ((newParam, originalParam) in wrapper.explicitParameters zip originalFunction.explicitParameters) {
- putArgument(originalParam, irGet(newParam))
- }
- }).transform(this@JvmMultiFieldValueClassLowering, null)
+ val function = expression.symbol.owner
+ val replacement = function.getReplacement() ?: return super.visitFunctionReference(expression)
+ return context.createJvmIrBuilder(expression.symbol, expression).irBlock {
+ // Bridge call is added in BridgeLowering
+ buildReplacement(function, expression, replacement) {
+ IrFunctionReferenceImpl(
+ expression.startOffset, expression.endOffset,
+ expression.type, replacement.symbol, function.typeParameters.size, replacement.valueParameters.size,
+ expression.reflectionTarget, expression.origin
+ ).copyAttributes(expression)
}
- })
+ }.unwrapBlock()
}
private fun IrFunction.getReplacement(): IrFunction? =
@@ -995,7 +1007,7 @@
require(parameter2expression.size == structure.size)
require(structure.sumOf { it.valueParameters.size } == replacement.explicitParametersCount)
val newArguments: List<IrExpression?> =
- makeNewArguments(parameter2expression.map { (_, argument) -> argument }, structure.map { it.valueParameters })
+ makeNewArguments(parameter2expression.map { (_, argument) -> argument }, structure)
val resultExpression = makeMemberAccessExpression(replacement.symbol).apply {
passTypeArgumentsWithOffsets(replacement, originalFunction) { original.getTypeArgument(it)!! }
for ((parameter, argument) in replacement.explicitParameters zip newArguments) {
@@ -1023,21 +1035,15 @@
return super.visitStringConcatenation(expression)
}
- private fun IrBlockBuilder.makeNewArguments(
- oldArguments: List<IrExpression?>,
- structure: List<List<IrValueParameter>>
- ): List<IrExpression?> {
- val argumentSizes: List<Int> = structure.map { argTemplate -> argTemplate.size }
- val newArguments = (oldArguments zip argumentSizes).flatMap { (oldArgument, parametersCount) ->
+ private fun IrBlockBuilder.makeNewArguments(oldArguments: List<IrExpression?>, structure: List<RemappedParameter>): List<IrExpression?> {
+ val argumentSizes: List<Int> = structure.map { argTemplate -> argTemplate.valueParameters.size }
+ val newArguments = (oldArguments zip argumentSizes).flatMapIndexed { index, (oldArgument, parametersCount) ->
when {
oldArgument == null -> List(parametersCount) { null }
parametersCount == 1 -> listOf(oldArgument.transform(this@JvmMultiFieldValueClassLowering, null))
else -> {
- val castedIfNeeded = when {
- oldArgument.type.needsMfvcFlattening() -> oldArgument
- oldArgument.type.makeNotNull().needsMfvcFlattening() -> irImplicitCast(oldArgument, oldArgument.type.makeNotNull())
- else -> error("Unexpected type: ${oldArgument.type.render()}")
- }
+ val expectedType = (structure[index] as MultiFieldValueClassMapping).boxedType
+ val castedIfNeeded = castExpressionToNotNullTypeIfNeeded(oldArgument, expectedType)
flattenExpression(castedIfNeeded).also {
require(it.size == parametersCount) { "Expected $parametersCount arguments but got ${it.size}" }
}
@@ -1047,6 +1053,12 @@
return newArguments
}
+ private fun IrBuilderWithScope.castExpressionToNotNullTypeIfNeeded(expression: IrExpression, type: IrType) = when (type) {
+ expression.type -> expression
+ expression.type.makeNotNull() -> irImplicitCast(expression, type)
+ else -> irAs(expression, type)
+ }
+
/**
* Inlines initialization of variables when possible and returns their values
*
@@ -1212,7 +1224,7 @@
)
val type = if (expression is IrConstructorCall) expression.symbol.owner.constructedClass.defaultType else expression.type
val lowering = this@JvmMultiFieldValueClassLowering
- if (rootNode == null || !type.needsMfvcFlattening()) {
+ if (rootNode == null || !type.needsMfvcFlattening() || instance.size == 1) {
require(instance.size == 1) { "Required 1 variable/field to store regular value but got ${instance.size}" }
instance.addSetterStatements(this, listOf(expression.transform(lowering, null)))
return
@@ -1263,11 +1275,7 @@
}
}
val nullableTransformedExpression = expression.transform(this@JvmMultiFieldValueClassLowering, null)
- val transformedExpression =
- if (nullableTransformedExpression.type.isNullable())
- irImplicitCast(nullableTransformedExpression, nullableTransformedExpression.type.makeNotNull())
- else
- nullableTransformedExpression
+ val transformedExpression = castExpressionToNotNullTypeIfNeeded(nullableTransformedExpression, instance.type)
val addedSettersToFlattened = valueDeclarationsRemapper.handleFlattenedGetterExpressions(this, transformedExpression) {
require(it.size == instance.size) { "Incompatible assignment sizes: ${it.size}, ${instance.size}" }
instance.makeSetterExpressions(this, it)
diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/MfvcNodeFactory.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/MfvcNodeFactory.kt
index 2fec1b8..e4d814e 100644
--- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/MfvcNodeFactory.kt
+++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/MfvcNodeFactory.kt
@@ -32,7 +32,6 @@
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.defaultType
import org.jetbrains.kotlin.ir.util.*
-import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.util.OperatorNameConventions
@@ -61,7 +60,7 @@
this.name = fullFieldName
this.type = type
this.visibility = DescriptorVisibilities.PRIVATE
- this.metadata = null
+ oldBackingField.metadata = null
}.apply {
this.parent = oldBackingField.parent
this.annotations = fieldAnnotations.map { it.deepCopyWithVariables() }
@@ -246,19 +245,27 @@
)
}
-fun collectPropertiesAfterLowering(irClass: IrClass): LinkedHashSet<IrProperty> =
- LinkedHashSet(collectPropertiesOrFieldsAfterLowering(irClass).map { (it as Property).property })
+fun collectPropertiesAfterLowering(irClass: IrClass, context: JvmBackendContext): LinkedHashSet<IrProperty> =
+ LinkedHashSet(collectPropertiesOrFieldsAfterLowering(irClass, context).map { (it as Property).property })
sealed class IrPropertyOrIrField {
data class Property(val property: IrProperty) : IrPropertyOrIrField()
data class Field(val field: IrField) : IrPropertyOrIrField()
}
-fun collectPropertiesOrFieldsAfterLowering(irClass: IrClass): LinkedHashSet<IrPropertyOrIrField> =
+fun collectPropertiesOrFieldsAfterLowering(irClass: IrClass, context: JvmBackendContext): LinkedHashSet<IrPropertyOrIrField> =
LinkedHashSet<IrPropertyOrIrField>().apply {
for (element in irClass.declarations) {
if (element is IrField) {
- element.correspondingPropertySymbol?.owner?.takeUnless { it.isDelegated }?.let { add(Property(it)) } ?: add(Field(element))
+ val property = element.correspondingPropertySymbol?.owner
+ if (
+ property != null && !property.isDelegated &&
+ !context.multiFieldValueClassReplacements.getFieldsToRemove(element.parentAsClass).contains(element)
+ ) {
+ add(Property(property))
+ } else {
+ add(Field(element))
+ }
} else if (element is IrSimpleFunction && element.extensionReceiverParameter == null && element.contextReceiverParametersCount == 0) {
element.correspondingPropertySymbol?.owner?.let { add(Property(it)) }
}
@@ -275,7 +282,7 @@
val oldPrimaryConstructor = mfvc.primaryConstructor!!
val oldFields = mfvc.fields.filter { !it.isStatic }.toList()
val representation = mfvc.multiFieldValueClassRepresentation!!
- val properties = collectPropertiesAfterLowering(mfvc).associateBy { it.isStatic(mfvc) to it.name }
+ val properties = collectPropertiesAfterLowering(mfvc, context).associateBy { it.isStatic(mfvc) to it.name }
val subnodes = makeRootMfvcNodeSubnodes(representation, properties, context, mfvc)
@@ -394,6 +401,11 @@
}
}
annotations = oldPrimaryConstructor.annotations
+ if (oldPrimaryConstructor.metadata != null) {
+ metadata = oldPrimaryConstructor.metadata
+ oldPrimaryConstructor.metadata = null
+ }
+ copyAttributes(oldPrimaryConstructor as? IrAttributeContainer)
// body is added in the Lowering file as it needs to be lowered
}
@@ -448,20 +460,18 @@
Modality.FINAL,
oldBackingField,
).also {
- updateAnnotationsAndPropertyFromOldProperty(oldProperty)
+ updateAnnotationsAndPropertyFromOldProperty(oldProperty, context, it)
it.unboxMethod.overriddenSymbols = listOf() // the getter is saved so it overrides itself
}
}
private fun updateAnnotationsAndPropertyFromOldProperty(
- oldProperty: IrProperty
+ oldProperty: IrProperty,
+ context: JvmBackendContext,
+ node: MfvcNode,
) {
- oldProperty.setter?.apply {
- name = Name.identifier(JvmAbi.setterName(oldProperty.name.asString()))
- correspondingPropertySymbol = null
- origin = IrDeclarationOrigin.DEFINED
- }
- oldProperty.setter = null
+ if (node is LeafMfvcNode) return
+ oldProperty.backingField?.let { context.multiFieldValueClassReplacements.addFieldToRemove(it.parentAsClass, it) }
oldProperty.backingField = null
}
@@ -482,7 +492,7 @@
parent, context, type, makeTypeArgumentsFromType(type), MethodFullNameMode.Getter, listOf(oldProperty.name),
fieldAnnotations, static, overriddenNode, null, oldGetter, modality, oldField
).also {
- updateAnnotationsAndPropertyFromOldProperty(oldProperty)
+ updateAnnotationsAndPropertyFromOldProperty(oldProperty, context, it)
}
}
diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/ir/JvmIrUtils.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/ir/JvmIrUtils.kt
index a4a995f..3d2490d 100644
--- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/ir/JvmIrUtils.kt
+++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/ir/JvmIrUtils.kt
@@ -243,9 +243,11 @@
fun IrProperty.needsAccessor(accessor: IrSimpleFunction): Boolean = when {
// Properties in annotation classes become abstract methods named after the property.
(parent as? IrClass)?.kind == ClassKind.ANNOTATION_CLASS -> true
- // Multi-field value class getters must always be added. Getters for properties of MFVC itself follow general rules.
+ // Multi-field value class accessors must always be added.
accessor.isGetter && accessor.contextReceiverParametersCount == 0 && accessor.extensionReceiverParameter == null &&
- !accessor.parent.let { it is IrClass && it.isMultiFieldValueClass } && accessor.returnType.needsMfvcFlattening() -> true
+ accessor.returnType.needsMfvcFlattening() -> true
+ accessor.isSetter && accessor.contextReceiverParametersCount == 0 && accessor.extensionReceiverParameter == null &&
+ accessor.valueParameters.single().type.needsMfvcFlattening() -> true
// @JvmField properties have no getters/setters
resolveFakeOverride()?.backingField?.hasAnnotation(JvmAbi.JVM_FIELD_ANNOTATION_FQ_NAME) == true -> false
// We do not produce default accessors for private fields
diff --git a/compiler/testData/codegen/box/reflection/call/valueClasses/constructorWithMfvcParameters.kt b/compiler/testData/codegen/box/reflection/call/valueClasses/constructorWithMfvcParameters.kt
new file mode 100644
index 0000000..996e5b3
--- /dev/null
+++ b/compiler/testData/codegen/box/reflection/call/valueClasses/constructorWithMfvcParameters.kt
@@ -0,0 +1,51 @@
+// TARGET_BACKEND: JVM_IR
+// WITH_REFLECT
+// LANGUAGE: +ValueClasses
+
+import kotlin.test.assertEquals
+
+
+@JvmInline
+value class Z(val x1: UInt, val x2: Int)
+
+class Outer(val z1: Z, val z2: Z?) {
+ inner class Inner(val z3: Z, val z4: Z?) {
+ val test = "$z1 $z2 $z3 $z4"
+ }
+}
+
+@JvmInline
+value class ValueNonNullOuter(val z11: Z, val z12: Z) {
+ class Inner(val t: ValueNonNullOuter, val z2: Z, val z3: Z?) {
+ val test = "${t.z11} ${t.z12} $z2 $z3"
+ }
+}
+
+@JvmInline
+value class ValueNullableOuter(val z11: Z?, val z12: Z?) {
+ class Inner(val t: ValueNullableOuter, val z2: Z, val z3: Z?) {
+ val test = "${t.z11} ${t.z12} $z2 $z3"
+ }
+}
+
+fun box(): String {
+ val z1 = Z(1U, -1)
+ val z2 = Z(2U, -2)
+ val z3 = Z(3U, -3)
+ val z4 = Z(4U, -4)
+
+ val outer = ::Outer.call(z1, z2)
+ assertEquals(z1, outer.z1)
+ assertEquals(z2, outer.z2)
+
+ assertEquals("Z(x1=1, x2=-1) Z(x1=2, x2=-2) Z(x1=3, x2=-3) Z(x1=4, x2=-4)", Outer::Inner.call(outer, z3, z4).test)
+ assertEquals("Z(x1=1, x2=-1) Z(x1=2, x2=-2) Z(x1=2, x2=-2) Z(x1=4, x2=-4)", outer::Inner.call(z2, z4).test)
+
+ val valueNonNullOuter = ValueNonNullOuter(z1, z4)
+ assertEquals("Z(x1=1, x2=-1) Z(x1=4, x2=-4) Z(x1=2, x2=-2) Z(x1=3, x2=-3)", ValueNonNullOuter::Inner.call(valueNonNullOuter, z2, z3).test)
+
+ val valueNullableOuter = ValueNullableOuter(z1, z4)
+ assertEquals("Z(x1=1, x2=-1) Z(x1=4, x2=-4) Z(x1=2, x2=-2) Z(x1=3, x2=-3)", ValueNullableOuter::Inner.call(valueNullableOuter, z2, z3).test)
+
+ return "OK"
+}
diff --git a/compiler/testData/codegen/box/reflection/call/valueClasses/fieldAccessors.kt b/compiler/testData/codegen/box/reflection/call/valueClasses/fieldAccessors.kt
new file mode 100644
index 0000000..20b97fd
--- /dev/null
+++ b/compiler/testData/codegen/box/reflection/call/valueClasses/fieldAccessors.kt
@@ -0,0 +1,59 @@
+// TARGET_BACKEND: JVM_IR
+// WITH_REFLECT
+// LANGUAGE: +ValueClasses
+
+import kotlin.reflect.jvm.isAccessible
+import kotlin.test.assertEquals
+
+@JvmInline
+value class S(val value1: UInt, val value2: Int) {
+ operator fun plus(other: S): S = S(this.value1 + other.value1, this.value2 + other.value2)
+}
+
+class C {
+ private var nonNullMember: S = S(UInt.MAX_VALUE, -10)
+ private var nullableMember: S? = S(UInt.MAX_VALUE, -10)
+
+ fun nonNullUnboundRef() = C::nonNullMember.apply { isAccessible = true }
+ fun nonNullBoundRef() = this::nonNullMember.apply { isAccessible = true }
+ fun nullableUnboundRef() = C::nullableMember.apply { isAccessible = true }
+ fun nullableBoundRef() = this::nullableMember.apply { isAccessible = true }
+}
+
+private var nonNullTopLevel: S = S(UInt.MAX_VALUE, -10)
+private var nullableTopLevel: S? = S(UInt.MAX_VALUE, -10)
+
+fun box(): String {
+ val c = C()
+ val zero = S(0U, 5)
+ val one = S(1U, 10)
+ val two = S(2U, 20)
+
+ assertEquals(Unit, c.nonNullUnboundRef().setter.call(c, zero))
+ assertEquals(zero, c.nonNullUnboundRef().call(c))
+ assertEquals(zero, c.nonNullUnboundRef().getter.call(c))
+
+ assertEquals(Unit, c.nonNullBoundRef().setter.call(one))
+ assertEquals(one, c.nonNullBoundRef().call())
+ assertEquals(one, c.nonNullBoundRef().getter.call())
+
+ assertEquals(Unit, c.nullableUnboundRef().setter.call(c, zero))
+ assertEquals(zero, c.nullableUnboundRef().call(c))
+ assertEquals(zero, c.nullableUnboundRef().getter.call(c))
+
+ assertEquals(Unit, c.nullableBoundRef().setter.call(one))
+ assertEquals(one, c.nullableBoundRef().call())
+ assertEquals(one, c.nullableBoundRef().getter.call())
+
+ val nonNullTopLevel = ::nonNullTopLevel.apply { isAccessible = true }
+ assertEquals(Unit, nonNullTopLevel.setter.call(two))
+ assertEquals(two, nonNullTopLevel.call())
+ assertEquals(two, nonNullTopLevel.getter.call())
+
+ val nullableTopLevel = ::nullableTopLevel.apply { isAccessible = true }
+ assertEquals(Unit, nullableTopLevel.setter.call(two))
+ assertEquals(two, nullableTopLevel.call())
+ assertEquals(two, nullableTopLevel.getter.call())
+
+ return "OK"
+}
diff --git a/compiler/testData/codegen/box/reflection/call/valueClasses/functionsWithMfvcParameters.kt b/compiler/testData/codegen/box/reflection/call/valueClasses/functionsWithMfvcParameters.kt
new file mode 100644
index 0000000..e157ba2
--- /dev/null
+++ b/compiler/testData/codegen/box/reflection/call/valueClasses/functionsWithMfvcParameters.kt
@@ -0,0 +1,53 @@
+// TARGET_BACKEND: JVM_IR
+// WITH_REFLECT
+// LANGUAGE: +ValueClasses
+
+import kotlin.test.assertEquals
+
+@JvmInline
+value class S(val value1: UInt, val value2: Int) {
+ operator fun plus(other: S): S = S(this.value1 + other.value1, this.value2 + other.value2)
+}
+
+class C {
+ fun member(x: S, y1: UInt, y2: Int, z: S?): S = x + S(y1, y2) + z!!
+}
+
+fun topLevel(x1: UInt, x2: Int, y: S, z: S?): S = S(x1, x2) + y + z!!
+
+fun S.extension1(y: S, z: S?): S = this + y + z!!
+
+fun S?.extension2(y: S, z: S?) = this!! + y + z!!
+
+fun S.extension3_1(): UInt = value1
+fun S.extension3_2(): Int = value2
+
+fun S?.extension4_1(): UInt = this!!.value1
+fun S?.extension4_2(): Int = this!!.value2
+
+fun box(): String {
+ val zero = S(0U, 1000)
+ val one = S(1U, -1)
+ val two = S(2U, -2)
+ val four = S(4U, -4)
+ val seven = S(7U, -7)
+
+ assertEquals(seven, C::member.call(C(), one, 2U, -2, four))
+ assertEquals(seven, ::topLevel.call(1U, -1, two, four))
+ assertEquals(seven, S::extension1.call(one, two, four))
+ assertEquals(seven, S::extension2.call(one, two, four))
+ assertEquals(0U, S::extension3_1.call(zero))
+ assertEquals(1000, S::extension3_2.call(zero))
+ assertEquals(0U, S?::extension4_1.call(zero))
+ assertEquals(1000, S?::extension4_2.call(zero))
+
+ assertEquals(seven, C()::member.call(one, 2U, -2, four))
+ assertEquals(seven, one::extension1.call(two, four))
+ assertEquals(seven, one::extension2.call(two, four))
+ assertEquals(0U, zero::extension3_1.call())
+ assertEquals(1000, zero::extension3_2.call())
+ assertEquals(0U, zero::extension4_1.call())
+ assertEquals(1000, zero::extension4_2.call())
+
+ return "OK"
+}
diff --git a/compiler/testData/codegen/box/reflection/call/valueClasses/internalPrimaryValOfMfvc.kt b/compiler/testData/codegen/box/reflection/call/valueClasses/internalPrimaryValOfMfvc.kt
new file mode 100644
index 0000000..681b223
--- /dev/null
+++ b/compiler/testData/codegen/box/reflection/call/valueClasses/internalPrimaryValOfMfvc.kt
@@ -0,0 +1,74 @@
+// TARGET_BACKEND: JVM_IR
+// WITH_REFLECT
+// LANGUAGE: +ValueClasses
+
+import kotlin.test.assertEquals
+
+@JvmInline
+value class Z(internal val x1: UInt, internal val x2: Int)
+@JvmInline
+value class Z2(internal val x1: Z, internal val x2: Z)
+
+@JvmInline
+value class L(internal val x1: ULong, internal val x2: Long)
+@JvmInline
+value class L2(internal val x1: L, internal val x2: L)
+
+@JvmInline
+value class A1(internal val x1: Any?, internal val x2: Any?)
+@JvmInline
+value class A1_2(internal val x1: A1, internal val x2: A1)
+@JvmInline
+value class A2(internal val x1: Any, internal val x2: Any)
+@JvmInline
+value class A2_2(internal val x1: A2, internal val x2: A2)
+
+fun box(): String {
+ assertEquals(42U, Z::x1.call(Z(42U, 43)))
+ assertEquals(43, Z::x2.call(Z(42U, 43)))
+ assertEquals(42U, Z(42U, 43)::x1.call())
+ assertEquals(43, Z(42U, 43)::x2.call())
+
+ assertEquals(1234UL, L::x1.call(L(1234UL, 5678L)))
+ assertEquals(5678L, L::x2.call(L(1234UL, 5678L)))
+ assertEquals(1234UL, L(1234UL, 5678L)::x1.call())
+ assertEquals(5678L, L(1234UL, 5678L)::x2.call())
+
+ assertEquals("abc", A1::x1.call(A1("abc", "def")))
+ assertEquals("def", A1::x2.call(A1("abc", "def")))
+ assertEquals("abc", A1("abc", "def")::x1.call())
+ assertEquals("def", A1("abc", "def")::x2.call())
+ assertEquals(null, A1::x1.call(A1(null, null)))
+ assertEquals(null, A1::x2.call(A1(null, null)))
+ assertEquals(null, A1(null, null)::x1.call())
+ assertEquals(null, A1(null, null)::x2.call())
+ assertEquals("abc", A2::x1.call(A2("abc", "def")))
+ assertEquals("def", A2::x2.call(A2("abc", "def")))
+ assertEquals("abc", A2("abc", "def")::x1.call())
+ assertEquals("def", A2("abc", "def")::x2.call())
+
+ assertEquals(Z(42U, 43), Z2::x1.call(Z2(Z(42U, 43), Z(44U, 45))))
+ assertEquals(Z(44U, 45), Z2::x2.call(Z2(Z(42U, 43), Z(44U, 45))))
+ assertEquals(Z(42U, 43), Z2(Z(42U, 43), Z(44U, 45))::x1.call())
+ assertEquals(Z(44U, 45), Z2(Z(42U, 43), Z(44U, 45))::x2.call())
+
+ assertEquals(L(1234UL, 5678L), L2::x1.call(L2(L(1234UL, 5678L), L(12340UL, -5678L))))
+ assertEquals(L(12340UL, -5678L), L2::x2.call(L2(L(1234UL, 5678L), L(12340UL, -5678L))))
+ assertEquals(L(1234UL, 5678L), L2(L(1234UL, 5678L), L(12340UL, -5678L))::x1.call())
+ assertEquals(L(12340UL, -5678L), L2(L(1234UL, 5678L), L(12340UL, -5678L))::x2.call())
+
+ assertEquals(A1("abc", "def"), A1_2::x1.call(A1_2(A1("abc", "def"), A1("geh", "ijk"))))
+ assertEquals(A1("geh", "ijk"), A1_2::x2.call(A1_2(A1("abc", "def"), A1("geh", "ijk"))))
+ assertEquals(A1("abc", "def"), A1_2(A1("abc", "def"), A1("geh", "ijk"))::x1.call())
+ assertEquals(A1("geh", "ijk"), A1_2(A1("abc", "def"), A1("geh", "ijk"))::x2.call())
+ assertEquals(A1(null, null), A1_2::x1.call(A1_2(A1(null, null), A1(null, null))))
+ assertEquals(A1(null, null), A1_2::x2.call(A1_2(A1(null, null), A1(null, null))))
+ assertEquals(A1(null, null), A1_2(A1(null, null), A1(null, null))::x1.call())
+ assertEquals(A1(null, null), A1_2(A1(null, null), A1(null, null))::x2.call())
+ assertEquals(A2("abc", "def"), A2_2::x1.call(A2_2(A2("abc", "def"), A2("geh", "ijk"))))
+ assertEquals(A2("geh", "ijk"), A2_2::x2.call(A2_2(A2("abc", "def"), A2("geh", "ijk"))))
+ assertEquals(A2("abc", "def"), A2_2(A2("abc", "def"), A2("geh", "ijk"))::x1.call())
+ assertEquals(A2("geh", "ijk"), A2_2(A2("abc", "def"), A2("geh", "ijk"))::x2.call())
+
+ return "OK"
+}
diff --git a/compiler/testData/codegen/box/reflection/call/valueClasses/jvmStaticFieldInObject.kt b/compiler/testData/codegen/box/reflection/call/valueClasses/jvmStaticFieldInObject.kt
new file mode 100644
index 0000000..3784db6
--- /dev/null
+++ b/compiler/testData/codegen/box/reflection/call/valueClasses/jvmStaticFieldInObject.kt
@@ -0,0 +1,53 @@
+// TARGET_BACKEND: JVM_IR
+// JVM_TARGET: 1.8
+// WITH_REFLECT
+// LANGUAGE: +ValueClasses
+
+import kotlin.reflect.KMutableProperty1
+import kotlin.reflect.jvm.isAccessible
+import kotlin.test.assertEquals
+
+@JvmInline
+value class Z(val value1: UInt, val value2: Int) {
+ operator fun plus(other: Z): Z = Z(this.value1 + other.value1, this.value2 + other.value2)
+}
+
+object C {
+ @JvmStatic
+ private var p1: Z = Z(UInt.MAX_VALUE, -10)
+
+ @JvmStatic
+ private var p2: Z? = Z(UInt.MAX_VALUE, -10)
+
+ fun nonNullBoundRef() = this::p1.apply { isAccessible = true }
+ fun nullableBoundRef() = this::p2.apply { isAccessible = true }
+}
+
+fun box(): String {
+ val one = Z(1U, 10)
+ val two = Z(2U, 20)
+
+ val nonNullUnboundRef = C::class.members.single { it.name == "p1" } as KMutableProperty1<C, Z>
+ nonNullUnboundRef.isAccessible = true
+ assertEquals(Unit, nonNullUnboundRef.setter.call(C, one))
+ assertEquals(one, nonNullUnboundRef.call(C))
+ assertEquals(one, nonNullUnboundRef.getter.call(C))
+
+ val nullableUnboundRef = C::class.members.single { it.name == "p2" } as KMutableProperty1<C, Z?>
+ nullableUnboundRef.isAccessible = true
+ assertEquals(Unit, nullableUnboundRef.setter.call(C, one))
+ assertEquals(one, nullableUnboundRef.call(C))
+ assertEquals(one, nullableUnboundRef.getter.call(C))
+
+ val nonNullBoundRef = C.nonNullBoundRef()
+ assertEquals(Unit, nonNullBoundRef.setter.call(two))
+ assertEquals(two, nonNullBoundRef.call())
+ assertEquals(two, nonNullBoundRef.getter.call())
+
+ val nullableBoundRef = C.nullableBoundRef()
+ assertEquals(Unit, nullableBoundRef.setter.call(two))
+ assertEquals(two, nullableBoundRef.call())
+ assertEquals(two, nullableBoundRef.getter.call())
+
+ return "OK"
+}
diff --git a/compiler/testData/codegen/box/reflection/call/valueClasses/jvmStaticFunction.kt b/compiler/testData/codegen/box/reflection/call/valueClasses/jvmStaticFunction.kt
new file mode 100644
index 0000000..d6617fa
--- /dev/null
+++ b/compiler/testData/codegen/box/reflection/call/valueClasses/jvmStaticFunction.kt
@@ -0,0 +1,42 @@
+// TARGET_BACKEND: JVM_IR
+// JVM_TARGET: 1.8
+// WITH_REFLECT
+// LANGUAGE: +ValueClasses
+
+import kotlin.reflect.KFunction
+import kotlin.test.assertEquals
+
+@JvmInline
+value class Z(val value1: UInt, val value2: Int) {
+ operator fun plus(other: Z): Z = Z(this.value1 + other.value1, this.value2 + other.value2)
+}
+
+object C {
+ @JvmStatic
+ fun foo(x: Z, y1: UInt, y2: Int, z: Z?): Z = x + Z(y1, y2) + z!!
+}
+
+interface I {
+ companion object {
+ @JvmStatic
+ fun bar(x1: UInt, x2: Int, y: Z, z: Z?): Z = Z(x1, x2) + y + z!!
+ }
+}
+
+fun box(): String {
+ val one = Z(1U, -1)
+ val two = Z(2U, -2)
+ val four = Z(4U, -4)
+ val seven = Z(7U, -7)
+
+ assertEquals(seven, C::foo.call(one, 2U, -2, four))
+ assertEquals(seven, (I)::bar.call(1U, -1, two, four))
+
+ val unboundFoo = C::class.members.single { it.name == "foo" } as KFunction<*>
+ assertEquals(seven, unboundFoo.call(C, one, 2U, -2, four))
+
+ val unboundBar = I.Companion::class.members.single { it.name == "bar" } as KFunction<*>
+ assertEquals(seven, unboundBar.call(I, 1U, -1, two, four))
+
+ return "OK"
+}
diff --git a/compiler/testData/codegen/box/reflection/call/valueClasses/mfvcConstructor.kt b/compiler/testData/codegen/box/reflection/call/valueClasses/mfvcConstructor.kt
new file mode 100644
index 0000000..25a446d
--- /dev/null
+++ b/compiler/testData/codegen/box/reflection/call/valueClasses/mfvcConstructor.kt
@@ -0,0 +1,82 @@
+// TARGET_BACKEND: JVM_IR
+// WITH_REFLECT
+// LANGUAGE: +ValueClasses
+
+import kotlin.reflect.KCallable
+import kotlin.test.assertEquals
+
+@JvmInline
+value class Z(val x1: UInt, val x2: Int) {
+ constructor(a: UInt, b: UInt, c: Int, d: Int) : this(a + b, c + d)
+}
+
+@JvmInline
+value class L(val x1: ULong, val x2: Long) {
+ constructor(a: ULong, b: ULong, c: Long, d: Long) : this(a + b, c + d)
+}
+
+@JvmInline
+value class S1(val x1: String, val x2: String) {
+ constructor(a: String, b: String, c: String, d: String) : this(a + b, c + d)
+}
+
+@JvmInline
+value class S2(val x1: String?, val x2: String?) {
+ constructor(a: String?, b: String?, c: String?, d: String?) : this(a!! + b!!, c!! + d!!)
+}
+
+@JvmInline
+value class A(val x1: Any, val x2: Any) {
+ constructor(a: String, b: String, c: String, d: String) : this(a + b, c + d)
+}
+
+@JvmInline
+value class Z2(val z1: Z, val z2: Z) {
+ constructor(z1: Z, z2: Z, z3: Z, z4: Z) : this(Z(z1.x1 + z2.x1, z1.x2 + z2.x2), Z(z3.x1 + z4.x1, z3.x2 + z4.x2))
+}
+
+@JvmInline
+value class Z3(val z1: Z?, val z2: Z?) {
+ constructor(z1: Z?, z2: Z?, z3: Z?, z4: Z?) : this(Z(z1!!.x1 + z2!!.x1, z1!!.x2 + z2!!.x2), Z(z3!!.x1 + z4!!.x1, z3!!.x2 + z4!!.x2))
+}
+
+fun box(): String {
+ val ctorZ1_1: (UInt, Int) -> Z = ::Z
+ val ctorZ1_2: (UInt, UInt, Int, Int) -> Z = ::Z
+ val ctorL1: (ULong, Long) -> L = ::L
+ val ctorL2: (ULong, ULong, Long, Long) -> L = ::L
+ val ctorS1_1: (String, String) -> S1 = ::S1
+ val ctorS1_2: (String, String, String, String) -> S1 = ::S1
+ val ctorS2_1: (String, String) -> S2 = ::S2
+ val ctorS2_2: (String, String, String, String) -> S2 = ::S2
+ val ctorA1: (Any, Any) -> A = ::A
+ val ctorA2: (String, String, String, String) -> A = ::A
+ val ctorZ2_2: (Z, Z) -> Z2 = ::Z2
+ val ctorZ2_4: (Z, Z, Z, Z) -> Z2 = ::Z2
+ val ctorZ3_2: (Z, Z) -> Z3 = ::Z3
+ val ctorZ3_4: (Z, Z, Z, Z) -> Z3 = ::Z3
+
+ assertEquals(Z(42U, 43), (ctorZ1_1 as KCallable<Z>).call(42U, 43))
+ assertEquals(Z(123U, 224), (ctorZ1_2 as KCallable<Z>).call(100U, 23U, 200, 24))
+ assertEquals(L(1UL, 2L), (ctorL1 as KCallable<L>).call(1UL, 2L))
+ assertEquals(L(123UL, 224L), (ctorL2 as KCallable<L>).call(100UL, 23UL, 200L, 24L))
+ assertEquals(S1("abc", "def"), (ctorS1_1 as KCallable<S1>).call("abc", "def"))
+ assertEquals(S1("abc", "def"), (ctorS1_2 as KCallable<S1>).call("ab", "c", "de", "f"))
+ assertEquals(S2("abc", "def"), (ctorS2_1 as KCallable<S2>).call("abc", "def"))
+ assertEquals(S2("abc", "def"), (ctorS2_2 as KCallable<S2>).call("ab", "c", "de", "f"))
+ assertEquals(A("abc", "def"), (ctorA1 as KCallable<A>).call("abc", "def"))
+ assertEquals(A("abc", "def"), (ctorA2 as KCallable<A>).call("a", "bc", "d", "ef"))
+
+ assertEquals(Z2(Z(42U, 43), Z(44U, 45)), (ctorZ2_2 as KCallable<Z2>).call(Z(42U, 43), Z(44U, 45)))
+ assertEquals(Z3(Z(42U, 43), Z(44U, 45)), (ctorZ3_2 as KCallable<Z3>).call(Z(42U, 43), Z(44U, 45)))
+ assertEquals(
+ Z2(Z(142U, 243), Z(344U, 445)),
+ (ctorZ2_4 as KCallable<Z2>).call(Z(42U, 43), Z(100U, 200), Z(44U, 45), Z(300U, 400))
+ )
+ assertEquals(
+ Z3(Z(142U, 243), Z(344U, 445)),
+ (ctorZ3_4 as KCallable<Z3>).call(Z(42U, 43), Z(100U, 200), Z(44U, 45), Z(300U, 400))
+ )
+
+ return "OK"
+}
diff --git a/compiler/testData/codegen/box/reflection/call/valueClasses/nonOverridingFunOfMfvc.kt b/compiler/testData/codegen/box/reflection/call/valueClasses/nonOverridingFunOfMfvc.kt
new file mode 100644
index 0000000..0bc1b30
--- /dev/null
+++ b/compiler/testData/codegen/box/reflection/call/valueClasses/nonOverridingFunOfMfvc.kt
@@ -0,0 +1,37 @@
+// TARGET_BACKEND: JVM_IR
+// WITH_REFLECT
+// LANGUAGE: +ValueClasses
+
+import kotlin.test.assertEquals
+
+@JvmInline
+value class Z(val x1: UInt, val x2: Int) {
+ fun test(a: Int, b: Z, c: Z?) = "$x1$x2$a${b.x1}${b.x2}${c!!.x1}${c!!.x2}"
+}
+
+@JvmInline
+value class S(val x1: String, val x2: String) {
+ fun test(a: Int, b: Z, c: Z?) = "$x1$x2$a${b.x1}${b.x2}${c!!.x1}${c!!.x2}"
+}
+
+@JvmInline
+value class A(val x1: Any, val x2: Any) {
+ fun test(a: Int, b: Z, c: Z?) = "$x1$x2$a${b.x1}${b.x2}${c!!.x1}${c!!.x2}"
+}
+
+fun box(): String {
+ val two = Z(2U, 3)
+ val four = Z(4U, 5)
+
+ val expected = "0912345"
+ assertEquals(expected, Z::test.call(Z(0U, 9), 1, two, four))
+ assertEquals(expected, Z(0U, 9)::test.call(1, two, four))
+
+ assertEquals(expected, S::test.call(S("0", "9"), 1, two, four))
+ assertEquals(expected, S("0", "9")::test.call(1, two, four))
+
+ assertEquals(expected, A::test.call(A(0U, 9), 1, two, four))
+ assertEquals(expected, A(0U, 9)::test.call(1, two, four))
+
+ return "OK"
+}
diff --git a/compiler/testData/codegen/box/reflection/call/valueClasses/nonOverridingVarOfMfvc.kt b/compiler/testData/codegen/box/reflection/call/valueClasses/nonOverridingVarOfMfvc.kt
new file mode 100644
index 0000000..dd8b4f5
--- /dev/null
+++ b/compiler/testData/codegen/box/reflection/call/valueClasses/nonOverridingVarOfMfvc.kt
@@ -0,0 +1,127 @@
+// TARGET_BACKEND: JVM_IR
+// WITH_REFLECT
+// LANGUAGE: +ValueClasses
+
+import kotlin.test.assertEquals
+
+var global = Z(0U, 0)
+
+@JvmInline
+value class Z(val x1: UInt, val x2: Int) {
+ var nonNullTest: Z
+ get() = Z(global.x1 + this.x1, global.x2 + this.x2)
+ set(value) {
+ global = Z(this.x1 + value.x1, this.x2 + value.x2)
+ }
+
+ var nullableTest: Z?
+ get() = Z(global.x1 + this.x1, global.x2 + this.x2)
+ set(value) {
+ global = Z(this.x1 + value!!.x1, this.x2 + value!!.x2)
+ }
+}
+
+@JvmInline
+value class S(val x1: String, val x2: String) {
+ var nonNullTest: Z
+ get() = Z(global.x1 + x1.toUInt(), global.x2 + x2.toInt())
+ set(value) {
+ global = Z(this.x1.toUInt() + value.x1, this.x2.toInt() + value.x2)
+ }
+
+ var nullableTest: Z?
+ get() = Z(global.x1 + x1.toUInt(), global.x2 + x2.toInt())
+ set(value) {
+ global = Z(this.x1.toUInt() + value!!.x1, this.x2.toInt() + value!!.x2)
+ }
+}
+
+@JvmInline
+value class A(val x1: Any, val x2: Any) {
+ var nonNullTest: Z
+ get() = Z(global.x1 + this.x1 as UInt, global.x2 + this.x2 as Int)
+ set(value) {
+ global = Z(this.x1 as UInt + value.x1, this.x2 as Int + value.x2)
+ }
+
+ var nullableTest: Z?
+ get() = Z(global.x1 + this.x1 as UInt, global.x2 + this.x2 as Int)
+ set(value) {
+ global = Z(this.x1 as UInt + value!!.x1, this.x2 as Int + value!!.x2)
+ }
+
+}
+
+fun box(): String {
+ val zZero = Z(0U, 0)
+ val zOne = Z(1U, -1)
+ val zTwo = Z(2U, -2)
+ val zThree = Z(3U, -3)
+ val zFour = Z(4U, -4)
+
+ val sOne = S("1", "-1")
+
+ val aOne = A(1U, -1)
+
+ global = zZero
+ assertEquals(zOne, Z::nonNullTest.call(zOne))
+ assertEquals(zOne, zOne::nonNullTest.call())
+ assertEquals(zOne, Z::nonNullTest.getter.call(zOne))
+ assertEquals(zOne, zOne::nonNullTest.getter.call())
+ Z::nonNullTest.setter.call(zOne, zTwo)
+ assertEquals(zThree, global)
+ zOne::nonNullTest.setter.call(zThree)
+ assertEquals(zFour, global)
+
+ global = zZero
+ assertEquals(zOne, Z::nullableTest.call(zOne))
+ assertEquals(zOne, zOne::nullableTest.call())
+ assertEquals(zOne, Z::nullableTest.getter.call(zOne))
+ assertEquals(zOne, zOne::nullableTest.getter.call())
+ Z::nullableTest.setter.call(zOne, zTwo)
+ assertEquals(zThree, global)
+ zOne::nullableTest.setter.call(zThree)
+ assertEquals(zFour, global)
+
+ global = zZero
+ assertEquals(zOne, S::nonNullTest.call(sOne))
+ assertEquals(zOne, sOne::nonNullTest.call())
+ assertEquals(zOne, S::nonNullTest.getter.call(sOne))
+ assertEquals(zOne, sOne::nonNullTest.getter.call())
+ S::nonNullTest.setter.call(sOne, zTwo)
+ assertEquals(zThree, global)
+ sOne::nonNullTest.setter.call(zThree)
+ assertEquals(zFour, global)
+
+ global = zZero
+ assertEquals(zOne, S::nullableTest.call(sOne))
+ assertEquals(zOne, sOne::nullableTest.call())
+ assertEquals(zOne, S::nullableTest.getter.call(sOne))
+ assertEquals(zOne, sOne::nullableTest.getter.call())
+ S::nullableTest.setter.call(sOne, zTwo)
+ assertEquals(zThree, global)
+ sOne::nullableTest.setter.call(zThree)
+ assertEquals(zFour, global)
+
+ global = zZero
+ assertEquals(zOne, A::nonNullTest.call(aOne))
+ assertEquals(zOne, aOne::nonNullTest.call())
+ assertEquals(zOne, A::nonNullTest.getter.call(aOne))
+ assertEquals(zOne, aOne::nonNullTest.getter.call())
+ A::nonNullTest.setter.call(aOne, zTwo)
+ assertEquals(zThree, global)
+ aOne::nonNullTest.setter.call(zThree)
+ assertEquals(zFour, global)
+
+ global = zZero
+ assertEquals(zOne, A::nullableTest.call(aOne))
+ assertEquals(zOne, aOne::nullableTest.call())
+ assertEquals(zOne, A::nullableTest.getter.call(aOne))
+ assertEquals(zOne, aOne::nullableTest.getter.call())
+ A::nullableTest.setter.call(aOne, zTwo)
+ assertEquals(zThree, global)
+ aOne::nullableTest.setter.call(zThree)
+ assertEquals(zFour, global)
+
+ return "OK"
+}
diff --git a/compiler/testData/codegen/box/reflection/call/valueClasses/overridingFunOfMfvc.kt b/compiler/testData/codegen/box/reflection/call/valueClasses/overridingFunOfMfvc.kt
new file mode 100644
index 0000000..6dc55f7
--- /dev/null
+++ b/compiler/testData/codegen/box/reflection/call/valueClasses/overridingFunOfMfvc.kt
@@ -0,0 +1,40 @@
+// TARGET_BACKEND: JVM_IR
+// WITH_REFLECT
+// LANGUAGE: +ValueClasses
+
+import kotlin.test.assertEquals
+
+interface ITest {
+ fun test(a: Int, b: Z, c: Z?): String
+}
+
+@JvmInline
+value class Z(val x1: UInt, val x2: Int) : ITest {
+ override fun test(a: Int, b: Z, c: Z?) = "$x1$x2$a${b.x1}${b.x2}${c!!.x1}${c!!.x2}"
+}
+
+@JvmInline
+value class S(val x1: String, val x2: String) : ITest {
+ override fun test(a: Int, b: Z, c: Z?) = "$x1$x2$a${b.x1}${b.x2}${c!!.x1}${c!!.x2}"
+}
+
+@JvmInline
+value class A(val x1: Any, val x2: Any) : ITest {
+ override fun test(a: Int, b: Z, c: Z?) = "$x1$x2$a${b.x1}${b.x2}${c!!.x1}${c!!.x2}"
+}
+
+fun box(): String {
+ val two = Z(2U, 3)
+ val four = Z(4U, 5)
+
+ assertEquals("0912345", Z::test.call(Z(0U, 9), 1, two, four))
+ assertEquals("0912345", Z(0U, 9)::test.call(1, two, four))
+
+ assertEquals("0912345", S::test.call(S("0", "9"), 1, two, four))
+ assertEquals("0912345", S("0", "9")::test.call(1, two, four))
+
+ assertEquals("0912345", A::test.call(A(0U, 9), 1, two, four))
+ assertEquals("0912345", A(0U, 9)::test.call(1, two, four))
+
+ return "OK"
+}
diff --git a/compiler/testData/codegen/box/reflection/call/valueClasses/overridingVarOfMfvc.kt b/compiler/testData/codegen/box/reflection/call/valueClasses/overridingVarOfMfvc.kt
new file mode 100644
index 0000000..44c811b
--- /dev/null
+++ b/compiler/testData/codegen/box/reflection/call/valueClasses/overridingVarOfMfvc.kt
@@ -0,0 +1,132 @@
+// TARGET_BACKEND: JVM_IR
+// WITH_REFLECT
+// LANGUAGE: +ValueClasses
+
+import kotlin.test.assertEquals
+
+var global = Z(0U, 0)
+
+interface ITest {
+ var nonNullTest: Z
+ var nullableTest: Z?
+}
+
+@JvmInline
+value class Z(val x1: UInt, val x2: Int) : ITest {
+ override var nonNullTest: Z
+ get() = Z(global.x1 + this.x1, global.x2 + this.x2)
+ set(value) {
+ global = Z(this.x1 + value.x1, this.x2 + value.x2)
+ }
+
+ override var nullableTest: Z?
+ get() = Z(global.x1 + this.x1, global.x2 + this.x2)
+ set(value) {
+ global = Z(this.x1 + value!!.x1, this.x2 + value!!.x2)
+ }
+}
+
+@JvmInline
+value class S(val x1: String, val x2: String) : ITest {
+ override var nonNullTest: Z
+ get() = Z(global.x1 + x1.toUInt(), global.x2 + x2.toInt())
+ set(value) {
+ global = Z(this.x1.toUInt() + value.x1, this.x2.toInt() + value.x2)
+ }
+
+ override var nullableTest: Z?
+ get() = Z(global.x1 + x1.toUInt(), global.x2 + x2.toInt())
+ set(value) {
+ global = Z(this.x1.toUInt() + value!!.x1, this.x2.toInt() + value!!.x2)
+ }
+}
+
+@JvmInline
+value class A(val x1: Any, val x2: Any) : ITest {
+ override var nonNullTest: Z
+ get() = Z(global.x1 + this.x1 as UInt, global.x2 + this.x2 as Int)
+ set(value) {
+ global = Z(this.x1 as UInt + value.x1, this.x2 as Int + value.x2)
+ }
+
+ override var nullableTest: Z?
+ get() = Z(global.x1 + this.x1 as UInt, global.x2 + this.x2 as Int)
+ set(value) {
+ global = Z(this.x1 as UInt + value!!.x1, this.x2 as Int + value!!.x2)
+ }
+
+}
+
+fun box(): String {
+ val zZero = Z(0U, 0)
+ val zOne = Z(1U, -1)
+ val zTwo = Z(2U, -2)
+ val zThree = Z(3U, -3)
+ val zFour = Z(4U, -4)
+
+ val sOne = S("1", "-1")
+
+ val aOne = A(1U, -1)
+
+ global = zZero
+ assertEquals(zOne, Z::nonNullTest.call(zOne))
+ assertEquals(zOne, zOne::nonNullTest.call())
+ assertEquals(zOne, Z::nonNullTest.getter.call(zOne))
+ assertEquals(zOne, zOne::nonNullTest.getter.call())
+ Z::nonNullTest.setter.call(zOne, zTwo)
+ assertEquals(zThree, global)
+ zOne::nonNullTest.setter.call(zThree)
+ assertEquals(zFour, global)
+
+ global = zZero
+ assertEquals(zOne, Z::nullableTest.call(zOne))
+ assertEquals(zOne, zOne::nullableTest.call())
+ assertEquals(zOne, Z::nullableTest.getter.call(zOne))
+ assertEquals(zOne, zOne::nullableTest.getter.call())
+ Z::nullableTest.setter.call(zOne, zTwo)
+ assertEquals(zThree, global)
+ zOne::nullableTest.setter.call(zThree)
+ assertEquals(zFour, global)
+
+ global = zZero
+ assertEquals(zOne, S::nonNullTest.call(sOne))
+ assertEquals(zOne, sOne::nonNullTest.call())
+ assertEquals(zOne, S::nonNullTest.getter.call(sOne))
+ assertEquals(zOne, sOne::nonNullTest.getter.call())
+ S::nonNullTest.setter.call(sOne, zTwo)
+ assertEquals(zThree, global)
+ sOne::nonNullTest.setter.call(zThree)
+ assertEquals(zFour, global)
+
+ global = zZero
+ assertEquals(zOne, S::nullableTest.call(sOne))
+ assertEquals(zOne, sOne::nullableTest.call())
+ assertEquals(zOne, S::nullableTest.getter.call(sOne))
+ assertEquals(zOne, sOne::nullableTest.getter.call())
+ S::nullableTest.setter.call(sOne, zTwo)
+ assertEquals(zThree, global)
+ sOne::nullableTest.setter.call(zThree)
+ assertEquals(zFour, global)
+
+ global = zZero
+ assertEquals(zOne, A::nonNullTest.call(aOne))
+ assertEquals(zOne, aOne::nonNullTest.call())
+ assertEquals(zOne, A::nonNullTest.getter.call(aOne))
+ assertEquals(zOne, aOne::nonNullTest.getter.call())
+ A::nonNullTest.setter.call(aOne, zTwo)
+ assertEquals(zThree, global)
+ aOne::nonNullTest.setter.call(zThree)
+ assertEquals(zFour, global)
+
+ global = zZero
+ assertEquals(zOne, A::nullableTest.call(aOne))
+ assertEquals(zOne, aOne::nullableTest.call())
+ assertEquals(zOne, A::nullableTest.getter.call(aOne))
+ assertEquals(zOne, aOne::nullableTest.getter.call())
+ A::nullableTest.setter.call(aOne, zTwo)
+ assertEquals(zThree, global)
+ aOne::nullableTest.setter.call(zThree)
+ assertEquals(zFour, global)
+
+ return "OK"
+}
diff --git a/compiler/testData/codegen/box/reflection/call/valueClasses/primaryValOfMfvc.kt b/compiler/testData/codegen/box/reflection/call/valueClasses/primaryValOfMfvc.kt
new file mode 100644
index 0000000..d25127d
--- /dev/null
+++ b/compiler/testData/codegen/box/reflection/call/valueClasses/primaryValOfMfvc.kt
@@ -0,0 +1,180 @@
+// TARGET_BACKEND: JVM_IR
+// WITH_REFLECT
+// LANGUAGE: +ValueClasses
+
+import kotlin.test.assertEquals
+
+@JvmInline
+value class Z(val x1: UInt, val x2: Int) {
+ var x3
+ get() = x1
+ set(value) = Unit
+}
+@JvmInline
+value class Z2(val x1: Z, val x2: Z) {
+ var x3
+ get() = x1
+ set(value) = Unit
+}
+
+@JvmInline
+value class L(val x1: ULong, val x2: Long) {
+ var x3
+ get() = x1
+ set(value) = Unit
+}
+@JvmInline
+value class L2(val x1: L, val x2: L) {
+ var x3
+ get() = x1
+ set(value) = Unit
+}
+
+@JvmInline
+value class A1(val x1: Any?, val x2: Any?) {
+ var x3
+ get() = x1
+ set(value) = Unit
+}
+@JvmInline
+value class A1_2(val x1: A1, val x2: A1) {
+ var x3
+ get() = x1
+ set(value) = Unit
+}
+@JvmInline
+value class A2(val x1: Any, val x2: Any) {
+ var x3
+ get() = x1
+ set(value) = Unit
+}
+@JvmInline
+value class A2_2(val x1: A2, val x2: A2) {
+ var x3
+ get() = x1
+ set(value) = Unit
+}
+
+fun box(): String {
+ assertEquals(42U, Z::x1.call(Z(42U, 43)))
+ assertEquals(43, Z::x2.call(Z(42U, 43)))
+ assertEquals(42U, Z::x3.call(Z(42U, 43)))
+ assertEquals(42U, Z::x3.getter.call(Z(42U, 43)))
+ assertEquals(Unit, Z::x3.setter.call(Z(42U, 43), 42U))
+
+ assertEquals(42U, Z(42U, 43)::x1.call())
+ assertEquals(43, Z(42U, 43)::x2.call())
+ assertEquals(42U, Z(42U, 43)::x3.call())
+ assertEquals(42U, Z(42U, 43)::x3.getter.call())
+ assertEquals(Unit, Z(42U, 43)::x3.setter.call(42U))
+
+ assertEquals(1234UL, L::x1.call(L(1234UL, 5678L)))
+ assertEquals(5678L, L::x2.call(L(1234UL, 5678L)))
+ assertEquals(1234UL, L::x3.call(L(1234UL, 5678L)))
+ assertEquals(1234UL, L::x3.getter.call(L(1234UL, 5678L)))
+ assertEquals(Unit, L::x3.setter.call(L(1234UL, 5678L), 1234UL))
+
+ assertEquals(1234UL, L(1234UL, 5678L)::x1.call())
+ assertEquals(5678L, L(1234UL, 5678L)::x2.call())
+ assertEquals(1234UL, L(1234UL, 5678L)::x3.call())
+ assertEquals(1234UL, L(1234UL, 5678L)::x3.getter.call())
+ assertEquals(Unit, L(1234UL, 5678L)::x3.setter.call(1234UL))
+
+ assertEquals("abc", A1::x1.call(A1("abc", "def")))
+ assertEquals("def", A1::x2.call(A1("abc", "def")))
+ assertEquals("abc", A1::x3.call(A1("abc", "def")))
+ assertEquals("abc", A1::x3.getter.call(A1("abc", "def")))
+ assertEquals(Unit, A1::x3.setter.call(A1("abc", "def"), "abc"))
+
+ assertEquals("abc", A1("abc", "def")::x1.call())
+ assertEquals("def", A1("abc", "def")::x2.call())
+ assertEquals("abc", A1("abc", "def")::x3.call())
+ assertEquals("abc", A1("abc", "def")::x3.getter.call())
+ assertEquals(Unit, A1("abc", "def")::x3.setter.call("abc"))
+
+ assertEquals(null, A1::x1.call(A1(null, null)))
+ assertEquals(null, A1::x2.call(A1(null, null)))
+ assertEquals(null, A1::x3.call(A1(null, null)))
+ assertEquals(null, A1::x3.getter.call(A1(null, null)))
+ assertEquals(Unit, A1::x3.setter.call(A1(null, null), null))
+
+ assertEquals(null, A1(null, null)::x1.call())
+ assertEquals(null, A1(null, null)::x2.call())
+ assertEquals(null, A1(null, null)::x3.call())
+ assertEquals(null, A1(null, null)::x3.getter.call())
+ assertEquals(Unit, A1(null, null)::x3.setter.call(null))
+
+ assertEquals("abc", A2::x1.call(A2("abc", "def")))
+ assertEquals("def", A2::x2.call(A2("abc", "def")))
+ assertEquals("abc", A2::x3.call(A2("abc", "def")))
+ assertEquals("abc", A2::x3.getter.call(A2("abc", "def")))
+ assertEquals(Unit, A2::x3.setter.call(A2("abc", "def"), "abc"))
+
+ assertEquals("abc", A2("abc", "def")::x1.call())
+ assertEquals("def", A2("abc", "def")::x2.call())
+ assertEquals("abc", A2("abc", "def")::x3.call())
+ assertEquals("abc", A2("abc", "def")::x3.getter.call())
+ assertEquals(Unit, A2("abc", "def")::x3.setter.call("abc"))
+
+ assertEquals(Z(42U, 43), Z2::x1.call(Z2(Z(42U, 43), Z(44U, 45))))
+ assertEquals(Z(44U, 45), Z2::x2.call(Z2(Z(42U, 43), Z(44U, 45))))
+ assertEquals(Z(42U, 43), Z2::x3.call(Z2(Z(42U, 43), Z(44U, 45))))
+ assertEquals(Z(42U, 43), Z2::x3.getter.call(Z2(Z(42U, 43), Z(44U, 45))))
+ assertEquals(Unit, Z2::x3.setter.call(Z2(Z(42U, 43), Z(44U, 45)), Z(42U, 43)))
+
+ assertEquals(Z(42U, 43), Z2(Z(42U, 43), Z(44U, 45))::x1.call())
+ assertEquals(Z(44U, 45), Z2(Z(42U, 43), Z(44U, 45))::x2.call())
+ assertEquals(Z(42U, 43), Z2(Z(42U, 43), Z(44U, 45))::x3.call())
+ assertEquals(Z(42U, 43), Z2(Z(42U, 43), Z(44U, 45))::x3.getter.call())
+ assertEquals(Unit, Z2(Z(42U, 43), Z(44U, 45))::x3.setter.call(Z(42U, 43)))
+
+ assertEquals(L(1234UL, 5678L), L2::x1.call(L2(L(1234UL, 5678L), L(12340UL, -5678L))))
+ assertEquals(L(12340UL, -5678L), L2::x2.call(L2(L(1234UL, 5678L), L(12340UL, -5678L))))
+ assertEquals(L(1234UL, 5678L), L2::x3.call(L2(L(1234UL, 5678L), L(12340UL, -5678L))))
+ assertEquals(L(1234UL, 5678L), L2::x3.getter.call(L2(L(1234UL, 5678L), L(12340UL, -5678L))))
+ assertEquals(Unit, L2::x3.setter.call(L2(L(1234UL, 5678L), L(12340UL, -5678L)), L(1234UL, 5678L)))
+
+ assertEquals(L(1234UL, 5678L), L2(L(1234UL, 5678L), L(12340UL, -5678L))::x1.call())
+ assertEquals(L(12340UL, -5678L), L2(L(1234UL, 5678L), L(12340UL, -5678L))::x2.call())
+ assertEquals(L(1234UL, 5678L), L2(L(1234UL, 5678L), L(12340UL, -5678L))::x3.call())
+ assertEquals(L(1234UL, 5678L), L2(L(1234UL, 5678L), L(12340UL, -5678L))::x3.getter.call())
+ assertEquals(Unit, L2(L(1234UL, 5678L), L(12340UL, -5678L))::x3.setter.call(L(1234UL, 5678L)))
+
+ assertEquals(A1("abc", "def"), A1_2::x1.call(A1_2(A1("abc", "def"), A1("geh", "ijk"))))
+ assertEquals(A1("geh", "ijk"), A1_2::x2.call(A1_2(A1("abc", "def"), A1("geh", "ijk"))))
+ assertEquals(A1("abc", "def"), A1_2::x3.call(A1_2(A1("abc", "def"), A1("geh", "ijk"))))
+ assertEquals(A1("abc", "def"), A1_2::x3.getter.call(A1_2(A1("abc", "def"), A1("geh", "ijk"))))
+ assertEquals(Unit, A1_2::x3.setter.call(A1_2(A1("abc", "def"), A1("geh", "ijk")), A1("abc", "def")))
+
+ assertEquals(A1("abc", "def"), A1_2(A1("abc", "def"), A1("geh", "ijk"))::x1.call())
+ assertEquals(A1("geh", "ijk"), A1_2(A1("abc", "def"), A1("geh", "ijk"))::x2.call())
+ assertEquals(A1("abc", "def"), A1_2(A1("abc", "def"), A1("geh", "ijk"))::x3.call())
+ assertEquals(A1("abc", "def"), A1_2(A1("abc", "def"), A1("geh", "ijk"))::x3.getter.call())
+ assertEquals(Unit, A1_2(A1("abc", "def"), A1("geh", "ijk"))::x3.setter.call(A1("abc", "def")))
+
+ assertEquals(A1(null, null), A1_2::x1.call(A1_2(A1(null, null), A1(null, null))))
+ assertEquals(A1(null, null), A1_2::x2.call(A1_2(A1(null, null), A1(null, null))))
+ assertEquals(A1(null, null), A1_2::x3.call(A1_2(A1(null, null), A1(null, null))))
+ assertEquals(A1(null, null), A1_2::x3.getter.call(A1_2(A1(null, null), A1(null, null))))
+ assertEquals(Unit, A1_2::x3.setter.call(A1_2(A1(null, null), A1(null, null)), A1(null, null)))
+
+ assertEquals(A1(null, null), A1_2(A1(null, null), A1(null, null))::x1.call())
+ assertEquals(A1(null, null), A1_2(A1(null, null), A1(null, null))::x2.call())
+ assertEquals(A1(null, null), A1_2(A1(null, null), A1(null, null))::x3.call())
+ assertEquals(A1(null, null), A1_2(A1(null, null), A1(null, null))::x3.getter.call())
+ assertEquals(Unit, A1_2(A1(null, null), A1(null, null))::x3.setter.call(A1(null, null)))
+
+ assertEquals(A2("abc", "def"), A2_2::x1.call(A2_2(A2("abc", "def"), A2("geh", "ijk"))))
+ assertEquals(A2("geh", "ijk"), A2_2::x2.call(A2_2(A2("abc", "def"), A2("geh", "ijk"))))
+ assertEquals(A2("abc", "def"), A2_2::x3.call(A2_2(A2("abc", "def"), A2("geh", "ijk"))))
+ assertEquals(A2("abc", "def"), A2_2::x3.getter.call(A2_2(A2("abc", "def"), A2("geh", "ijk"))))
+ assertEquals(Unit, A2_2::x3.setter.call(A2_2(A2("abc", "def"), A2("geh", "ijk")), A2("abc", "def")))
+
+ assertEquals(A2("abc", "def"), A2_2(A2("abc", "def"), A2("geh", "ijk"))::x1.call())
+ assertEquals(A2("geh", "ijk"), A2_2(A2("abc", "def"), A2("geh", "ijk"))::x2.call())
+ assertEquals(A2("abc", "def"), A2_2(A2("abc", "def"), A2("geh", "ijk"))::x3.call())
+ assertEquals(A2("abc", "def"), A2_2(A2("abc", "def"), A2("geh", "ijk"))::x3.getter.call())
+ assertEquals(Unit, A2_2(A2("abc", "def"), A2("geh", "ijk"))::x3.setter.call(A2("abc", "def")))
+
+ return "OK"
+}
diff --git a/compiler/testData/codegen/box/reflection/call/valueClasses/properties.kt b/compiler/testData/codegen/box/reflection/call/valueClasses/properties.kt
new file mode 100644
index 0000000..3e37c63
--- /dev/null
+++ b/compiler/testData/codegen/box/reflection/call/valueClasses/properties.kt
@@ -0,0 +1,122 @@
+// TARGET_BACKEND: JVM_IR
+// WITH_REFLECT
+// LANGUAGE: +ValueClasses
+
+import kotlin.reflect.KMutableProperty2
+import kotlin.test.assertEquals
+
+@JvmInline
+value class Z(val value1: UInt, val value2: Int) {
+ operator fun plus(other: Z): Z = Z(this.value1 + other.value1, this.value2 + other.value2)
+}
+
+class C {
+ var nonNullMember: Z = Z(0U, 0)
+ var nullableMember: Z? = Z(0U, 0)
+
+ private var offset = Z(0U, 0)
+ var Z.nonNull_nonNullMemExt: Z
+ get() = this + offset
+ set(value) { offset = this + value }
+
+ var Z.nonNull_nullableMemExt: Z?
+ get() = this + offset
+ set(value) { offset = this + value!! }
+
+ var Z?.nullable_nonNullMemExt: Z
+ get() = this!! + offset
+ set(value) { offset = this!! + value }
+
+ var Z?.nullable_nullableMemExt: Z?
+ get() = this!! + offset
+ set(value) { offset = this!! + value!! }
+}
+
+var nonNullTopLevel: Z = Z(0U, 0)
+var nullableTopLevel: Z? = Z(0U, 0)
+
+private var offset = Z(0U, 0)
+var Z.nonNull_nonNullExt: Z
+ get() = this + offset
+ set(value) { offset = this + value }
+
+var Z.nonNull_nullableExt: Z?
+ get() = this + offset
+ set(value) { offset = this + value!! }
+
+var Z?.nullable_nonNullExt: Z
+ get() = this!! + offset
+ set(value) { offset = this!! + value }
+
+var Z?.nullable_nullableExt: Z?
+ get() = this!! + offset
+ set(value) { offset = this!! + value!! }
+
+fun box(): String {
+ val one = Z(1U, -1)
+ val two = Z(2U, -2)
+ val three = Z(3U, -3)
+
+ val c = C()
+ assertEquals(Unit, C::nonNullMember.setter.call(c, one))
+ assertEquals(one, C::nonNullMember.call(c))
+ assertEquals(one, C::nonNullMember.getter.call(c))
+
+ assertEquals(Unit, c::nonNullMember.setter.call(two))
+ assertEquals(two, c::nonNullMember.call())
+ assertEquals(two, c::nonNullMember.getter.call())
+
+ assertEquals(Unit, C::nullableMember.setter.call(c, one))
+ assertEquals(one, C::nullableMember.call(c))
+ assertEquals(one, C::nullableMember.getter.call(c))
+
+ assertEquals(Unit, c::nullableMember.setter.call(two))
+ assertEquals(two, c::nullableMember.call())
+ assertEquals(two, c::nullableMember.getter.call())
+
+ val nonNull_nonNullMemExt = C::class.members.single { it.name == "nonNull_nonNullMemExt" } as KMutableProperty2<C, Z, Z>
+ assertEquals(Unit, nonNull_nonNullMemExt.setter.call(c, Z(0U, 0), two))
+ assertEquals(three, nonNull_nonNullMemExt.call(c, one))
+ assertEquals(three, nonNull_nonNullMemExt.getter.call(c, one))
+
+ val nonNull_nullableMemExt = C::class.members.single { it.name == "nonNull_nullableMemExt" } as KMutableProperty2<C, Z, Z?>
+ assertEquals(Unit, nonNull_nullableMemExt.setter.call(c, Z(0U, 0), two))
+ assertEquals(three, nonNull_nullableMemExt.call(c, one))
+ assertEquals(three, nonNull_nullableMemExt.getter.call(c, one))
+
+ val nullable_nonNullMemExt = C::class.members.single { it.name == "nullable_nonNullMemExt" } as KMutableProperty2<C, Z?, Z>
+ assertEquals(Unit, nullable_nonNullMemExt.setter.call(c, Z(0U, 0), two))
+ assertEquals(three, nullable_nonNullMemExt.call(c, one))
+ assertEquals(three, nullable_nonNullMemExt.getter.call(c, one))
+
+ val nullable_nullableMemExt = C::class.members.single { it.name == "nullable_nullableMemExt" } as KMutableProperty2<C, Z?, Z?>
+ assertEquals(Unit, nullable_nullableMemExt.setter.call(c, Z(0U, 0), two))
+ assertEquals(three, nullable_nullableMemExt.call(c, one))
+ assertEquals(three, nullable_nullableMemExt.getter.call(c, one))
+
+ assertEquals(Unit, ::nonNullTopLevel.setter.call(one))
+ assertEquals(one, ::nonNullTopLevel.call())
+ assertEquals(one, ::nonNullTopLevel.getter.call())
+
+ assertEquals(Unit, ::nullableTopLevel.setter.call(one))
+ assertEquals(one, ::nullableTopLevel.call())
+ assertEquals(one, ::nullableTopLevel.getter.call())
+
+ assertEquals(Unit, Z::nonNull_nonNullExt.setter.call(Z(0U, 0), two))
+ assertEquals(three, Z::nonNull_nonNullExt.call(one))
+ assertEquals(three, Z::nonNull_nonNullExt.getter.call(one))
+
+ assertEquals(Unit, Z::nonNull_nullableExt.setter.call(Z(0U, 0), two))
+ assertEquals(three, Z::nonNull_nullableExt.call(one))
+ assertEquals(three, Z::nonNull_nullableExt.getter.call(one))
+
+ assertEquals(Unit, Z?::nullable_nonNullExt.setter.call(Z(0U, 0), two))
+ assertEquals(three, Z?::nullable_nonNullExt.call(one))
+ assertEquals(three, Z?::nullable_nonNullExt.getter.call(one))
+
+ assertEquals(Unit, Z?::nullable_nullableExt.setter.call(Z(0U, 0), two))
+ assertEquals(three, Z?::nullable_nullableExt.call(one))
+ assertEquals(three, Z?::nullable_nullableExt.getter.call(one))
+
+ return "OK"
+}
diff --git a/compiler/testData/codegen/box/reflection/call/valueClasses/suspendFunction.kt b/compiler/testData/codegen/box/reflection/call/valueClasses/suspendFunction.kt
new file mode 100644
index 0000000..5b19e09
--- /dev/null
+++ b/compiler/testData/codegen/box/reflection/call/valueClasses/suspendFunction.kt
@@ -0,0 +1,91 @@
+// TARGET_BACKEND: JVM_IR
+// WITH_REFLECT
+// WITH_COROUTINES
+// LANGUAGE: +ValueClasses
+
+import kotlin.coroutines.startCoroutine
+import kotlin.reflect.full.callSuspend
+import kotlin.test.assertEquals
+import kotlin.test.assertFailsWith
+import helpers.*
+
+@JvmInline
+value class Z(val value1: UInt, val value2: Int)
+
+class C {
+ private var value: Z = Z(0U, 0)
+
+ suspend fun nonNullConsume(z: Z) { value = z }
+ suspend fun nonNullProduce(): Z = value
+ suspend fun nullableConsume(z: Z?) { value = z!! }
+ suspend fun nullableProduce(): Z? = value
+ suspend fun nonNull_nonNullConsumeAndProduce(z: Z): Z = z
+ suspend fun nonNull_nullableConsumeAndProduce(z: Z): Z? = z
+ suspend fun nullable_nonNullConsumeAndProduce(z: Z?): Z = z!!
+ suspend fun nullable_nullableConsumeAndProduce(z: Z?): Z? = z
+}
+
+private fun run0(f: suspend () -> Int): Int {
+ var result = -1
+ f.startCoroutine(handleResultContinuation { result = it })
+ return result
+}
+
+private fun run0U(f: suspend () -> UInt): UInt {
+ var result = UInt.MAX_VALUE
+ f.startCoroutine(handleResultContinuation { result = it })
+ return result
+}
+
+fun box(): String {
+ val c = C()
+
+ run0U {
+ C::nonNullConsume.callSuspend(c, Z(1U, -1))
+ C::nonNullProduce.callSuspend(c).value1
+ }.let { assertEquals(1U, it) }
+
+ run0 {
+ C::nonNullConsume.callSuspend(c, Z(1U, -1))
+ C::nonNullProduce.callSuspend(c).value2
+ }.let { assertEquals(-1, it) }
+
+ run0U {
+ C::nullableConsume.callSuspend(c, Z(2U, -2))
+ C::nullableProduce.callSuspend(c)!!.value1
+ }.let { assertEquals(2U, it) }
+ run0 {
+ C::nullableConsume.callSuspend(c, Z(2U, -2))
+ C::nullableProduce.callSuspend(c)!!.value2
+ }.let { assertEquals(-2, it) }
+
+ run0U {
+ C::nonNull_nonNullConsumeAndProduce.callSuspend(c, Z(3U, -3)).value1
+ }.let { assertEquals(3U, it) }
+ run0 {
+ C::nonNull_nonNullConsumeAndProduce.callSuspend(c, Z(3U, -3)).value2
+ }.let { assertEquals(-3, it) }
+
+ run0U {
+ C::nonNull_nullableConsumeAndProduce.callSuspend(c, Z(4U, -4))!!.value1
+ }.let { assertEquals(4U, it) }
+ run0 {
+ C::nonNull_nullableConsumeAndProduce.callSuspend(c, Z(4U, -4))!!.value2
+ }.let { assertEquals(-4, it) }
+
+ run0U {
+ C::nullable_nonNullConsumeAndProduce.callSuspend(c, Z(5U, -5)).value1
+ }.let { assertEquals(5U, it) }
+ run0 {
+ C::nullable_nonNullConsumeAndProduce.callSuspend(c, Z(5U, -5)).value2
+ }.let { assertEquals(-5, it) }
+
+ run0U {
+ C::nullable_nullableConsumeAndProduce.callSuspend(c, Z(6U, -6))!!.value1
+ }.let { assertEquals(6U, it) }
+ run0 {
+ C::nullable_nullableConsumeAndProduce.callSuspend(c, Z(6U, -6))!!.value2
+ }.let { assertEquals(-6, it) }
+
+ return "OK"
+}
diff --git a/compiler/testData/codegen/box/reflection/callBy/mfvcDefaultArguments.kt b/compiler/testData/codegen/box/reflection/callBy/mfvcDefaultArguments.kt
new file mode 100644
index 0000000..9de476a
--- /dev/null
+++ b/compiler/testData/codegen/box/reflection/callBy/mfvcDefaultArguments.kt
@@ -0,0 +1,72 @@
+// TARGET_BACKEND: JVM_IR
+// WITH_REFLECT
+// LANGUAGE: +ValueClasses
+
+import kotlin.test.assertEquals
+
+@JvmInline
+value class A(val x: UInt, val y: Int)
+
+fun test1(x: A = A(0U, 1)) = "OK"
+
+fun test32(
+ arg00: Long = 0L, arg01: Long = 0L, arg02: Long = 0L, arg03: Long = 0L, arg04: Long = 0L,
+ arg05: Long = 0L, arg06: Long = 0L, arg07: Long = 0L, arg08: Long = 0L, arg09: Long = 0L,
+ arg10: Long = 0L, arg11: Long = 0L, arg12: Long = 0L, arg13: Long = 0L, arg14: Long = 0L,
+ arg15: Long = 0L, arg16: Long = 0L, arg17: Long = 0L, arg18: Long = 0L, arg19: Long = 0L,
+ arg20: Long = 0L, arg21: Long = 0L, arg22: Long = 0L, arg23: Long = 0L, arg24: Long = 0L,
+ arg25: Long = 0L, arg26: Long = 0L, arg27: Long = 0L, arg28: Long = 0L, arg29: Long = 0L,
+ arg30: Long = 0L, x: A = A(0U, 1)
+) = "OK"
+
+fun test33(
+ arg00: Long = 0L, arg01: Long = 0L, arg02: Long = 0L, arg03: Long = 0L, arg04: Long = 0L,
+ arg05: Long = 0L, arg06: Long = 0L, arg07: Long = 0L, arg08: Long = 0L, arg09: Long = 0L,
+ arg10: Long = 0L, arg11: Long = 0L, arg12: Long = 0L, arg13: Long = 0L, arg14: Long = 0L,
+ arg15: Long = 0L, arg16: Long = 0L, arg17: Long = 0L, arg18: Long = 0L, arg19: Long = 0L,
+ arg20: Long = 0L, arg21: Long = 0L, arg22: Long = 0L, arg23: Long = 0L, arg24: Long = 0L,
+ arg25: Long = 0L, arg26: Long = 0L, arg27: Long = 0L, arg28: Long = 0L, arg29: Long = 0L,
+ arg30: Long = 0L, arg31: Long = 0L, x: A = A(0U, 1)
+) = "OK"
+
+fun test64(
+ arg00: Long = 0L, arg01: Long = 0L, arg02: Long = 0L, arg03: Long = 0L, arg04: Long = 0L,
+ arg05: Long = 0L, arg06: Long = 0L, arg07: Long = 0L, arg08: Long = 0L, arg09: Long = 0L,
+ arg10: Long = 0L, arg11: Long = 0L, arg12: Long = 0L, arg13: Long = 0L, arg14: Long = 0L,
+ arg15: Long = 0L, arg16: Long = 0L, arg17: Long = 0L, arg18: Long = 0L, arg19: Long = 0L,
+ arg20: Long = 0L, arg21: Long = 0L, arg22: Long = 0L, arg23: Long = 0L, arg24: Long = 0L,
+ arg25: Long = 0L, arg26: Long = 0L, arg27: Long = 0L, arg28: Long = 0L, arg29: Long = 0L,
+ arg30: Long = 0L, arg31: Long = 0L, arg32: Long = 0L, arg33: Long = 0L, arg34: Long = 0L,
+ arg35: Long = 0L, arg36: Long = 0L, arg37: Long = 0L, arg38: Long = 0L, arg39: Long = 0L,
+ arg40: Long = 0L, arg41: Long = 0L, arg42: Long = 0L, arg43: Long = 0L, arg44: Long = 0L,
+ arg45: Long = 0L, arg46: Long = 0L, arg47: Long = 0L, arg48: Long = 0L, arg49: Long = 0L,
+ arg50: Long = 0L, arg51: Long = 0L, arg52: Long = 0L, arg53: Long = 0L, arg54: Long = 0L,
+ arg55: Long = 0L, arg56: Long = 0L, arg57: Long = 0L, arg58: Long = 0L, arg59: Long = 0L,
+ arg60: Long = 0L, arg61: Long = 0L, arg62: Long = 0L, x: A = A(0U, 1)
+) = "OK"
+
+fun test65(
+ arg00: Long = 0L, arg01: Long = 0L, arg02: Long = 0L, arg03: Long = 0L, arg04: Long = 0L,
+ arg05: Long = 0L, arg06: Long = 0L, arg07: Long = 0L, arg08: Long = 0L, arg09: Long = 0L,
+ arg10: Long = 0L, arg11: Long = 0L, arg12: Long = 0L, arg13: Long = 0L, arg14: Long = 0L,
+ arg15: Long = 0L, arg16: Long = 0L, arg17: Long = 0L, arg18: Long = 0L, arg19: Long = 0L,
+ arg20: Long = 0L, arg21: Long = 0L, arg22: Long = 0L, arg23: Long = 0L, arg24: Long = 0L,
+ arg25: Long = 0L, arg26: Long = 0L, arg27: Long = 0L, arg28: Long = 0L, arg29: Long = 0L,
+ arg30: Long = 0L, arg31: Long = 0L, arg32: Long = 0L, arg33: Long = 0L, arg34: Long = 0L,
+ arg35: Long = 0L, arg36: Long = 0L, arg37: Long = 0L, arg38: Long = 0L, arg39: Long = 0L,
+ arg40: Long = 0L, arg41: Long = 0L, arg42: Long = 0L, arg43: Long = 0L, arg44: Long = 0L,
+ arg45: Long = 0L, arg46: Long = 0L, arg47: Long = 0L, arg48: Long = 0L, arg49: Long = 0L,
+ arg50: Long = 0L, arg51: Long = 0L, arg52: Long = 0L, arg53: Long = 0L, arg54: Long = 0L,
+ arg55: Long = 0L, arg56: Long = 0L, arg57: Long = 0L, arg58: Long = 0L, arg59: Long = 0L,
+ arg60: Long = 0L, arg61: Long = 0L, arg62: Long = 0L, arg63: Long = 0L, x: A = A(0U, 1)
+) = "OK"
+
+fun box(): String {
+ assertEquals("OK", ::test1.callBy(mapOf()))
+ assertEquals("OK", ::test32.callBy(mapOf()))
+ assertEquals("OK", ::test33.callBy(mapOf()))
+ assertEquals("OK", ::test64.callBy(mapOf()))
+ assertEquals("OK", ::test65.callBy(mapOf()))
+
+ return "OK"
+}
diff --git a/compiler/testData/codegen/box/reflection/callBy/mfvcFunctionsAndConstructors.kt b/compiler/testData/codegen/box/reflection/callBy/mfvcFunctionsAndConstructors.kt
new file mode 100644
index 0000000..f84056a
--- /dev/null
+++ b/compiler/testData/codegen/box/reflection/callBy/mfvcFunctionsAndConstructors.kt
@@ -0,0 +1,53 @@
+// TARGET_BACKEND: JVM_IR
+// WITH_REFLECT
+// LANGUAGE: +ValueClasses
+
+import kotlin.test.assertEquals
+import kotlin.test.assertTrue
+
+@JvmInline
+value class S(val value1: UInt, val value2: String) {
+ operator fun plus(other: S): S = S(this.value1 * 10U + other.value1, this.value2 + other.value2)
+}
+
+class C {
+ fun member(a: S, b: S = S(1U, "b2")): S = a + b
+}
+
+fun topLevel(c: S, d: S = S(1U, "d2")): S = c + d
+
+class D(e: S, f: S = S(1U, "f2")) {
+ val result = e + f
+}
+
+fun S.extension(h: S = S(1U, "h2")): S = this + h
+
+fun box(): String {
+ assertEquals(S(11U, "a2b2"), C().member(S(1U, "a2")))
+ assertEquals(
+ S(11U, "a2b2"),
+ C::member.callBy(C::member.parameters.filter { it.name != "b" }.associateWith { (if (it.name == "a") S(1U, "a2") else C()) })
+ )
+
+ assertEquals(S(11U, "c2d2"), topLevel(S(1U, "c2")))
+ assertEquals(S(11U, "c2d2"), ::topLevel.callBy(::topLevel.parameters.filter { it.name != "d" }.associateWith { S(1U, "c2") }))
+
+ assertEquals(S(11U, "e2f2"), ::D.callBy(::D.parameters.filter { it.name != "f" }.associateWith { S(1U, "e2") }).result)
+
+ assertEquals(S(11U, "g2h2"), S(1U, "g2").extension())
+ assertEquals(S(11U, "g2h2"), S::extension.callBy(S::extension.parameters.filter { it.name != "h" }.associateWith { S(1U, "g2") }))
+
+ val boundMember = C()::member
+ assertEquals(S(11U, "a2b2"), boundMember.callBy(boundMember.parameters.associateWith { S(1U, it.name!! + "2") }))
+
+ val boundExtension = S(1U, "g2")::extension
+ assertEquals(S(11U, "g2h2"), boundExtension.callBy(boundExtension.parameters.associateWith { S(1U, it.name!! + "2") }))
+
+ val mfvcConstructor = ::S
+ val exception = runCatching { mfvcConstructor.callBy(mapOf(mfvcConstructor.parameters.first() to 1U)) }.exceptionOrNull()!!
+ assertTrue(exception is IllegalArgumentException)
+ assertTrue(exception.message!!.startsWith("No argument provided for a required parameter: parameter #1 value2 of fun `<init>`(kotlin.UInt, kotlin.String): "), exception.message)
+ assertTrue(exception.message!!.endsWith("S"), exception.message)
+
+ return "OK"
+}
diff --git a/compiler/testData/codegen/box/reflection/callBy/mfvcMembers.kt b/compiler/testData/codegen/box/reflection/callBy/mfvcMembers.kt
new file mode 100644
index 0000000..6fb4129
--- /dev/null
+++ b/compiler/testData/codegen/box/reflection/callBy/mfvcMembers.kt
@@ -0,0 +1,77 @@
+// TARGET_BACKEND: JVM_IR
+// WITH_REFLECT
+// LANGUAGE: +ValueClasses
+import kotlin.test.assertEquals
+
+interface IFoo {
+ fun fooFun(z: Z): Z
+ var fooVar: Z
+}
+
+var global = Z(0U, 0)
+
+
+@JvmInline
+value class Z(val x1: UInt, val x2: Int) : IFoo {
+
+ override fun fooFun(z: Z): Z = Z(z.x1 + x1, z.x2 + x2)
+
+ override var fooVar: Z
+ get() = Z(global.x1 + x1, global.x2 + x2)
+ set(value) {
+ global = Z(value.x1 + x1, value.x2 + x2)
+ }
+
+ fun barFun(z: Z): Z = Z(z.x1 * 100U + x1, z.x2 * 100 + x2)
+
+ var barVar: Z
+ get() = Z(global.x1 * 100U + x1, global.x2 * 100 + x2)
+ set(value) {
+ global = Z(value.x1 * 100U + x1, value.x2 * 100 + x2)
+ }
+}
+
+
+fun box(): String {
+ val fooFunR = Z::fooFun
+ assertEquals(Z(53U, -53), fooFunR.callBy(mapOf(fooFunR.parameters[0] to Z(42U, -42), fooFunR.parameters[1] to Z(11U, -11))))
+
+ val fooFunBR = Z(42U, -42)::fooFun
+ assertEquals(Z(142U, -142), fooFunBR.callBy(mapOf(fooFunBR.parameters[0] to Z(100U, -100))))
+
+ global = Z(0U, 0)
+ val fooVarR = Z::fooVar
+ assertEquals(Z(42U, -42), fooVarR.callBy(mapOf(fooVarR.parameters[0] to Z(42U, -42))))
+ assertEquals(Z(42U, -42), fooVarR.getter.callBy(mapOf(fooVarR.getter.parameters[0] to Z(42U, -42))))
+ fooVarR.setter.callBy(mapOf(fooVarR.setter.parameters[0] to Z(42U, -42), fooVarR.setter.parameters[1] to Z(1U, -1)))
+ assertEquals(Z(43U, -43), global)
+
+ global = Z(100U, -100)
+ val fooVarBR = Z(42U, -42)::fooVar
+ assertEquals(Z(142U, -142), fooVarBR.callBy(mapOf()))
+ assertEquals(Z(142U, -142), fooVarBR.getter.callBy(mapOf()))
+ fooVarBR.setter.callBy(mapOf(fooVarBR.setter.parameters[0] to Z(1U, -1)))
+ assertEquals(Z(43U, -43), global)
+
+ val barFunR = Z::barFun
+ assertEquals(Z(1142U, -1142), barFunR.callBy(mapOf(barFunR.parameters[0] to Z(42U, -42), barFunR.parameters[1] to Z(11U, -11))))
+
+ val barFunBR = Z(42U, -42)::barFun
+ assertEquals(Z(2242U, -2242), barFunBR.callBy(mapOf(barFunBR.parameters[0] to Z(22U, -22))))
+
+ global = Z(1U, -1)
+ val barVarR = Z::barVar
+ assertEquals(Z(142U, -142), barVarR.callBy(mapOf(barVarR.parameters[0] to Z(42U, -42))))
+ assertEquals(Z(142U, -142), barVarR.getter.callBy(mapOf(barVarR.getter.parameters[0] to Z(42U, -42))))
+ barVarR.setter.callBy(mapOf(barVarR.setter.parameters[0] to Z(42U, -42), barVarR.setter.parameters[1] to Z(3U, -3)))
+ assertEquals(Z(342U, -342), global)
+
+ global = Z(2U, -2)
+ val barVarBR = Z(42U, -42)::barVar
+ assertEquals(Z(242U, -242), barVarBR.callBy(mapOf()))
+ assertEquals(Z(242U, -242), barVarBR.getter.callBy(mapOf()))
+ barVarBR.setter.callBy(mapOf(barVarBR.setter.parameters[0] to Z(4U, -4)))
+ assertEquals(Z(442U, -442), global)
+
+ return "OK"
+}
\ No newline at end of file
diff --git a/compiler/testData/codegen/box/reflection/lambdaClasses/reflectOnDefaultWithMfvcArgument.kt b/compiler/testData/codegen/box/reflection/lambdaClasses/reflectOnDefaultWithMfvcArgument.kt
new file mode 100644
index 0000000..7256f40
--- /dev/null
+++ b/compiler/testData/codegen/box/reflection/lambdaClasses/reflectOnDefaultWithMfvcArgument.kt
@@ -0,0 +1,14 @@
+// LAMBDAS: CLASS
+// !OPT_IN: kotlin.reflect.jvm.ExperimentalReflectionOnLambdas
+// TARGET_BACKEND: JVM_IR
+// WITH_REFLECT
+// LANGUAGE: +ValueClasses
+
+import kotlin.reflect.jvm.reflect
+
+@JvmInline
+value class C(val x1: UInt, val x2: Int)
+
+fun C.f(x: (String) -> Unit = { OK: String -> }) = x.reflect()?.parameters?.singleOrNull()?.name
+
+fun box(): String = C(0U, 1).f() ?: "null"
diff --git a/compiler/testData/codegen/box/reflection/mapping/constructorWithMfvcParameters.kt b/compiler/testData/codegen/box/reflection/mapping/constructorWithMfvcParameters.kt
new file mode 100644
index 0000000..cfefc53
--- /dev/null
+++ b/compiler/testData/codegen/box/reflection/mapping/constructorWithMfvcParameters.kt
@@ -0,0 +1,23 @@
+// TARGET_BACKEND: JVM_IR
+// WITH_REFLECT
+// LANGUAGE: +ValueClasses
+import kotlin.reflect.full.primaryConstructor
+import kotlin.reflect.jvm.javaConstructor
+import kotlin.reflect.jvm.kotlinFunction
+import kotlin.test.assertEquals
+
+@JvmInline
+value class Z(val x1: UInt, val x2: Int)
+
+class Test(val x: Z)
+
+fun box(): String {
+ val kctor1 = Test::class.primaryConstructor ?: throw AssertionError("No primary constructor")
+ val jctor1 = kctor1.javaConstructor ?: throw AssertionError("No javaConstructor for $kctor1")
+ val kctor2 = jctor1.kotlinFunction ?: throw AssertionError("No kotlinFunction for $jctor1")
+
+ assertEquals(kctor1, kctor2)
+ assertEquals("[x]", kctor2.parameters.map { it.name }.toString())
+
+ return "OK"
+}
\ No newline at end of file
diff --git a/compiler/testData/codegen/box/reflection/mapping/types/inlineClassInSignature.kt b/compiler/testData/codegen/box/reflection/mapping/types/inlineClassInSignature.kt
index d9f90b9..eb9ddc0 100644
--- a/compiler/testData/codegen/box/reflection/mapping/types/inlineClassInSignature.kt
+++ b/compiler/testData/codegen/box/reflection/mapping/types/inlineClassInSignature.kt
@@ -8,20 +8,16 @@
fun S.foo(x: Int, s: S): S = this
-/* TODO: Support calling members of inline classes in reflection (KT-26748)
inline class T(val s: S) {
fun bar(u: S): T = this
}
-*/
fun box(): String {
assertEquals(listOf(String::class.java, Int::class.java, String::class.java), S::foo.parameters.map { it.type.javaType })
assertEquals(String::class.java, S::foo.returnType.javaType)
-/*
- assertEquals(listOf(), T::bar.parameters.map { it.type.javaType })
+ assertEquals(listOf(String::class.java, String::class.java), T::bar.parameters.map { it.type.javaType })
assertEquals(String::class.java, T::bar.returnType.javaType)
-*/
return "OK"
}
diff --git a/compiler/testData/codegen/box/reflection/mapping/types/mfvcInSignature.kt b/compiler/testData/codegen/box/reflection/mapping/types/mfvcInSignature.kt
new file mode 100644
index 0000000..e7b0a61
--- /dev/null
+++ b/compiler/testData/codegen/box/reflection/mapping/types/mfvcInSignature.kt
@@ -0,0 +1,46 @@
+// TARGET_BACKEND: JVM_IR
+// WITH_REFLECT
+// LANGUAGE: +ValueClasses
+
+import kotlin.reflect.jvm.*
+import kotlin.test.assertEquals
+import java.lang.reflect.Type
+
+@JvmInline
+value class S(val value1: UInt, val value2: String)
+
+fun S.foo(x: Int, s: S): S = this
+
+fun compoundType(vararg types: Type) = listOf(*types).toString()
+
+@JvmInline
+value class T(val s: S) {
+ fun bar(u: S): T = this
+}
+data class U(val s: S) {
+ fun bar(u: S): U = this
+}
+
+@kotlin.ExperimentalStdlibApi
+fun box(): String {
+ assertEquals(listOf(Int::class.java, String::class.java), ::S.parameters.map { it.type.javaType })
+ assertEquals(S::class.java, ::S.returnType.javaType)
+
+ assertEquals(listOf(compoundType(Int::class.java, String::class.java)), ::T.parameters.map { it.type.javaType.toString() })
+ assertEquals(T::class.java, ::T.returnType.javaType)
+
+ assertEquals(listOf(compoundType(Int::class.java, String::class.java)), ::U.parameters.map { it.type.javaType.toString() })
+ assertEquals(U::class.java, ::U.returnType.javaType)
+
+
+ assertEquals(listOf(compoundType(Int::class.java, String::class.java), Int::class.java.toString(), compoundType(Int::class.java, String::class.java)), S::foo.parameters.map { it.type.javaType.toString() })
+ assertEquals(S::class.java, S::foo.returnType.javaType)
+
+ assertEquals(listOf(compoundType(Int::class.java, String::class.java), compoundType(Int::class.java, String::class.java)), T::bar.parameters.map { it.type.javaType.toString() })
+ assertEquals(T::class.java, T::bar.returnType.javaType)
+
+ assertEquals(listOf(U::class.java.toString(), compoundType(Int::class.java, String::class.java)), U::bar.parameters.map { it.type.javaType.toString() })
+ assertEquals(U::class.java, U::bar.returnType.javaType)
+
+ return "OK"
+}
diff --git a/compiler/testData/codegen/box/reflection/mapping/types/mfvcPrimaryVal.kt b/compiler/testData/codegen/box/reflection/mapping/types/mfvcPrimaryVal.kt
new file mode 100644
index 0000000..154089b
--- /dev/null
+++ b/compiler/testData/codegen/box/reflection/mapping/types/mfvcPrimaryVal.kt
@@ -0,0 +1,85 @@
+// TARGET_BACKEND: JVM_IR
+// WITH_REFLECT
+// LANGUAGE: +ValueClasses
+
+package test
+
+import kotlin.reflect.KCallable
+import kotlin.reflect.jvm.*
+import kotlin.test.assertEquals
+
+@JvmInline
+value class Z1(val publicX1: UInt, val publicX2: Int) {
+ companion object {
+ val publicX1Ref = Z1::publicX1
+ val publicX2Ref = Z1::publicX2
+ val publicX1BoundRef = Z1(42U, 43)::publicX1
+ val publicX2BoundRef = Z1(42U, 43)::publicX2
+ }
+}
+
+@JvmInline
+value class Z2(internal val internalX1: UInt, internal val internalX2: Int) {
+ companion object {
+ val internalX1Ref = Z2::internalX1
+ val internalX2Ref = Z2::internalX2
+ val internalX1BoundRef = Z2(42U, 43)::internalX1
+ val internalX2BoundRef = Z2(42U, 43)::internalX2
+ }
+}
+
+@JvmInline
+value class Z3(private val privateX1: UInt, private val privateX2: Int) {
+ companion object {
+ val privateX1Ref = Z3::privateX1
+ val privateX2Ref = Z3::privateX2
+ val privateX1BoundRef = Z3(42U, 43)::privateX1
+ val privateX2BoundRef = Z3(42U, 43)::privateX2
+ }
+}
+
+@JvmInline
+value class ZZ(val x1: Z1, val x2: Z1)
+
+fun KCallable<*>.getJavaTypesOfParams() = parameters.map { it.type.javaType }.toString()
+fun KCallable<*>.getJavaTypeOfResult() = returnType.javaType.toString()
+
+fun box(): String {
+ assertEquals("[class test.Z1]", Z1.publicX1Ref.getJavaTypesOfParams())
+ assertEquals("[class test.Z1]", Z1.publicX2Ref.getJavaTypesOfParams())
+ assertEquals("int", Z1.publicX1Ref.getJavaTypeOfResult())
+ assertEquals("int", Z1.publicX2Ref.getJavaTypeOfResult())
+
+ assertEquals("[]", Z1.publicX1BoundRef.getJavaTypesOfParams())
+ assertEquals("[]", Z1.publicX2BoundRef.getJavaTypesOfParams())
+ assertEquals("int", Z1.publicX1BoundRef.getJavaTypeOfResult())
+ assertEquals("int", Z1.publicX2BoundRef.getJavaTypeOfResult())
+
+ assertEquals("[class test.Z2]", Z2.internalX1Ref.getJavaTypesOfParams())
+ assertEquals("[class test.Z2]", Z2.internalX2Ref.getJavaTypesOfParams())
+ assertEquals("int", Z2.internalX1Ref.getJavaTypeOfResult())
+ assertEquals("int", Z2.internalX2Ref.getJavaTypeOfResult())
+
+ assertEquals("[]", Z2.internalX1BoundRef.getJavaTypesOfParams())
+ assertEquals("[]", Z2.internalX2BoundRef.getJavaTypesOfParams())
+ assertEquals("int", Z2.internalX1BoundRef.getJavaTypeOfResult())
+ assertEquals("int", Z2.internalX2BoundRef.getJavaTypeOfResult())
+
+ assertEquals("[class test.Z3]", Z3.privateX1Ref.getJavaTypesOfParams())
+ assertEquals("[class test.Z3]", Z3.privateX2Ref.getJavaTypesOfParams())
+ assertEquals("int", Z3.privateX1Ref.getJavaTypeOfResult())
+ assertEquals("int", Z3.privateX2Ref.getJavaTypeOfResult())
+
+ assertEquals("[]", Z3.privateX1BoundRef.getJavaTypesOfParams())
+ assertEquals("[]", Z3.privateX2BoundRef.getJavaTypesOfParams())
+ assertEquals("int", Z3.privateX1BoundRef.getJavaTypeOfResult())
+ assertEquals("int", Z3.privateX2BoundRef.getJavaTypeOfResult())
+
+
+ assertEquals("[class test.ZZ]", ZZ::x1.getJavaTypesOfParams())
+ assertEquals("[class test.ZZ]", ZZ::x2.getJavaTypesOfParams())
+ assertEquals("class test.Z1", ZZ::x1.getJavaTypeOfResult())
+ assertEquals("class test.Z1", ZZ::x2.getJavaTypeOfResult())
+
+ return "OK"
+}
diff --git a/compiler/testData/codegen/box/reflection/mapping/valueClasses/mfvcPrimaryVal.kt b/compiler/testData/codegen/box/reflection/mapping/valueClasses/mfvcPrimaryVal.kt
new file mode 100644
index 0000000..e903677
--- /dev/null
+++ b/compiler/testData/codegen/box/reflection/mapping/valueClasses/mfvcPrimaryVal.kt
@@ -0,0 +1,90 @@
+// TARGET_BACKEND: JVM_IR
+// WITH_REFLECT
+// LANGUAGE: +ValueClasses
+
+import kotlin.reflect.jvm.*
+import kotlin.test.assertEquals
+import kotlin.test.assertTrue
+
+@JvmInline
+value class Z1(val publicX1: UInt, val publicX2: Int) {
+ companion object {
+ val publicX1Ref = Z1::publicX1
+ val publicX2Ref = Z1::publicX2
+ val publicX1BoundRef = Z1(42U, -42)::publicX1
+ val publicX2BoundRef = Z1(42U, -42)::publicX2
+ }
+}
+
+@JvmInline
+value class Z2(internal val internalX1: UInt, internal val internalX2: Int) {
+ companion object {
+ val internalX1Ref = Z2::internalX1
+ val internalX2Ref = Z2::internalX2
+ val internalX1BoundRef = Z2(42U, -42)::internalX1
+ val internalX2BoundRef = Z2(42U, -42)::internalX2
+ }
+}
+
+@JvmInline
+value class Z3(private val privateX1: UInt, private val privateX2: Int) {
+ companion object {
+ val privateX1Ref = Z3::privateX1
+ val privateX2Ref = Z3::privateX2
+ val privateX1BoundRef = Z3(42U, -42)::privateX1
+ val privateX2BoundRef = Z3(42U, -42)::privateX2
+ }
+}
+@JvmInline
+value class Z1_2(val publicX: Z1) {
+ companion object {
+ val publicXRef = Z1_2::publicX
+ val publicXBoundRef = Z1_2(Z1(42U, -42))::publicX
+ }
+}
+
+@JvmInline
+value class Z2_2(internal val internalX: Z2) {
+ companion object {
+ val internalXRef = Z2_2::internalX
+ val internalXBoundRef = Z2_2(Z2(42U, -42))::internalX
+ }
+}
+
+@JvmInline
+value class Z3_2(private val privateX: Z3) {
+ companion object {
+ val privateXRef = Z3_2::privateX
+ val privateXBoundRef = Z3_2(Z3(42U, -42))::privateX
+ }
+}
+
+fun box(): String {
+ val suffix = "-pVg5ArA"
+ assertEquals("getPublicX1$suffix", Z1.publicX1Ref.javaGetter!!.name)
+ assertEquals("getPublicX2", Z1.publicX2Ref.javaGetter!!.name)
+ assertEquals("getPublicX1$suffix", Z1.publicX1BoundRef.javaGetter!!.name)
+ assertEquals("getPublicX2", Z1.publicX2BoundRef.javaGetter!!.name)
+
+ assertTrue(Z2.internalX1Ref.javaGetter!!.name.startsWith("getInternalX1$suffix\$"), Z2.internalX1Ref.javaGetter!!.name)
+ assertTrue(Z2.internalX2Ref.javaGetter!!.name.startsWith("getInternalX2\$"), Z2.internalX2Ref.javaGetter!!.name)
+ assertTrue(Z2.internalX1BoundRef.javaGetter!!.name.startsWith("getInternalX1$suffix\$"), Z2.internalX1BoundRef.javaGetter!!.name)
+ assertTrue(Z2.internalX2BoundRef.javaGetter!!.name.startsWith("getInternalX2\$"), Z2.internalX2BoundRef.javaGetter!!.name)
+
+ assertEquals(null, Z3.privateX1Ref.javaGetter)
+ assertEquals(null, Z3.privateX2Ref.javaGetter)
+ assertEquals(null, Z3.privateX1BoundRef.javaGetter)
+ assertEquals(null, Z3.privateX2BoundRef.javaGetter)
+
+
+ assertEquals("getPublicX", Z1_2.publicXRef.javaGetter!!.name)
+ assertEquals("getPublicX", Z1_2.publicXBoundRef.javaGetter!!.name)
+
+ assertTrue(Z2_2.internalXRef.javaGetter!!.name.startsWith("getInternalX\$"), Z2_2.internalXRef.javaGetter!!.name)
+ assertTrue(Z2_2.internalXBoundRef.javaGetter!!.name.startsWith("getInternalX\$"), Z2_2.internalXBoundRef.javaGetter!!.name)
+
+ assertEquals("getPrivateX", Z3_2.privateXRef.javaGetter!!.name)
+ assertEquals("getPrivateX", Z3_2.privateXBoundRef.javaGetter!!.name)
+
+ return "OK"
+}
\ No newline at end of file
diff --git a/compiler/testData/codegen/box/reflection/mapping/valueClasses/suspendFunctionWithMfvcInSignature.kt b/compiler/testData/codegen/box/reflection/mapping/valueClasses/suspendFunctionWithMfvcInSignature.kt
new file mode 100644
index 0000000..293076a
--- /dev/null
+++ b/compiler/testData/codegen/box/reflection/mapping/valueClasses/suspendFunctionWithMfvcInSignature.kt
@@ -0,0 +1,49 @@
+// TARGET_BACKEND: JVM_IR
+// WITH_REFLECT
+// LANGUAGE: +ValueClasses
+
+package test
+
+import kotlin.reflect.*
+import kotlin.reflect.jvm.*
+import kotlin.test.assertEquals
+import kotlin.test.assertTrue
+
+@JvmInline
+value class Z(val value1: UInt, val value2: String)
+
+class S {
+ suspend fun consumeZ(z: Z) {}
+ suspend fun produceZ(): Z = Z(0U, "")
+ suspend fun consumeAndProduceZ(z: Z): Z = z
+}
+
+fun box(): String {
+ val members = S::class.members.filterIsInstance<KFunction<*>>().associateBy(KFunction<*>::name)
+
+ members["consumeZ"]!!.let { cz ->
+ val czj = cz.javaMethod!!
+ assertTrue(czj.name.startsWith("consumeZ-"), czj.name)
+ assertEquals("int, java.lang.String, kotlin.coroutines.Continuation", czj.parameterTypes.joinToString { it.name })
+ val czjk = czj.kotlinFunction
+ assertEquals(cz, czjk)
+ }
+
+ members["produceZ"]!!.let { pz ->
+ val pzj = pz.javaMethod!!
+ assertEquals("produceZ", pzj.name)
+ assertEquals("kotlin.coroutines.Continuation", pzj.parameterTypes.joinToString { it.name })
+ val pzjk = pzj!!.kotlinFunction
+ assertEquals(pz, pzjk)
+ }
+
+ members["consumeAndProduceZ"]!!.let { cpz ->
+ val cpzj = cpz.javaMethod!!
+ assertTrue(cpzj.name.startsWith("consumeAndProduceZ-"), cpzj.name)
+ assertEquals("int, java.lang.String, kotlin.coroutines.Continuation", cpzj.parameterTypes.joinToString { it.name })
+ val cpzjk = cpzj!!.kotlinFunction
+ assertEquals(cpz, cpzjk)
+ }
+
+ return "OK"
+}
diff --git a/compiler/testData/codegen/box/reflection/modifiers/mfvc.kt b/compiler/testData/codegen/box/reflection/modifiers/mfvc.kt
new file mode 100644
index 0000000..77aae13
--- /dev/null
+++ b/compiler/testData/codegen/box/reflection/modifiers/mfvc.kt
@@ -0,0 +1,20 @@
+// TARGET_BACKEND: JVM_IR
+// WITH_REFLECT
+// LANGUAGE: +ValueClasses
+// FILE: box.kt
+
+import kotlin.test.assertTrue
+import kotlin.test.assertFalse
+@JvmInline
+value class V(val value: String, val value1: String)
+
+fun box(): String {
+ assertFalse(V::class.isSealed)
+ assertFalse(V::class.isData)
+ assertFalse(V::class.isInner)
+ assertFalse(V::class.isCompanion)
+ assertFalse(V::class.isFun)
+ assertTrue(V::class.isValue)
+
+ return "OK"
+}
diff --git a/compiler/testData/codegen/box/reflection/typeOf/mfvc.kt b/compiler/testData/codegen/box/reflection/typeOf/mfvc.kt
new file mode 100644
index 0000000..e58b179
--- /dev/null
+++ b/compiler/testData/codegen/box/reflection/typeOf/mfvc.kt
@@ -0,0 +1,25 @@
+// TARGET_BACKEND: JVM_IR
+// WITH_REFLECT
+// LANGUAGE: +ValueClasses
+
+package test
+
+import kotlin.reflect.KType
+import kotlin.reflect.typeOf
+import kotlin.test.assertEquals
+
+@JvmInline
+value class Z(val value1: String, val value2: String)
+
+fun check(expected: String, actual: KType) {
+ assertEquals(expected, actual.toString())
+}
+
+fun box(): String {
+ check("test.Z", typeOf<Z>())
+ check("test.Z?", typeOf<Z?>())
+ check("kotlin.Array<test.Z>", typeOf<Array<Z>>())
+ check("kotlin.Array<test.Z?>", typeOf<Array<Z?>>())
+
+ return "OK"
+}
diff --git a/compiler/testData/codegen/box/reflection/typeOf/noReflect/mfvc.kt b/compiler/testData/codegen/box/reflection/typeOf/noReflect/mfvc.kt
new file mode 100644
index 0000000..3fcf991
--- /dev/null
+++ b/compiler/testData/codegen/box/reflection/typeOf/noReflect/mfvc.kt
@@ -0,0 +1,25 @@
+// TARGET_BACKEND: JVM_IR
+// WITH_STDLIB
+// LANGUAGE: +ValueClasses
+
+package test
+
+import kotlin.reflect.KType
+import kotlin.reflect.typeOf
+import kotlin.test.assertEquals
+
+@JvmInline
+value class Z(val value1: String, val value2: String)
+
+fun check(expected: String, actual: KType) {
+ assertEquals(expected + " (Kotlin reflection is not available)", actual.toString())
+}
+
+fun box(): String {
+ check("test.Z", typeOf<Z>())
+ check("test.Z?", typeOf<Z?>())
+ check("kotlin.Array<test.Z>", typeOf<Array<Z>>())
+ check("kotlin.Array<test.Z?>", typeOf<Array<Z?>>())
+
+ return "OK"
+}
diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java
index 800237d..f7b3397 100644
--- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java
+++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java
@@ -41385,6 +41385,16 @@
}
}
}
+
+ @Nested
+ @TestMetadata("compiler/testData/codegen/box/reflection/call/valueClasses")
+ @TestDataPath("$PROJECT_ROOT")
+ public class ValueClasses {
+ @Test
+ public void testAllFilesPresentInValueClasses() throws Exception {
+ KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/reflection/call/valueClasses"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
+ }
+ }
}
@Nested
@@ -42739,6 +42749,16 @@
runTest("compiler/testData/codegen/box/reflection/mapping/types/withNullability.kt");
}
}
+
+ @Nested
+ @TestMetadata("compiler/testData/codegen/box/reflection/mapping/valueClasses")
+ @TestDataPath("$PROJECT_ROOT")
+ public class ValueClasses {
+ @Test
+ public void testAllFilesPresentInValueClasses() throws Exception {
+ KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/reflection/mapping/valueClasses"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
+ }
+ }
}
@Nested
diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java
index 08b2222..59ed627 100644
--- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java
+++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java
@@ -43521,6 +43521,100 @@
}
}
}
+
+ @Nested
+ @TestMetadata("compiler/testData/codegen/box/reflection/call/valueClasses")
+ @TestDataPath("$PROJECT_ROOT")
+ public class ValueClasses {
+ @Test
+ public void testAllFilesPresentInValueClasses() throws Exception {
+ KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/reflection/call/valueClasses"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
+ }
+
+ @Test
+ @TestMetadata("constructorWithMfvcParameters.kt")
+ public void testConstructorWithMfvcParameters() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/call/valueClasses/constructorWithMfvcParameters.kt");
+ }
+
+ @Test
+ @TestMetadata("fieldAccessors.kt")
+ public void testFieldAccessors() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/call/valueClasses/fieldAccessors.kt");
+ }
+
+ @Test
+ @TestMetadata("functionsWithMfvcParameters.kt")
+ public void testFunctionsWithMfvcParameters() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/call/valueClasses/functionsWithMfvcParameters.kt");
+ }
+
+ @Test
+ @TestMetadata("internalPrimaryValOfMfvc.kt")
+ public void testInternalPrimaryValOfMfvc() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/call/valueClasses/internalPrimaryValOfMfvc.kt");
+ }
+
+ @Test
+ @TestMetadata("jvmStaticFieldInObject.kt")
+ public void testJvmStaticFieldInObject() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/call/valueClasses/jvmStaticFieldInObject.kt");
+ }
+
+ @Test
+ @TestMetadata("jvmStaticFunction.kt")
+ public void testJvmStaticFunction() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/call/valueClasses/jvmStaticFunction.kt");
+ }
+
+ @Test
+ @TestMetadata("mfvcConstructor.kt")
+ public void testMfvcConstructor() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/call/valueClasses/mfvcConstructor.kt");
+ }
+
+ @Test
+ @TestMetadata("nonOverridingFunOfMfvc.kt")
+ public void testNonOverridingFunOfMfvc() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/call/valueClasses/nonOverridingFunOfMfvc.kt");
+ }
+
+ @Test
+ @TestMetadata("nonOverridingVarOfMfvc.kt")
+ public void testNonOverridingVarOfMfvc() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/call/valueClasses/nonOverridingVarOfMfvc.kt");
+ }
+
+ @Test
+ @TestMetadata("overridingFunOfMfvc.kt")
+ public void testOverridingFunOfMfvc() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/call/valueClasses/overridingFunOfMfvc.kt");
+ }
+
+ @Test
+ @TestMetadata("overridingVarOfMfvc.kt")
+ public void testOverridingVarOfMfvc() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/call/valueClasses/overridingVarOfMfvc.kt");
+ }
+
+ @Test
+ @TestMetadata("primaryValOfMfvc.kt")
+ public void testPrimaryValOfMfvc() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/call/valueClasses/primaryValOfMfvc.kt");
+ }
+
+ @Test
+ @TestMetadata("properties.kt")
+ public void testProperties() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/call/valueClasses/properties.kt");
+ }
+
+ @Test
+ @TestMetadata("suspendFunction.kt")
+ public void testSuspendFunction() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/call/valueClasses/suspendFunction.kt");
+ }
+ }
}
@Nested
@@ -43641,6 +43735,24 @@
}
@Test
+ @TestMetadata("mfvcDefaultArguments.kt")
+ public void testMfvcDefaultArguments() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/callBy/mfvcDefaultArguments.kt");
+ }
+
+ @Test
+ @TestMetadata("mfvcFunctionsAndConstructors.kt")
+ public void testMfvcFunctionsAndConstructors() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/callBy/mfvcFunctionsAndConstructors.kt");
+ }
+
+ @Test
+ @TestMetadata("mfvcMembers.kt")
+ public void testMfvcMembers() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/callBy/mfvcMembers.kt");
+ }
+
+ @Test
@TestMetadata("nonDefaultParameterOmitted.kt")
public void testNonDefaultParameterOmitted() throws Exception {
runTest("compiler/testData/codegen/box/reflection/callBy/nonDefaultParameterOmitted.kt");
@@ -44485,6 +44597,12 @@
}
@Test
+ @TestMetadata("reflectOnDefaultWithMfvcArgument.kt")
+ public void testReflectOnDefaultWithMfvcArgument() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/lambdaClasses/reflectOnDefaultWithMfvcArgument.kt");
+ }
+
+ @Test
@TestMetadata("reflectOnLambdaInArrayConstructor.kt")
public void testReflectOnLambdaInArrayConstructor() throws Exception {
runTest("compiler/testData/codegen/box/reflection/lambdaClasses/reflectOnLambdaInArrayConstructor.kt");
@@ -44555,6 +44673,12 @@
}
@Test
+ @TestMetadata("constructorWithMfvcParameters.kt")
+ public void testConstructorWithMfvcParameters() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/mapping/constructorWithMfvcParameters.kt");
+ }
+
+ @Test
@TestMetadata("extensionProperty.kt")
public void testExtensionProperty() throws Exception {
runTest("compiler/testData/codegen/box/reflection/mapping/extensionProperty.kt");
@@ -44816,6 +44940,18 @@
}
@Test
+ @TestMetadata("mfvcInSignature.kt")
+ public void testMfvcInSignature() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/mapping/types/mfvcInSignature.kt");
+ }
+
+ @Test
+ @TestMetadata("mfvcPrimaryVal.kt")
+ public void testMfvcPrimaryVal() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/mapping/types/mfvcPrimaryVal.kt");
+ }
+
+ @Test
@TestMetadata("overrideAnyWithPrimitive.kt")
public void testOverrideAnyWithPrimitive() throws Exception {
runTest("compiler/testData/codegen/box/reflection/mapping/types/overrideAnyWithPrimitive.kt");
@@ -44881,6 +45017,28 @@
runTest("compiler/testData/codegen/box/reflection/mapping/types/withNullability.kt");
}
}
+
+ @Nested
+ @TestMetadata("compiler/testData/codegen/box/reflection/mapping/valueClasses")
+ @TestDataPath("$PROJECT_ROOT")
+ public class ValueClasses {
+ @Test
+ public void testAllFilesPresentInValueClasses() throws Exception {
+ KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/reflection/mapping/valueClasses"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
+ }
+
+ @Test
+ @TestMetadata("mfvcPrimaryVal.kt")
+ public void testMfvcPrimaryVal() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/mapping/valueClasses/mfvcPrimaryVal.kt");
+ }
+
+ @Test
+ @TestMetadata("suspendFunctionWithMfvcInSignature.kt")
+ public void testSuspendFunctionWithMfvcInSignature() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/mapping/valueClasses/suspendFunctionWithMfvcInSignature.kt");
+ }
+ }
}
@Nested
@@ -45095,6 +45253,12 @@
}
@Test
+ @TestMetadata("mfvc.kt")
+ public void testMfvc() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/modifiers/mfvc.kt");
+ }
+
+ @Test
@TestMetadata("properties.kt")
public void testProperties() throws Exception {
runTest("compiler/testData/codegen/box/reflection/modifiers/properties.kt");
@@ -45905,6 +46069,12 @@
}
@Test
+ @TestMetadata("mfvc.kt")
+ public void testMfvc() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/typeOf/mfvc.kt");
+ }
+
+ @Test
@TestMetadata("multipleLayers.kt")
public void testMultipleLayers() throws Exception {
runTest("compiler/testData/codegen/box/reflection/typeOf/multipleLayers.kt");
@@ -46014,6 +46184,12 @@
}
@Test
+ @TestMetadata("mfvc.kt")
+ public void testMfvc() throws Exception {
+ runTest("compiler/testData/codegen/box/reflection/typeOf/noReflect/mfvc.kt");
+ }
+
+ @Test
@TestMetadata("mutableCollections_after.kt")
public void testMutableCollections_after() throws Exception {
runTest("compiler/testData/codegen/box/reflection/typeOf/noReflect/mutableCollections_after.kt");
diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java
index 20ebb55..f7ace6d 100644
--- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java
+++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java
@@ -33110,6 +33110,19 @@
}
}
}
+
+ @TestMetadata("compiler/testData/codegen/box/reflection/call/valueClasses")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class ValueClasses extends AbstractLightAnalysisModeTest {
+ private void runTest(String testDataFilePath) throws Exception {
+ KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath);
+ }
+
+ public void testAllFilesPresentInValueClasses() throws Exception {
+ KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/reflection/call/valueClasses"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
+ }
+ }
}
@TestMetadata("compiler/testData/codegen/box/reflection/callBy")
@@ -34313,6 +34326,19 @@
runTest("compiler/testData/codegen/box/reflection/mapping/types/withNullability.kt");
}
}
+
+ @TestMetadata("compiler/testData/codegen/box/reflection/mapping/valueClasses")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class ValueClasses extends AbstractLightAnalysisModeTest {
+ private void runTest(String testDataFilePath) throws Exception {
+ KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath);
+ }
+
+ public void testAllFilesPresentInValueClasses() throws Exception {
+ KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/reflection/mapping/valueClasses"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
+ }
+ }
}
@TestMetadata("compiler/testData/codegen/box/reflection/methodsFromAny")
diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/inlineClassesUtils.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/inlineClassesUtils.kt
index 40ca3fe..ef0baa2 100644
--- a/core/descriptors/src/org/jetbrains/kotlin/resolve/inlineClassesUtils.kt
+++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/inlineClassesUtils.kt
@@ -9,6 +9,7 @@
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.descriptorUtil.inlineClassRepresentation
+import org.jetbrains.kotlin.resolve.descriptorUtil.multiFieldValueClassRepresentation
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeSubstitutor
import org.jetbrains.kotlin.types.TypeUtils
@@ -42,6 +43,8 @@
fun KotlinType.isInlineClassType(): Boolean = constructor.declarationDescriptor?.isInlineClass() ?: false
+fun KotlinType.isMultiFieldValueClassType(): Boolean = constructor.declarationDescriptor?.isMultiFieldValueClass() ?: false
+fun KotlinType.isValueClassType(): Boolean = constructor.declarationDescriptor?.isValueClass() ?: false
fun KotlinType.needsMfvcFlattening(): Boolean =
constructor.declarationDescriptor?.run { isMultiFieldValueClass() && !isNullableType() } == true
@@ -77,6 +80,20 @@
fun CallableDescriptor.isGetterOfUnderlyingPropertyOfInlineClass() =
this is PropertyGetterDescriptor && correspondingProperty.isUnderlyingPropertyOfInlineClass()
+fun CallableDescriptor.isGetterOfUnderlyingPropertyOfMultiFieldValueClass() =
+ this is PropertyGetterDescriptor && correspondingProperty.isUnderlyingPropertyOfMultiFieldValueClass()
+
+fun CallableDescriptor.isGetterOfUnderlyingPropertyOfValueClass() =
+ this is PropertyGetterDescriptor && correspondingProperty.isUnderlyingPropertyOfValueClass()
+
fun VariableDescriptor.isUnderlyingPropertyOfInlineClass(): Boolean =
extensionReceiverParameter == null &&
(containingDeclaration as? ClassDescriptor)?.inlineClassRepresentation?.underlyingPropertyName == this.name
+
+fun VariableDescriptor.isUnderlyingPropertyOfMultiFieldValueClass(): Boolean =
+ extensionReceiverParameter == null &&
+ (containingDeclaration as? ClassDescriptor)?.multiFieldValueClassRepresentation?.containsPropertyWithName(this.name) == true
+
+fun VariableDescriptor.isUnderlyingPropertyOfValueClass(): Boolean =
+ extensionReceiverParameter == null &&
+ (containingDeclaration as? ClassDescriptor)?.valueClassRepresentation?.containsPropertyWithName(this.name) == true
diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KCallableImpl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KCallableImpl.kt
index 9763c6f..a6162dc 100644
--- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KCallableImpl.kt
+++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KCallableImpl.kt
@@ -8,13 +8,14 @@
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor
+import org.jetbrains.kotlin.types.asSimpleType
import java.lang.reflect.ParameterizedType
import java.lang.reflect.Type
import java.lang.reflect.WildcardType
-import java.util.*
import kotlin.coroutines.Continuation
import kotlin.reflect.*
import kotlin.reflect.jvm.internal.calls.Caller
+import kotlin.reflect.jvm.internal.calls.getMfvcUnboxMethods
import kotlin.reflect.jvm.javaType
import kotlin.reflect.jvm.jvmErasure
import java.lang.reflect.Array as ReflectArray
@@ -113,7 +114,9 @@
private val _absentArguments = ReflectProperties.lazySoft {
val parameterSize = parameters.size + (if (isSuspend) 1 else 0)
- val maskSize = (parameters.size + Integer.SIZE - 1) / Integer.SIZE
+ val flattenedParametersSize =
+ if (parametersNeedMFVCFlattening.value) parameters.sumOf { getParameterTypeSize(it) } else parameters.size
+ val maskSize = (flattenedParametersSize + Integer.SIZE - 1) / Integer.SIZE
// Array containing the actual function arguments, masks, and +1 for DefaultConstructorMarker or MethodHandle.
val arguments = arrayOfNulls<Any?>(parameterSize + maskSize + 1)
@@ -161,14 +164,23 @@
var valueParameterIndex = 0
var anyOptional = false
+ val hasMfvcParameters = parametersNeedMFVCFlattening.value
for (parameter in parameters) {
+ val parameterTypeSize = if (hasMfvcParameters) getParameterTypeSize(parameter) else 1
when {
args.containsKey(parameter) -> {
arguments[parameter.index] = args[parameter]
}
parameter.isOptional -> {
- val maskIndex = parameterSize + (valueParameterIndex / Integer.SIZE)
- arguments[maskIndex] = (arguments[maskIndex] as Int) or (1 shl (valueParameterIndex % Integer.SIZE))
+ if (hasMfvcParameters) {
+ for (valueSubParameterIndex in valueParameterIndex until (valueParameterIndex + parameterTypeSize)) {
+ val maskIndex = parameterSize + (valueSubParameterIndex / Integer.SIZE)
+ arguments[maskIndex] = (arguments[maskIndex] as Int) or (1 shl (valueSubParameterIndex % Integer.SIZE))
+ }
+ } else {
+ val maskIndex = parameterSize + (valueParameterIndex / Integer.SIZE)
+ arguments[maskIndex] = (arguments[maskIndex] as Int) or (1 shl (valueParameterIndex % Integer.SIZE))
+ }
anyOptional = true
}
parameter.isVararg -> {}
@@ -178,7 +190,7 @@
}
if (parameter.kind == KParameter.Kind.VALUE) {
- valueParameterIndex++
+ valueParameterIndex += parameterTypeSize
}
}
@@ -197,6 +209,20 @@
}
}
+ private val parametersNeedMFVCFlattening = lazy(LazyThreadSafetyMode.PUBLICATION) {
+ parameters.any { it.type.needsMultiFieldValueClassFlattening }
+ }
+
+ private fun getParameterTypeSize(parameter: KParameter): Int {
+ require(parametersNeedMFVCFlattening.value) { "Check if parametersNeedMFVCFlattening is true before" }
+ return if (parameter.type.needsMultiFieldValueClassFlattening) {
+ val type = (parameter.type as KTypeImpl).type.asSimpleType()
+ getMfvcUnboxMethods(type)!!.size
+ } else {
+ 1
+ }
+ }
+
private fun callAnnotationConstructor(args: Map<KParameter, Any?>): R {
val arguments = parameters.map { parameter ->
when {
diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KDeclarationContainerImpl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KDeclarationContainerImpl.kt
index d4e7739..7064a14 100644
--- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KDeclarationContainerImpl.kt
+++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KDeclarationContainerImpl.kt
@@ -24,10 +24,12 @@
import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.renderer.DescriptorRenderer
+import org.jetbrains.kotlin.resolve.isMultiFieldValueClass
import org.jetbrains.kotlin.resolve.scopes.MemberScope
import java.lang.reflect.Constructor
import java.lang.reflect.Method
import kotlin.jvm.internal.ClassBasedDeclarationContainer
+import kotlin.reflect.jvm.internal.calls.toJvmDescriptor
internal abstract class KDeclarationContainerImpl : ClassBasedDeclarationContainer {
abstract inner class Data {
@@ -119,9 +121,25 @@
}
fun findFunctionDescriptor(name: String, signature: String): FunctionDescriptor {
- val members = if (name == "<init>") constructorDescriptors.toList() else getFunctions(Name.identifier(name))
- val functions = members.filter { descriptor ->
- RuntimeTypeMapper.mapSignature(descriptor).asString() == signature
+ val members: Collection<FunctionDescriptor>
+ val functions: List<FunctionDescriptor>
+ if (name == "<init>") {
+ members = constructorDescriptors.toList()
+ functions = members.filter { descriptor ->
+ val descriptorSignature = if (descriptor.isPrimary && descriptor.containingDeclaration.isMultiFieldValueClass()) {
+ val initial = RuntimeTypeMapper.mapSignature(descriptor).asString()
+ require(initial.startsWith("constructor-impl") && initial.endsWith(")V")) {
+ "Invalid signature of $descriptor: $initial"
+ }
+ initial.removeSuffix("V") + descriptor.containingDeclaration.toJvmDescriptor()
+ } else {
+ RuntimeTypeMapper.mapSignature(descriptor).asString()
+ }
+ descriptorSignature == signature
+ }
+ } else {
+ members = getFunctions(Name.identifier(name))
+ functions = members.filter { descriptor -> RuntimeTypeMapper.mapSignature(descriptor).asString() == signature }
}
if (functions.size != 1) {
diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KFunctionImpl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KFunctionImpl.kt
index dce795c..0d2ee46 100644
--- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KFunctionImpl.kt
+++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KFunctionImpl.kt
@@ -17,8 +17,10 @@
package kotlin.reflect.jvm.internal
import org.jetbrains.kotlin.descriptors.ClassDescriptor
+import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
-import org.jetbrains.kotlin.resolve.jvm.shouldHideConstructorDueToInlineClassTypeValueParameters
+import org.jetbrains.kotlin.resolve.isMultiFieldValueClass
+import org.jetbrains.kotlin.resolve.jvm.shouldHideConstructorDueToValueClassTypeValueParameters
import java.lang.reflect.Constructor
import java.lang.reflect.Member
import java.lang.reflect.Method
@@ -66,7 +68,14 @@
return@caller AnnotationConstructorCaller(container.jClass, parameters.map { it.name!! }, POSITIONAL_CALL, KOTLIN)
container.findConstructorBySignature(jvmSignature.constructorDesc)
}
- is KotlinFunction -> container.findMethodBySignature(jvmSignature.methodName, jvmSignature.methodDesc)
+ is KotlinFunction -> {
+ if (descriptor.let { it.containingDeclaration.isMultiFieldValueClass() && it is ConstructorDescriptor && it.isPrimary }) {
+ return@caller ValueClassAwareCaller.MultiFieldValueClassPrimaryConstructorCaller(
+ descriptor, container, jvmSignature.methodDesc, descriptor.valueParameters
+ )
+ }
+ container.findMethodBySignature(jvmSignature.methodName, jvmSignature.methodDesc)
+ }
is JavaMethod -> jvmSignature.method
is JavaConstructor -> jvmSignature.constructor
is FakeJavaAnnotationConstructor -> {
@@ -87,13 +96,16 @@
createStaticMethodCaller(member)
}
else -> throw KotlinReflectionInternalError("Could not compute caller for function: $descriptor (member = $member)")
- }.createInlineClassAwareCallerIfNeeded(descriptor)
+ }.createValueClassAwareCallerIfNeeded(descriptor)
}
override val defaultCaller: Caller<*>? by lazy(PUBLICATION) defaultCaller@{
val jvmSignature = RuntimeTypeMapper.mapSignature(descriptor)
val member: Member? = when (jvmSignature) {
is KotlinFunction -> {
+ if (descriptor.let { it.containingDeclaration.isMultiFieldValueClass() && it is ConstructorDescriptor && it.isPrimary }) {
+ throw KotlinReflectionInternalError("${descriptor.containingDeclaration} cannot have default arguments")
+ }
container.findDefaultMethod(jvmSignature.methodName, jvmSignature.methodDesc, !Modifier.isStatic(caller.member!!.modifiers))
}
is KotlinConstructor -> {
@@ -126,7 +138,7 @@
createStaticMethodCaller(member)
}
else -> null
- }?.createInlineClassAwareCallerIfNeeded(descriptor, isDefault = true)
+ }?.createValueClassAwareCallerIfNeeded(descriptor, isDefault = true)
}
private val boundReceiver
@@ -144,7 +156,7 @@
private fun createConstructorCaller(
member: Constructor<*>, descriptor: FunctionDescriptor, isDefault: Boolean
): CallerImpl<Constructor<*>> {
- return if (!isDefault && shouldHideConstructorDueToInlineClassTypeValueParameters(descriptor)) {
+ return if (!isDefault && shouldHideConstructorDueToValueClassTypeValueParameters(descriptor)) {
if (isBound)
CallerImpl.AccessorForHiddenBoundConstructor(member, boundReceiver)
else
diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KParameterImpl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KParameterImpl.kt
index 7906172..b6319c3 100644
--- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KParameterImpl.kt
+++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KParameterImpl.kt
@@ -18,8 +18,10 @@
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.resolve.descriptorUtil.declaresOrInheritsDefaultValue
+import java.lang.reflect.Type
import kotlin.reflect.KParameter
import kotlin.reflect.KType
+import kotlin.reflect.jvm.internal.calls.ValueClassAwareCaller
internal class KParameterImpl(
val callable: KCallableImpl<*>,
@@ -39,6 +41,27 @@
return if (name.isSpecial) null else name.asString()
}
+
+ private fun compoundType(vararg types: Type): Type = when (types.size) {
+ 0 -> throw KotlinReflectionNotSupportedError("Expected at least 1 type for compound type")
+ 1 -> types.single()
+ else -> CompoundTypeImpl(types)
+ }
+
+ private class CompoundTypeImpl(val types: Array<out Type>) : Type {
+ private val hashCode = types.contentHashCode()
+ override fun getTypeName(): String {
+ return types.joinToString(", ", "[", "]")
+ }
+
+ override fun equals(other: Any?): Boolean =
+ other is CompoundTypeImpl && this.types contentEquals other.types
+
+ override fun hashCode(): Int = hashCode
+
+ override fun toString(): String = typeName
+ }
+
override val type: KType
get() = KTypeImpl(descriptor.type) {
val descriptor = descriptor
@@ -53,7 +76,16 @@
(callable.descriptor.containingDeclaration as ClassDescriptor).toJavaClass()
?: throw KotlinReflectionInternalError("Cannot determine receiver Java type of inherited declaration: $descriptor")
} else {
- callable.caller.parameterTypes[index]
+ when (val caller = callable.caller) {
+ is ValueClassAwareCaller -> {
+ val slice = caller.getRealSlicesOfParameters(index)
+ val parameterTypes = caller.parameterTypes.slice(slice)
+ compoundType(*parameterTypes.toTypedArray())
+ }
+ is ValueClassAwareCaller.MultiFieldValueClassPrimaryConstructorCaller ->
+ compoundType(*caller.originalParametersGroups[index].toTypedArray())
+ else -> caller.parameterTypes[index]
+ }
}
}
diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KPropertyImpl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KPropertyImpl.kt
index eeaa98d..fa9596a 100644
--- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KPropertyImpl.kt
+++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KPropertyImpl.kt
@@ -271,8 +271,9 @@
if (property.descriptor.isUnderlyingPropertyOfInlineClass() &&
property.descriptor.visibility == DescriptorVisibilities.INTERNAL
) {
- val unboxMethod = property.descriptor.containingDeclaration.toInlineClass()?.getUnboxMethod(property.descriptor)
- ?: throw KotlinReflectionInternalError("Underlying property of inline class $property should have a field")
+ val unboxMethod =
+ property.descriptor.containingDeclaration.toInlineClass()?.getInlineClassUnboxMethod(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 {
@@ -316,7 +317,7 @@
return if (isBound) CallerImpl.Method.BoundInstance(accessor, boundReceiver)
else CallerImpl.Method.Instance(accessor)
}
- }.createInlineClassAwareCallerIfNeeded(descriptor)
+ }.createValueClassAwareCallerIfNeeded(descriptor)
}
private fun PropertyDescriptor.isJvmFieldPropertyInCompanionObject(): Boolean {
diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/RuntimeTypeMapper.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/RuntimeTypeMapper.kt
index 5d64815..8d117df 100644
--- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/RuntimeTypeMapper.kt
+++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/RuntimeTypeMapper.kt
@@ -44,6 +44,7 @@
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.descriptorUtil.propertyIfAccessor
import org.jetbrains.kotlin.resolve.isInlineClass
+import org.jetbrains.kotlin.resolve.isMultiFieldValueClass
import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor
@@ -51,6 +52,7 @@
import java.lang.reflect.Constructor
import java.lang.reflect.Field
import java.lang.reflect.Method
+import kotlin.reflect.jvm.internal.calls.toJvmDescriptor
internal sealed class JvmFunctionSignature {
abstract fun asString(): String
@@ -174,10 +176,27 @@
}
if (proto is ProtoBuf.Constructor) {
JvmProtoBufUtil.getJvmConstructorSignature(proto, function.nameResolver, function.typeTable)?.let { signature ->
- return if (possiblySubstitutedFunction.containingDeclaration.isInlineClass())
- JvmFunctionSignature.KotlinFunction(signature)
- else
- JvmFunctionSignature.KotlinConstructor(signature)
+ return when {
+ possiblySubstitutedFunction.containingDeclaration.isInlineClass() ->
+ JvmFunctionSignature.KotlinFunction(signature)
+ possiblySubstitutedFunction.containingDeclaration.isMultiFieldValueClass() -> {
+ val realSignature = if ((possiblySubstitutedFunction as ConstructorDescriptor).isPrimary) {
+ require(signature.name == "constructor-impl" && signature.desc.endsWith(")V")) { "Invalid signature: $signature" }
+ signature
+ } else {
+ require(signature.name == "constructor-impl") { "Invalid signature: $signature" }
+ val constructedClass = possiblySubstitutedFunction.constructedClass.toJvmDescriptor()
+ if (signature.desc.endsWith(")V")) {
+ signature.copy(desc = signature.desc.removeSuffix("V") + constructedClass)
+ } else {
+ require(signature.desc.endsWith(constructedClass)) { "Invalid signature: $signature" }
+ signature
+ }
+ }
+ JvmFunctionSignature.KotlinFunction(realSignature)
+ }
+ else -> JvmFunctionSignature.KotlinConstructor(signature)
+ }
}
}
return mapJvmFunctionSignature(function)
diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/calls/CallerImpl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/calls/CallerImpl.kt
index 6665636..7b52532 100644
--- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/calls/CallerImpl.kt
+++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/calls/CallerImpl.kt
@@ -122,7 +122,7 @@
}
}
- class BoundStatic(method: ReflectMethod, private val boundReceiver: Any?) : BoundCaller, Method(
+ class BoundStatic(method: ReflectMethod, internal val boundReceiver: Any?) : BoundCaller, Method(
method, requiresInstance = false, parameterTypes = method.genericParameterTypes.dropFirst()
) {
override fun call(args: Array<*>): Any? {
@@ -131,6 +131,21 @@
}
}
+ class BoundStaticMultiFieldValueClass(
+ method: ReflectMethod, internal val boundReceiverComponents: Array<Any?>
+ ) : BoundCaller, Method(
+ method = method,
+ requiresInstance = false,
+ parameterTypes = method.genericParameterTypes.drop(boundReceiverComponents.size).toTypedArray()
+ ) {
+ override fun call(args: Array<*>): Any? {
+ checkArguments(args)
+ return callMethod(null, arrayOf(*boundReceiverComponents, *args))
+ }
+
+ val receiverComponentsCount: Int get() = boundReceiverComponents.size
+ }
+
class BoundInstance(method: ReflectMethod, private val boundReceiver: Any?) : BoundCaller,
Method(method, requiresInstance = false) {
override fun call(args: Array<*>): Any? {
diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/calls/ValueClassAwareCaller.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/calls/ValueClassAwareCaller.kt
index dd3540a..feacd27 100644
--- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/calls/ValueClassAwareCaller.kt
+++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/calls/ValueClassAwareCaller.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
@@ -7,29 +7,50 @@
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.*
+import org.jetbrains.kotlin.descriptors.runtime.structure.desc
import org.jetbrains.kotlin.load.java.JvmAbi
+import org.jetbrains.kotlin.metadata.jvm.deserialization.ClassMapperLite
import org.jetbrains.kotlin.resolve.*
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
+import org.jetbrains.kotlin.resolve.descriptorUtil.multiFieldValueClassRepresentation
import org.jetbrains.kotlin.types.KotlinType
+import org.jetbrains.kotlin.types.SimpleType
import org.jetbrains.kotlin.types.TypeUtils
+import org.jetbrains.kotlin.types.asSimpleType
import java.lang.reflect.Member
import java.lang.reflect.Method
import java.lang.reflect.Type
+import kotlin.reflect.jvm.internal.KDeclarationContainerImpl
import kotlin.reflect.jvm.internal.KotlinReflectionInternalError
import kotlin.reflect.jvm.internal.defaultPrimitiveValue
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.
+ * A caller that is used whenever the declaration has value classes in its parameter types or inline class in return type.
+ * Each argument of an value 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 ValueClassAwareCaller<out M : Member?>(
descriptor: CallableMemberDescriptor,
- private val caller: Caller<M>,
+ oldCaller: Caller<M>,
private val isDefault: Boolean
) : Caller<M> {
- override val member: M
- get() = caller.member
+
+ private val caller: Caller<M> = if (oldCaller is CallerImpl.Method.BoundStatic) {
+ val receiverType = (descriptor.extensionReceiverParameter ?: descriptor.dispatchReceiverParameter)?.type
+ if (receiverType != null && receiverType.needsMfvcFlattening()) {
+ val unboxMethods = getMfvcUnboxMethods(receiverType.asSimpleType())!!
+ val boundReceiverComponents = unboxMethods.map { it.invoke(oldCaller.boundReceiver) }.toTypedArray()
+ @Suppress("UNCHECKED_CAST")
+ CallerImpl.Method.BoundStaticMultiFieldValueClass(oldCaller.member, boundReceiverComponents) as Caller<M>
+ } else {
+ oldCaller
+ }
+ } else {
+ oldCaller
+ }
+
+ override val member: M = caller.member
+
override val returnType: Type
get() = caller.returnType
@@ -37,24 +58,18 @@
override val parameterTypes: List<Type>
get() = caller.parameterTypes
- private class BoxUnboxData(val argumentRange: IntRange, val unbox: Array<Method?>, val box: Method?) {
- operator fun component1(): IntRange = argumentRange
- operator fun component2(): Array<Method?> = unbox
- operator fun component3(): Method? = box
- }
+ private class BoxUnboxData(val argumentRange: IntRange, val unboxParameters: Array<List<Method>?>, val box: Method?)
private val data: BoxUnboxData = run {
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.
+ if (descriptor.isGetterOfUnderlyingPropertyOfValueClass()) {
+ // Getter of the underlying val of a value class is always called on a boxed receiver,
+ // no argument unboxing is required.
return@run BoxUnboxData(IntRange.EMPTY, emptyArray(), box)
}
val shift = when {
- caller is CallerImpl.Method.BoundStatic -> {
+ caller is CallerImpl.Method.BoundStatic || caller is CallerImpl.Method.BoundStaticMultiFieldValueClass -> {
// Bound reference to a static method is only possible for a top level extension function/property,
// and in that case the number of expected arguments is one less than usual, hence -1
-1
@@ -64,9 +79,9 @@
if (caller is BoundCaller) -1 else 0
descriptor.dispatchReceiverParameter != null && caller !is BoundCaller -> {
- // If we have an unbound reference to the inline class member,
+ // If we have an unbound reference to the value class member,
// its receiver (which is passed as argument 0) should also be unboxed.
- if (descriptor.containingDeclaration.isInlineClass())
+ if (descriptor.containingDeclaration.isValueClass())
0
else
1
@@ -75,117 +90,229 @@
else -> 0
}
- val kotlinParameterTypes: List<KotlinType> = ArrayList<KotlinType>().also { kotlinParameterTypes ->
- val extensionReceiverType = descriptor.extensionReceiverParameter?.type
- if (extensionReceiverType != null) {
- kotlinParameterTypes.add(extensionReceiverType)
- } 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.isInlineClass()) {
- kotlinParameterTypes.add(containingDeclaration.defaultType)
- }
- }
+ val flattenedShift = if (caller is CallerImpl.Method.BoundStaticMultiFieldValueClass) -caller.receiverComponentsCount else shift
- descriptor.valueParameters.mapTo(kotlinParameterTypes, ValueParameterDescriptor::getType)
- }
+ val kotlinParameterTypes: List<KotlinType> = makeKotlinParameterTypes(descriptor) { isValueClass() }
+
+ fun typeSize(type: KotlinType): Int = getMfvcUnboxMethods(type.asSimpleType())?.size ?: 1
// If the default argument is set,
- // (kotlinParameterTypes.size + Integer.SIZE - 1) / Integer.SIZE masks and one marker are added to the end of the argument.
- val extraArgumentsTail = (if (isDefault) ((kotlinParameterTypes.size + Integer.SIZE - 1) / Integer.SIZE) + 1 else 0) +
- (if (descriptor is FunctionDescriptor && descriptor.isSuspend) 1 else 0)
- val expectedArgsSize = kotlinParameterTypes.size + shift + extraArgumentsTail
- if (arity != expectedArgsSize) {
- throw KotlinReflectionInternalError(
- "Inconsistent number of parameters in the descriptor and Java reflection object: $arity != $expectedArgsSize\n" +
- "Calling: $descriptor\n" +
- "Parameter types: ${this.parameterTypes})\n" +
- "Default: $isDefault"
- )
- }
+ // (kotlinParameterTypes.size + Int.SIZE_BITS - 1) / Int.SIZE_BITS masks and one marker are added to the end of the argument.
+ val extraArgumentsTail =
+ (if (isDefault) ((kotlinParameterTypes.sumOf(::typeSize) + Int.SIZE_BITS - 1) / Int.SIZE_BITS) + 1 else 0) +
+ (if (descriptor is FunctionDescriptor && descriptor.isSuspend) 1 else 0)
+ val expectedArgsSize = kotlinParameterTypes.sumOf(::typeSize) + flattenedShift + extraArgumentsTail
+ checkParametersSize(expectedArgsSize, descriptor, isDefault)
// maxOf is needed because in case of a bound top level extension, shift can be -1 (see above). But in that case, we need not unbox
// the extension receiver argument, since it has already been unboxed at compile time and generated into the reference
val argumentRange = maxOf(shift, 0) until (kotlinParameterTypes.size + shift)
val unbox = Array(expectedArgsSize) { i ->
- if (i in argumentRange) {
- kotlinParameterTypes[i - shift].toInlineClass()?.getUnboxMethod(descriptor)
- } else null
+ if (i in argumentRange)
+ getValueClassUnboxMethods(kotlinParameterTypes[i - shift].asSimpleType(), descriptor)
+ else null
}
BoxUnboxData(argumentRange, unbox, box)
}
+ private val slices = buildList {
+ var currentOffset = when (caller) {
+ is CallerImpl.Method.BoundStaticMultiFieldValueClass -> caller.boundReceiverComponents.size
+ is CallerImpl.Method.BoundStatic -> 1
+ else -> 0
+ }
+ if (currentOffset > 0) {
+ add(0 until currentOffset)
+ }
+ for (parameterUnboxMethods in data.unboxParameters) {
+ val length = parameterUnboxMethods?.size ?: 1
+ add(currentOffset until (currentOffset + length))
+ currentOffset += length
+ }
+ }.toTypedArray()
+
+ fun getRealSlicesOfParameters(index: Int): IntRange = when {
+ index in slices.indices -> slices[index]
+ slices.isEmpty() -> index..index
+ else -> {
+ val start = (index - slices.size) + (slices.last().last + 1)
+ start..start
+ }
+ }
+
+ private val hasMfvcParameters = data.argumentRange.any { (data.unboxParameters[it] ?: return@any false).size > 1 }
+
override fun call(args: Array<*>): Any? {
- val (range, unbox, box) = data
+ val range = data.argumentRange
+ val unbox = data.unboxParameters
+ val box = data.box
- @Suppress("UNCHECKED_CAST")
- val unboxed = Array(args.size) { index ->
- val arg = args[index]
-
- if (index in range) {
- // Note that arg may be null in case we're calling a $default method and it's an optional parameter of an inline class type
- val method = unbox[index]
-
- if (method != null) {
- if (arg != null) {
- method.invoke(arg)
+ val unboxedArguments = when {
+ range.isEmpty() -> args
+ hasMfvcParameters -> buildList(args.size) {
+ for (index in 0 until range.first) {
+ add(args[index])
+ }
+ for (index in range) {
+ val methods = unbox[index]
+ val arg = args[index]
+ // Note that arg may be null in case we're calling a $default method, and it's an optional parameter of a value class type
+ if (methods != null) {
+ methods.mapTo(this) { if (arg != null) it.invoke(arg) else defaultPrimitiveValue(it.returnType) }
} else {
- defaultPrimitiveValue(method.returnType)
+ add(arg)
+ }
+ }
+ for (index in (range.last + 1)..args.lastIndex) {
+ add(args[index])
+ }
+ }.toTypedArray()
+ else -> Array(args.size) { index ->
+ if (index in range) {
+ val method = unbox[index]?.single()
+ val arg = args[index]
+ // Note that arg may be null in case we're calling a $default method, and it's an optional parameter of a inline class type
+ when {
+ method == null -> arg
+ arg != null -> method.invoke(arg)
+ else -> defaultPrimitiveValue(method.returnType)
}
} else {
- arg
+ args[index]
}
- } else {
- arg
}
}
- val result = caller.call(unboxed)
+ val result = caller.call(unboxedArguments)
+ // box is not null only for inline classes
return box?.invoke(null, result) ?: result
}
+
+ class MultiFieldValueClassPrimaryConstructorCaller(
+ descriptor: FunctionDescriptor,
+ container: KDeclarationContainerImpl,
+ constructorDesc: String,
+ originalParameters: List<ParameterDescriptor>
+ ) : Caller<Nothing?> {
+ private val constructorImpl = container.findMethodBySignature("constructor-impl", constructorDesc)!!
+ private val boxMethod = container.findMethodBySignature("box-impl", constructorDesc.removeSuffix("V") + container.jClass.desc)!!
+ private val parameterUnboxMethods: List<List<Method>?> = originalParameters.map { parameter ->
+ getValueClassUnboxMethods(parameter.type.asSimpleType(), descriptor)
+ }
+ override val member: Nothing?
+ get() = null
+ override val returnType: Type
+ get() = boxMethod.returnType
+
+ val originalParametersGroups: List<List<Class<*>>> = originalParameters.mapIndexed { index, it ->
+ val classDescriptor = it.type.constructor.declarationDescriptor as ClassDescriptor
+ parameterUnboxMethods[index]?.map { it.returnType } ?: listOf(classDescriptor.toJavaClass()!!)
+ }
+
+ override val parameterTypes: List<Type> = originalParametersGroups.flatten()
+
+ override fun call(args: Array<*>): Any? {
+ val newArgs = (args zip parameterUnboxMethods)
+ .flatMap { (arg, unboxMethods) -> unboxMethods?.map { it.invoke(arg) } ?: listOf(arg) }.toTypedArray()
+ constructorImpl.invoke(null, *newArgs)
+ return boxMethod.invoke(null, *newArgs)
+ }
+ }
}
-internal fun <M : Member?> Caller<M>.createInlineClassAwareCallerIfNeeded(
+internal fun ClassifierDescriptor.toJvmDescriptor(): String = ClassMapperLite.mapClass(classId!!.asString())
+
+
+private fun getValueClassUnboxMethods(type: SimpleType, descriptor: CallableMemberDescriptor): List<Method>? =
+ getMfvcUnboxMethods(type) ?: type.toInlineClass()?.getInlineClassUnboxMethod(descriptor)?.let(::listOf)
+
+internal fun getMfvcUnboxMethods(type: SimpleType): List<Method>? {
+ fun getUnboxMethodNameSuffixes(type: SimpleType): List<String>? =
+ if (type.needsMfvcFlattening()) (type.constructor.declarationDescriptor as ClassDescriptor)
+ .multiFieldValueClassRepresentation!!.underlyingPropertyNamesToTypes.flatMap { (name, innerType) ->
+ getUnboxMethodNameSuffixes(innerType)?.map { "${name.identifier}-${it}" } ?: listOf(name.identifier)
+ }
+ else null
+
+ val unboxMethodsNames = getUnboxMethodNameSuffixes(type.asSimpleType())?.map { "unbox-impl-$it" } ?: return null
+ val javaClass = (type.constructor.declarationDescriptor as ClassDescriptor).toJavaClass()!!
+ return unboxMethodsNames.map { javaClass.getDeclaredMethod(it) }
+}
+
+private fun Caller<*>.checkParametersSize(
+ expectedArgsSize: Int,
+ descriptor: CallableMemberDescriptor,
+ isDefault: Boolean,
+) {
+ if (arity != expectedArgsSize) {
+ throw KotlinReflectionInternalError(
+ "Inconsistent number of parameters in the descriptor and Java reflection object: $arity != $expectedArgsSize\n" +
+ "Calling: $descriptor\n" +
+ "Parameter types: ${this.parameterTypes})\n" +
+ "Default: $isDefault"
+ )
+ }
+}
+
+private fun makeKotlinParameterTypes(
+ descriptor: CallableMemberDescriptor, isSpecificClass: ClassDescriptor.() -> Boolean
+): List<KotlinType> = ArrayList<KotlinType>().also { kotlinParameterTypes ->
+ val extensionReceiverType = descriptor.extensionReceiverParameter?.type
+ if (extensionReceiverType != null) {
+ kotlinParameterTypes.add(extensionReceiverType)
+ } 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.isSpecificClass()) {
+ kotlinParameterTypes.add(containingDeclaration.defaultType)
+ }
+ }
+
+ descriptor.valueParameters.mapTo(kotlinParameterTypes, ValueParameterDescriptor::getType)
+}
+
+internal fun <M : Member?> Caller<M>.createValueClassAwareCallerIfNeeded(
descriptor: CallableMemberDescriptor,
isDefault: Boolean = false
): Caller<M> {
- val needsInlineAwareCaller: Boolean =
- descriptor.isGetterOfUnderlyingPropertyOfInlineClass() ||
- descriptor.valueParameters.any { it.type.isInlineClassType() } ||
+ val needsValueClassAwareCaller: Boolean =
+ descriptor.isGetterOfUnderlyingPropertyOfValueClass() ||
+ descriptor.contextReceiverParameters.any { it.type.isValueClassType() } ||
+ descriptor.valueParameters.any { it.type.isValueClassType() } ||
descriptor.returnType?.isInlineClassType() == true ||
- this !is BoundCaller && descriptor.hasInlineClassReceiver()
+ descriptor.hasValueClassReceiver()
- return if (needsInlineAwareCaller) InlineClassAwareCaller(descriptor, this, isDefault) else this
+ return if (needsValueClassAwareCaller) ValueClassAwareCaller(descriptor, this, isDefault) else this
}
-private fun CallableMemberDescriptor.hasInlineClassReceiver() =
- expectedReceiverType?.isInlineClassType() == true
+private fun CallableMemberDescriptor.hasValueClassReceiver() =
+ expectedReceiverType?.isValueClassType() == true
-internal fun Class<*>.getUnboxMethod(descriptor: CallableMemberDescriptor): Method =
+internal fun Class<*>.getInlineClassUnboxMethod(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 Class<*>.getBoxMethod(descriptor: CallableMemberDescriptor): Method =
+private fun Class<*>.getBoxMethod(descriptor: CallableMemberDescriptor): Method =
try {
- getDeclaredMethod("box" + JvmAbi.IMPL_SUFFIX_FOR_INLINE_CLASS_MEMBERS, getUnboxMethod(descriptor).returnType)
+ getDeclaredMethod("box" + JvmAbi.IMPL_SUFFIX_FOR_INLINE_CLASS_MEMBERS, getInlineClassUnboxMethod(descriptor).returnType)
} catch (e: NoSuchMethodException) {
throw KotlinReflectionInternalError("No box method found in inline class: $this (calling $descriptor)")
}
-internal fun KotlinType.toInlineClass(): Class<*>? {
+private fun KotlinType.toInlineClass(): Class<*>? {
// See computeExpandedTypeForInlineClass.
- // TODO: add tests on type parameters with inline class bounds.
- // TODO: add tests on usages of inline classes in Java.
+ // TODO: add tests on type parameters with value class bounds.
+ // TODO: add tests on usages of value classes in Java.
val klass = constructor.declarationDescriptor.toInlineClass() ?: return null
if (!TypeUtils.isNullableType(this)) return klass
@@ -217,7 +344,7 @@
if (descriptor is PropertyDescriptor && descriptor.isUnderlyingPropertyOfInlineClass()) return this
val expectedReceiverType = descriptor.expectedReceiverType
- val unboxMethod = expectedReceiverType?.toInlineClass()?.getUnboxMethod(descriptor) ?: return this
+ val unboxMethod = expectedReceiverType?.toInlineClass()?.getInlineClassUnboxMethod(descriptor) ?: return this
return unboxMethod.invoke(this)
}
diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/util.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/util.kt
index e09ed34..b848204 100644
--- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/util.kt
+++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/util.kt
@@ -44,6 +44,7 @@
import org.jetbrains.kotlin.resolve.descriptorUtil.annotationClass
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
import org.jetbrains.kotlin.resolve.isInlineClassType
+import org.jetbrains.kotlin.resolve.needsMfvcFlattening
import org.jetbrains.kotlin.serialization.deserialization.DeserializationContext
import org.jetbrains.kotlin.serialization.deserialization.MemberDeserializer
import java.lang.reflect.Field
@@ -268,6 +269,8 @@
internal val KType.isInlineClassType: Boolean
get() = (this as? KTypeImpl)?.type?.isInlineClassType() == true
+internal val KType.needsMultiFieldValueClassFlattening: Boolean
+ get() = (this as? KTypeImpl)?.type?.needsMfvcFlattening() == true
internal fun defaultPrimitiveValue(type: Type): Any? =
if (type is Class<*> && type.isPrimitive) {
diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/JsCodegenBoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/JsCodegenBoxTestGenerated.java
index 037751e..c0d77ef 100644
--- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/JsCodegenBoxTestGenerated.java
+++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/JsCodegenBoxTestGenerated.java
@@ -31931,6 +31931,16 @@
}
}
}
+
+ @Nested
+ @TestMetadata("compiler/testData/codegen/box/reflection/call/valueClasses")
+ @TestDataPath("$PROJECT_ROOT")
+ public class ValueClasses {
+ @Test
+ public void testAllFilesPresentInValueClasses() throws Exception {
+ KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/reflection/call/valueClasses"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS, true);
+ }
+ }
}
@Nested
@@ -32391,6 +32401,16 @@
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/reflection/mapping/types"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS, true);
}
}
+
+ @Nested
+ @TestMetadata("compiler/testData/codegen/box/reflection/mapping/valueClasses")
+ @TestDataPath("$PROJECT_ROOT")
+ public class ValueClasses {
+ @Test
+ public void testAllFilesPresentInValueClasses() throws Exception {
+ KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/reflection/mapping/valueClasses"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS, true);
+ }
+ }
}
@Nested
diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/fir/FirJsCodegenBoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/fir/FirJsCodegenBoxTestGenerated.java
index 22e5a53..3f973ee 100644
--- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/fir/FirJsCodegenBoxTestGenerated.java
+++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/fir/FirJsCodegenBoxTestGenerated.java
@@ -32117,6 +32117,16 @@
}
}
}
+
+ @Nested
+ @TestMetadata("compiler/testData/codegen/box/reflection/call/valueClasses")
+ @TestDataPath("$PROJECT_ROOT")
+ public class ValueClasses {
+ @Test
+ public void testAllFilesPresentInValueClasses() throws Exception {
+ KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/reflection/call/valueClasses"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true);
+ }
+ }
}
@Nested
@@ -32577,6 +32587,16 @@
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/reflection/mapping/types"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true);
}
}
+
+ @Nested
+ @TestMetadata("compiler/testData/codegen/box/reflection/mapping/valueClasses")
+ @TestDataPath("$PROJECT_ROOT")
+ public class ValueClasses {
+ @Test
+ public void testAllFilesPresentInValueClasses() throws Exception {
+ KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/reflection/mapping/valueClasses"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true);
+ }
+ }
}
@Nested
diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsCodegenBoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsCodegenBoxTestGenerated.java
index 53e4cda..79aa547 100644
--- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsCodegenBoxTestGenerated.java
+++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsCodegenBoxTestGenerated.java
@@ -32117,6 +32117,16 @@
}
}
}
+
+ @Nested
+ @TestMetadata("compiler/testData/codegen/box/reflection/call/valueClasses")
+ @TestDataPath("$PROJECT_ROOT")
+ public class ValueClasses {
+ @Test
+ public void testAllFilesPresentInValueClasses() throws Exception {
+ KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/reflection/call/valueClasses"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true);
+ }
+ }
}
@Nested
@@ -32577,6 +32587,16 @@
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/reflection/mapping/types"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true);
}
}
+
+ @Nested
+ @TestMetadata("compiler/testData/codegen/box/reflection/mapping/valueClasses")
+ @TestDataPath("$PROJECT_ROOT")
+ public class ValueClasses {
+ @Test
+ public void testAllFilesPresentInValueClasses() throws Exception {
+ KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/reflection/mapping/valueClasses"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true);
+ }
+ }
}
@Nested
diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsES6CodegenBoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsES6CodegenBoxTestGenerated.java
index 2ce5a51..e519b2e 100644
--- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsES6CodegenBoxTestGenerated.java
+++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsES6CodegenBoxTestGenerated.java
@@ -32117,6 +32117,16 @@
}
}
}
+
+ @Nested
+ @TestMetadata("compiler/testData/codegen/box/reflection/call/valueClasses")
+ @TestDataPath("$PROJECT_ROOT")
+ public class ValueClasses {
+ @Test
+ public void testAllFilesPresentInValueClasses() throws Exception {
+ KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/reflection/call/valueClasses"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR_ES6, true);
+ }
+ }
}
@Nested
@@ -32577,6 +32587,16 @@
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/reflection/mapping/types"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR_ES6, true);
}
}
+
+ @Nested
+ @TestMetadata("compiler/testData/codegen/box/reflection/mapping/valueClasses")
+ @TestDataPath("$PROJECT_ROOT")
+ public class ValueClasses {
+ @Test
+ public void testAllFilesPresentInValueClasses() throws Exception {
+ KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/reflection/mapping/valueClasses"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR_ES6, true);
+ }
+ }
}
@Nested
diff --git a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/K2NativeCodegenBoxTestGenerated.java b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/K2NativeCodegenBoxTestGenerated.java
index ec8207c..0f458e0 100644
--- a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/K2NativeCodegenBoxTestGenerated.java
+++ b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/K2NativeCodegenBoxTestGenerated.java
@@ -35571,6 +35571,19 @@
}
}
}
+
+ @Nested
+ @TestMetadata("compiler/testData/codegen/box/reflection/call/valueClasses")
+ @TestDataPath("$PROJECT_ROOT")
+ @Tag("codegenK2")
+ @UseExtTestCaseGroupProvider()
+ @K2Pipeline()
+ public class ValueClasses {
+ @Test
+ public void testAllFilesPresentInValueClasses() throws Exception {
+ KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/reflection/call/valueClasses"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.NATIVE, true);
+ }
+ }
}
@Nested
@@ -36091,6 +36104,19 @@
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/reflection/mapping/types"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.NATIVE, true);
}
}
+
+ @Nested
+ @TestMetadata("compiler/testData/codegen/box/reflection/mapping/valueClasses")
+ @TestDataPath("$PROJECT_ROOT")
+ @Tag("codegenK2")
+ @UseExtTestCaseGroupProvider()
+ @K2Pipeline()
+ public class ValueClasses {
+ @Test
+ public void testAllFilesPresentInValueClasses() throws Exception {
+ KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/reflection/mapping/valueClasses"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.NATIVE, true);
+ }
+ }
}
@Nested
diff --git a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeCodegenBoxTestGenerated.java b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeCodegenBoxTestGenerated.java
index 9891efe..b43c618 100644
--- a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeCodegenBoxTestGenerated.java
+++ b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeCodegenBoxTestGenerated.java
@@ -35148,6 +35148,18 @@
}
}
}
+
+ @Nested
+ @TestMetadata("compiler/testData/codegen/box/reflection/call/valueClasses")
+ @TestDataPath("$PROJECT_ROOT")
+ @Tag("codegen")
+ @UseExtTestCaseGroupProvider()
+ public class ValueClasses {
+ @Test
+ public void testAllFilesPresentInValueClasses() throws Exception {
+ KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/reflection/call/valueClasses"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.NATIVE, true);
+ }
+ }
}
@Nested
@@ -35652,6 +35664,18 @@
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/reflection/mapping/types"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.NATIVE, true);
}
}
+
+ @Nested
+ @TestMetadata("compiler/testData/codegen/box/reflection/mapping/valueClasses")
+ @TestDataPath("$PROJECT_ROOT")
+ @Tag("codegen")
+ @UseExtTestCaseGroupProvider()
+ public class ValueClasses {
+ @Test
+ public void testAllFilesPresentInValueClasses() throws Exception {
+ KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/reflection/mapping/valueClasses"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.NATIVE, true);
+ }
+ }
}
@Nested
diff --git a/wasm/wasm.tests/tests-gen/org/jetbrains/kotlin/wasm/test/IrCodegenBoxWasmTestGenerated.java b/wasm/wasm.tests/tests-gen/org/jetbrains/kotlin/wasm/test/IrCodegenBoxWasmTestGenerated.java
index 40b7cae..c80d55a 100644
--- a/wasm/wasm.tests/tests-gen/org/jetbrains/kotlin/wasm/test/IrCodegenBoxWasmTestGenerated.java
+++ b/wasm/wasm.tests/tests-gen/org/jetbrains/kotlin/wasm/test/IrCodegenBoxWasmTestGenerated.java
@@ -28720,6 +28720,19 @@
}
}
}
+
+ @TestMetadata("compiler/testData/codegen/box/reflection/call/valueClasses")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class ValueClasses extends AbstractIrCodegenBoxWasmTest {
+ private void runTest(String testDataFilePath) throws Exception {
+ KotlinTestUtils.runTest0(this::doTest, TargetBackend.WASM, testDataFilePath);
+ }
+
+ public void testAllFilesPresentInValueClasses() throws Exception {
+ KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/reflection/call/valueClasses"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.WASM, true);
+ }
+ }
}
@TestMetadata("compiler/testData/codegen/box/reflection/callBy")
@@ -29178,6 +29191,19 @@
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/reflection/mapping/types"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.WASM, true);
}
}
+
+ @TestMetadata("compiler/testData/codegen/box/reflection/mapping/valueClasses")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class ValueClasses extends AbstractIrCodegenBoxWasmTest {
+ private void runTest(String testDataFilePath) throws Exception {
+ KotlinTestUtils.runTest0(this::doTest, TargetBackend.WASM, testDataFilePath);
+ }
+
+ public void testAllFilesPresentInValueClasses() throws Exception {
+ KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/reflection/mapping/valueClasses"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.WASM, true);
+ }
+ }
}
@TestMetadata("compiler/testData/codegen/box/reflection/methodsFromAny")