[IR] Add MFVC generation tests

#KT-1179
This commit is contained in:
Evgeniy.Zhelenskiy
2022-05-07 00:03:39 +03:00
committed by teamcity
parent 894cdc2307
commit 765c212327
23 changed files with 1399 additions and 233 deletions
@@ -50189,6 +50189,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/valueClasses/classFlattening.kt", TransformersFunctions.getReplaceOptionalJvmInlineAnnotationWithReal());
}
@Test
@TestMetadata("complex.kt")
public void testComplex() throws Exception {
runTest("compiler/testData/codegen/box/valueClasses/complex.kt", TransformersFunctions.getReplaceOptionalJvmInlineAnnotationWithReal());
}
@Test
@TestMetadata("equality.kt")
public void testEquality() throws Exception {
@@ -50196,9 +50202,21 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
}
@Test
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
runTest("compiler/testData/codegen/box/valueClasses/simple.kt", TransformersFunctions.getReplaceOptionalJvmInlineAnnotationWithReal());
@TestMetadata("MFVCFieldInitializationOrder.kt")
public void testMFVCFieldInitializationOrder() throws Exception {
runTest("compiler/testData/codegen/box/valueClasses/MFVCFieldInitializationOrder.kt", TransformersFunctions.getReplaceOptionalJvmInlineAnnotationWithReal());
}
@Test
@TestMetadata("overrides.kt")
public void testOverrides() throws Exception {
runTest("compiler/testData/codegen/box/valueClasses/overrides.kt", TransformersFunctions.getReplaceOptionalJvmInlineAnnotationWithReal());
}
@Test
@TestMetadata("throwingMFVCReassignments.kt")
public void testThrowingMFVCReassignments() throws Exception {
runTest("compiler/testData/codegen/box/valueClasses/throwingMFVCReassignments.kt", TransformersFunctions.getReplaceOptionalJvmInlineAnnotationWithReal());
}
}
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.test.runners.codegen;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.util.KtTestUtil;
import org.jetbrains.kotlin.test.TargetBackend;
import org.jetbrains.kotlin.test.utils.TransformersFunctions;
import org.jetbrains.kotlin.test.TestMetadata;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
@@ -5779,6 +5780,46 @@ public class FirBytecodeTextTestGenerated extends AbstractFirBytecodeTextTest {
}
}
@Nested
@TestMetadata("compiler/testData/codegen/bytecodeText/valueClasses")
@TestDataPath("$PROJECT_ROOT")
public class ValueClasses {
@Test
public void testAllFilesPresentInValueClasses() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/bytecodeText/valueClasses"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
}
@Test
@TestMetadata("equalsBoxTest.kt")
public void testEqualsBoxTest() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/valueClasses/equalsBoxTest.kt", TransformersFunctions.getReplaceOptionalJvmInlineAnnotationWithReal());
}
@Test
@TestMetadata("MFVCDeclaration.kt")
public void testMFVCDeclaration() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/valueClasses/MFVCDeclaration.kt", TransformersFunctions.getReplaceOptionalJvmInlineAnnotationWithReal());
}
@Test
@TestMetadata("MFVCReassignments.kt")
public void testMFVCReassignments() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/valueClasses/MFVCReassignments.kt", TransformersFunctions.getReplaceOptionalJvmInlineAnnotationWithReal());
}
@Test
@TestMetadata("passingMFVC2Functions.kt")
public void testPassingMFVC2Functions() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/valueClasses/passingMFVC2Functions.kt", TransformersFunctions.getReplaceOptionalJvmInlineAnnotationWithReal());
}
@Test
@TestMetadata("regularClassWithMFVC.kt")
public void testRegularClassWithMFVC() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/valueClasses/regularClassWithMFVC.kt", TransformersFunctions.getReplaceOptionalJvmInlineAnnotationWithReal());
}
}
@Nested
@TestMetadata("compiler/testData/codegen/bytecodeText/varargs")
@TestDataPath("$PROJECT_ROOT")
@@ -113,7 +113,7 @@ internal val bridgePhase = makeIrFilePhase(
::BridgeLowering,
name = "Bridge",
description = "Generate bridges",
prerequisite = setOf(jvmInlineClassPhase, jvmMultiFieldValueClassPhase)
prerequisite = setOf(jvmInlineClassPhase, jvmMultiFieldValueClassPhase, inheritedDefaultMethodsOnClassesPhase)
)
internal class BridgeLowering(val context: JvmBackendContext) : FileLoweringPass, IrElementTransformerVoid() {
@@ -446,6 +446,11 @@ internal class BridgeLowering(val context: JvmBackendContext) : FileLoweringPass
}.apply {
copyAttributes(target)
copyParametersWithErasure(this@addBridge, bridge.overridden)
with(context.multiFieldValueClassReplacements) {
bindingNewFunctionToParameterTemplateStructure[bridge.overridden]?.also {
bindingNewFunctionToParameterTemplateStructure[this@apply] = it
}
}
// If target is a throwing stub, bridge also should just throw UnsupportedOperationException.
// Otherwise, it might throw ClassCastException when downcasting bridge argument to expected type.
@@ -501,6 +506,11 @@ internal class BridgeLowering(val context: JvmBackendContext) : FileLoweringPass
context.functionsWithSpecialBridges.add(target)
copyParametersWithErasure(this@addSpecialBridge, specialBridge.overridden, specialBridge.substitutedParameterTypes)
with(context.multiFieldValueClassReplacements) {
bindingNewFunctionToParameterTemplateStructure[specialBridge.overridden]?.also {
bindingNewFunctionToParameterTemplateStructure[this@apply] = it
}
}
body = context.createIrBuilder(symbol, startOffset, endOffset).irBlockBody {
specialBridge.methodInfo?.let { info ->
@@ -627,18 +637,36 @@ internal class BridgeLowering(val context: JvmBackendContext) : FileLoweringPass
) =
irCastIfNeeded(
irCall(target, origin = IrStatementOrigin.BRIDGE_DELEGATION, superQualifierSymbol = superQualifierSymbol).apply {
val mfvcOrOriginal =
this@BridgeLowering.context.inlineClassReplacements.originalFunctionForMethodReplacement[target] ?: target
val structure = with(this@BridgeLowering.context.multiFieldValueClassReplacements) {
originalFunctionForMethodReplacement[mfvcOrOriginal]
?.let { bindingParameterTemplateStructure[it] }
val targetStructure = run {
val mfvcOrOriginal =
this@BridgeLowering.context.inlineClassReplacements.originalFunctionForMethodReplacement[target] ?: target
this@BridgeLowering.context.multiFieldValueClassReplacements
.bindingNewFunctionToParameterTemplateStructure[mfvcOrOriginal]
?.also { structure ->
val errorMessage = { "Bad parameters structure: $structure" }
require(structure.size == bridge.explicitParametersCount) { errorMessage() }
require(structure.sumOf { it.valueParameters.size } == target.explicitParametersCount) { errorMessage() }
}
}
val bridgeStructure = run {
val mfvcOrOriginal =
this@BridgeLowering.context.inlineClassReplacements.originalFunctionForMethodReplacement[bridge] ?: bridge
this@BridgeLowering.context.multiFieldValueClassReplacements
.bindingNewFunctionToParameterTemplateStructure[mfvcOrOriginal]
?.also { structure ->
val errorMessage = { "Bad parameters structure: $structure" }
require(structure.sumOf { it.valueParameters.size } == bridge.explicitParametersCount) { errorMessage() }
}
}
require(targetStructure == null || bridgeStructure == null ||
bridgeStructure.size == targetStructure.size &&
(targetStructure zip bridgeStructure).none { (targetParameter, bridgeParameter) ->
targetParameter is MultiFieldValueClassMapping && bridgeParameter is MultiFieldValueClassMapping &&
targetParameter.declarations != bridgeParameter.declarations
}) { "Incompatible structures: $bridgeStructure and $targetStructure" }
fun irGetOrCast(bridgeParameter: IrValueParameter, targetParameter: IrValueParameter) =
irGet(bridgeParameter).let { argument ->
if (bridgeParameter == bridge.dispatchReceiverParameter)
@@ -647,29 +675,69 @@ internal class BridgeLowering(val context: JvmBackendContext) : FileLoweringPass
irCastIfNeeded(argument, targetParameter.type.upperBound)
}
val targetParameters = target.explicitParameters
val flattenedBridgeArguments = when (structure) {
null -> bridge.explicitParameters.zip(target.explicitParameters, ::irGetOrCast)
else -> {
var index = 0
(structure zip bridge.explicitParameters).flatMap { (remappedParameter, bridgeParameter) ->
when (remappedParameter) {
is MultiFieldValueClassMapping -> remappedParameter.declarations.unboxMethods.map { unboxFunction ->
val targetExplicitParameters = target.explicitParameters
val bridgeExplicitParameters = bridge.explicitParameters
var targetIndex = 0
var bridgeIndex = 0
var structureIndex = 0
while (targetIndex < targetExplicitParameters.size && bridgeIndex < bridgeExplicitParameters.size) {
val targetRemappedParameter = targetStructure?.get(structureIndex)
val bridgeRemappedParameter = bridgeStructure?.get(structureIndex)
when (targetRemappedParameter) {
is MultiFieldValueClassMapping -> when (bridgeRemappedParameter) {
is MultiFieldValueClassMapping -> {
require(bridgeRemappedParameter.declarations == targetRemappedParameter.declarations) {
"Incompatible parameters: $bridgeRemappedParameter, $targetRemappedParameter"
}
repeat(bridgeRemappedParameter.valueParameters.size) {
val bridgeParameter = bridgeExplicitParameters[bridgeIndex++]
val targetParameter = targetExplicitParameters[targetIndex++]
putArgument(targetParameter, irGetOrCast(bridgeParameter, targetParameter))
}
}
is RegularMapping, null -> {
val bridgeParameter = bridgeExplicitParameters[bridgeIndex++]
val newArguments = targetRemappedParameter.declarations.unboxMethods.map { unboxFunction ->
irCall(unboxFunction).apply {
dispatchReceiver =
irCastIfNeeded(irGet(bridgeParameter), remappedParameter.declarations.valueClass.defaultType)
val targetParameterType = targetRemappedParameter.declarations.valueClass.defaultType
dispatchReceiver = irCastIfNeeded(irGet(bridgeParameter), targetParameterType)
}
}.also { index += it.size }
is RegularMapping -> listOf(irGetOrCast(bridgeParameter, targetParameters[index++]))
}
for (newArgument in newArguments) {
putArgument(targetExplicitParameters[targetIndex++], newArgument)
}
}
}
is RegularMapping, null -> {
val targetParameter = targetExplicitParameters[targetIndex]
when (bridgeRemappedParameter) {
is MultiFieldValueClassMapping -> {
val count = bridgeRemappedParameter.declarations.fields.size
val boxCall = irCall(bridgeRemappedParameter.declarations.boxMethod).apply {
for (i in 0 until count) {
putValueArgument(i, irGet(bridgeExplicitParameters[bridgeIndex++]))
}
}
putArgument(targetParameter, irCastIfNeeded(boxCall, targetParameter.type.upperBound))
}
is RegularMapping, null -> {
val bridgeParameter = bridgeExplicitParameters[bridgeIndex++]
putArgument(targetParameter, irGetOrCast(bridgeParameter, targetParameter))
}
}
targetIndex++
}
}
structureIndex++
}
require(targetParameters.size == flattenedBridgeArguments.size) {
"Incorrect number of arguments: ${flattenedBridgeArguments.size} instead of ${targetParameters.size}"
require(targetIndex == targetExplicitParameters.size && bridgeIndex == bridgeExplicitParameters.size) {
"Incorrect bridge:\n${bridge.dump()}\n\nfor target\n${target.dump()}"
}
for ((targetParam, argument) in target.explicitParameters zip flattenedBridgeArguments) {
putArgument(targetParam, argument)
require((targetStructure == null || structureIndex == targetStructure.size)) {
"Invalid structure index $structureIndex for $targetStructure"
}
require((bridgeStructure == null || structureIndex == bridgeStructure.size)) {
"Invalid structure index $structureIndex for $bridgeStructure"
}
},
bridge.returnType.upperBound
@@ -12,6 +12,9 @@ import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
import org.jetbrains.kotlin.backend.jvm.MemoizedMultiFieldValueClassReplacements.RemappedParameter.MultiFieldValueClassMapping
import org.jetbrains.kotlin.backend.jvm.MemoizedMultiFieldValueClassReplacements.RemappedParameter.RegularMapping
import org.jetbrains.kotlin.backend.jvm.fullValueParameterList
import org.jetbrains.kotlin.backend.jvm.ir.*
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.config.JvmDefaultMode
@@ -100,15 +103,47 @@ private class InheritedDefaultMethodsOnClassesLowering(val context: JvmBackendCo
}
passTypeArgumentsFrom(irFunction, offset = superMethod.parentAsClass.typeParameters.size)
var offset = 0
irFunction.dispatchReceiverParameter?.let {
putValueArgument(
offset++,
irGet(it).reinterpretAsDispatchReceiverOfType(superClassType)
)
putValueArgument(0, irGet(it).reinterpretAsDispatchReceiverOfType(superClassType))
}
val lowering = this@InheritedDefaultMethodsOnClassesLowering
val mfvcOrOriginal = lowering.context.inlineClassReplacements.originalFunctionForMethodReplacement[classOverride]
?: classOverride
val bindingNewFunctionToParameterTemplateStructure = lowering.context.multiFieldValueClassReplacements
.bindingNewFunctionToParameterTemplateStructure
val structure = bindingNewFunctionToParameterTemplateStructure[mfvcOrOriginal]?.let { structure ->
val errorMessage = { "Bad parameters structure: $structure" }
require(structure.sumOf { it.valueParameters.size } == classOverride.explicitParametersCount) { errorMessage() }
if (defaultImplFun.explicitParametersCount == irFunction.explicitParametersCount) {
null
} else {
require(structure.size == defaultImplFun.explicitParametersCount) { errorMessage() }
structure
}
}
require(structure == null || structure.first() is RegularMapping) {
"Dispatch receiver for method replacement cannot be flattened"
}
val sourceFullValueParameterList = irFunction.fullValueParameterList
if (structure == null) {
sourceFullValueParameterList.forEachIndexed { index, parameter ->
putValueArgument(1 + index, irGet(parameter))
}
} else {
var flattenedIndex = 0
for (i in 1 until structure.size) {
when (val remappedParameter = structure[i]) {
is MultiFieldValueClassMapping ->
putValueArgument(i, irCall(remappedParameter.declarations.boxMethod).apply {
val boxArgumentsCount = remappedParameter.valueParameters.size
for (boxArgumentIndex in 0 until boxArgumentsCount) {
putValueArgument(boxArgumentIndex, irGet(sourceFullValueParameterList[flattenedIndex++]))
}
})
is RegularMapping -> putValueArgument(i, irGet(sourceFullValueParameterList[flattenedIndex++]))
}
}
}
irFunction.extensionReceiverParameter?.let { putValueArgument(offset++, irGet(it)) }
irFunction.valueParameters.mapIndexed { i, parameter -> putValueArgument(i + offset, irGet(parameter)) }
}
)
}
@@ -18,6 +18,7 @@ import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.builders.declarations.addConstructor
import org.jetbrains.kotlin.ir.builders.declarations.buildFun
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
@@ -29,6 +30,7 @@ import org.jetbrains.kotlin.ir.types.isNullable
import org.jetbrains.kotlin.ir.types.makeNotNull
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.JVM_INLINE_ANNOTATION_FQ_NAME
val jvmInlineClassPhase = makeIrFilePhase(
@@ -64,6 +66,21 @@ private class JvmInlineClassLowering(context: JvmBackendContext) : JvmValueClass
}
}
override fun createBridgeDeclaration(source: IrSimpleFunction, replacement: IrSimpleFunction, mangledName: Name): IrSimpleFunction =
context.irFactory.buildFun {
updateFrom(source)
name = mangledName
returnType = source.returnType
}.apply {
copyParameterDeclarationsFrom(source)
annotations = source.annotations
parent = source.parent
// We need to ensure that this bridge has the same attribute owner as its static inline class replacement, since this
// is used in [CoroutineCodegen.isStaticInlineClassReplacementDelegatingCall] to identify the bridge and avoid generating
// a continuation class.
copyAttributes(source)
}
override fun IrClass.isSpecificLoweringLogicApplicable(): Boolean = isSingleFieldValueClass
override fun IrFunction.isFieldGetterToRemove(): Boolean = isInlineClassFieldGetter
@@ -5,6 +5,8 @@
package org.jetbrains.kotlin.backend.jvm.lower
import org.jetbrains.kotlin.backend.common.ir.copyParameterDeclarationsFrom
import org.jetbrains.kotlin.backend.common.ir.copyTo
import org.jetbrains.kotlin.backend.common.ir.createDispatchReceiverParameter
import org.jetbrains.kotlin.backend.common.ir.passTypeArgumentsFrom
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
@@ -21,22 +23,26 @@ import org.jetbrains.kotlin.backend.jvm.MultiFieldValueClassSpecificDeclarations
import org.jetbrains.kotlin.backend.jvm.MultiFieldValueClassTree.InternalNode
import org.jetbrains.kotlin.backend.jvm.ir.erasedUpperBound
import org.jetbrains.kotlin.backend.jvm.ir.isMultiFieldValueClassType
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.builders.declarations.addGetter
import org.jetbrains.kotlin.ir.builders.declarations.buildField
import org.jetbrains.kotlin.ir.builders.declarations.buildFun
import org.jetbrains.kotlin.ir.builders.declarations.buildProperty
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrAnonymousInitializerSymbolImpl
import org.jetbrains.kotlin.ir.transformStatement
import org.jetbrains.kotlin.ir.types.classOrNull
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.isNullable
import org.jetbrains.kotlin.ir.types.makeNotNull
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.utils.addToStdlib.popLast
@@ -103,6 +109,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
private val regularClassMFVCPropertyNextGetters: MutableMap<IrSimpleFunction, Map<Name, IrSimpleFunction>> = mutableMapOf()
private val regularClassMFVCPropertyFieldsMapping: MutableMap<IrField, List<IrField>> = mutableMapOf()
private val regularClassMFVCPropertyNodes: MutableMap<IrSimpleFunction, MultiFieldValueClassTree<Unit, Unit>> = mutableMapOf()
private val regularClassMFVCPropertyAllPrimitiveGetters: MutableSet<IrSimpleFunction> = mutableSetOf()
override val replacements
get() = context.multiFieldValueClassReplacements
@@ -152,7 +159,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
visibility = sourceField.visibility
}.apply {
parent = declaration
initializer
initializer = null
}
}
regularClassMFVCPropertyFieldsMapping[oldField] = newFields
@@ -161,6 +168,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
type = newField.type,
makeGetter = { receiver: IrValueDeclaration -> irGetField(irGet(receiver), newField) },
assigner = { receiver: IrValueDeclaration, value: IrExpression -> irSetField(irGet(receiver), newField, value) },
symbol = null,
)
}
val implementationAgnostic = declarations.ImplementationAgnostic(virtualFields)
@@ -202,6 +210,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
regularClassMFVCPropertyNextGetters[getter] = node.fields.associate { it.name to nodesToGetters[it.node]!! }
}
}
regularClassMFVCPropertyAllPrimitiveGetters.addAll(nodesToGetters.values)
}
}
for (accessor in listOfNotNull(mainGetter, mainSetter))
@@ -214,7 +223,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
val gettersAndSetters =
newFields.toGettersAndSetters(accessor.dispatchReceiverParameter!!, transformReceiver = true)
val representation = newFields.zip(gettersAndSetters) { newField, (getter, setter) ->
VirtualProperty(newField.type, getter, setter)
VirtualProperty(newField.type, getter, setter, null)
}
val fieldRepresentation = declarations.ImplementationAgnostic(representation)
val boxed = fieldRepresentation.boxedExpression(
@@ -235,10 +244,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
parent = declaration
body = context.createIrBuilder(this.symbol).irBlockBody {
+irBlock {
flattenExpressionTo(
initializer.expression.transform(this@JvmMultiFieldValueClassLowering, null),
newFields.toGettersAndSetters(declaration.thisReceiver!!)
)
flattenExpressionTo(initializer.expression, newFields.toGettersAndSetters(declaration.thisReceiver!!))
}
}
oldFieldToInitializers[oldField] = this
@@ -317,40 +323,104 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
}
private fun MultiFieldValueClassSpecificDeclarations.replaceProperties() {
valueClass.declarations.removeIf { it is IrFunction && it.isFieldGetterToRemove() }
valueClass.declarations.removeAll(oldProperties.values.mapNotNull { it.getter })
properties.values.forEach {
it.parent = valueClass
}
valueClass.declarations += properties.values.map { it.getter!!.apply { parent = valueClass } }
}
override fun createBridgeDeclaration(source: IrSimpleFunction, replacement: IrSimpleFunction, mangledName: Name): IrSimpleFunction =
context.irFactory.buildFun {
updateFrom(source)
name = mangledName
returnType = source.returnType
}.apply {
val overriddenReplaced = replacement.overriddenSymbols.firstOrNull {
replacements.bindingNewFunctionToParameterTemplateStructure[it.owner] != null
}?.owner
if (source.isFakeOverride && source.parentAsClass.isMultiFieldValueClass && overriddenReplaced != null) {
copyParameterDeclarationsFrom(overriddenReplaced)
dispatchReceiverParameter = source.dispatchReceiverParameter!!.copyTo(this)
val replacementStructure = replacement.overriddenSymbols.firstNotNullOf {
replacements.bindingNewFunctionToParameterTemplateStructure[it.owner]
}.toMutableList().apply {
set(0, RegularMapping(ValueParameterTemplate(dispatchReceiverParameter!!, dispatchReceiverParameter!!.origin)))
}
replacements.bindingNewFunctionToParameterTemplateStructure[this] = replacementStructure
} else {
copyParameterDeclarationsFrom(source)
}
annotations = source.annotations
parent = source.parent
// We need to ensure that this bridge has the same attribute owner as its static inline class replacement, since this
// is used in [CoroutineCodegen.isStaticInlineClassReplacementDelegatingCall] to identify the bridge and avoid generating
// a continuation class.
copyAttributes(source)
}
override fun createBridgeBody(source: IrSimpleFunction, target: IrSimpleFunction, original: IrFunction, inverted: Boolean) {
allScopes.push(createScope(source))
source.body = context.createIrBuilder(source.symbol, source.startOffset, source.endOffset).run {
val sourceExplicitParameters = source.explicitParameters
if (inverted) {
irExprBody(irCall(target).apply {
passTypeArgumentsFrom(source)
val structure: List<RemappedParameter> = replacements.bindingParameterTemplateStructure[original]!!
var flattenedIndex = 0
for ((remappedParameter, targetParameter) in structure zip target.explicitParameters) {
when (remappedParameter) {
is MultiFieldValueClassMapping -> putArgument(
targetParameter,
irCall(remappedParameter.declarations.boxMethod).apply {
source.explicitParameters
.slice(flattenedIndex until flattenedIndex + remappedParameter.valueParameters.size)
.forEachIndexed { index, boxParameter -> putValueArgument(index, irGet(boxParameter)) }
.also { flattenedIndex += remappedParameter.valueParameters.size }
})
is RegularMapping -> putArgument(targetParameter, irGet(source.explicitParameters[flattenedIndex++]))
val targetExplicitParameters = target.explicitParameters
val originalStructure: List<RemappedParameter> = replacements.bindingOldFunctionToParameterTemplateStructure[original]!!
val targetStructure = replacements.bindingNewFunctionToParameterTemplateStructure[target]
require(
when (targetStructure) {
null -> originalStructure.size == targetExplicitParameters.size
else -> originalStructure.size == targetStructure.size &&
targetStructure.sumOf { it.valueParameters.size } == targetExplicitParameters.size
}
) {
"Incompatible structures: $originalStructure, $targetStructure"
}
val structuresSizes = originalStructure.size
var flattenedSourceIndex = 0
var flattenedTargetIndex = 0
for (i in 0 until structuresSizes) {
val remappedOriginalParameter = originalStructure[i]
val remappedTargetParameter = targetStructure?.get(i)
when (remappedOriginalParameter) {
is MultiFieldValueClassMapping -> {
when (remappedTargetParameter) {
is MultiFieldValueClassMapping -> {
require(remappedTargetParameter.valueParameters.size == remappedOriginalParameter.valueParameters.size) {
"Incompatible structures: $remappedTargetParameter, $remappedOriginalParameter"
}
repeat(remappedTargetParameter.valueParameters.size) {
putArgument(
targetExplicitParameters[flattenedTargetIndex++],
irGet(sourceExplicitParameters[flattenedSourceIndex++])
)
}
}
is RegularMapping, null ->
putArgument(
targetExplicitParameters[flattenedTargetIndex++],
irCall(remappedOriginalParameter.declarations.boxMethod).apply {
sourceExplicitParameters
.slice(flattenedSourceIndex until flattenedSourceIndex + remappedOriginalParameter.valueParameters.size)
.forEachIndexed { index, boxParameter -> putValueArgument(index, irGet(boxParameter)) }
.also { flattenedSourceIndex += remappedOriginalParameter.valueParameters.size }
})
}
}
is RegularMapping -> putArgument(
targetExplicitParameters[flattenedTargetIndex++],
irGet(sourceExplicitParameters[flattenedSourceIndex++])
)
}
}
})
} else {
irExprBody(irCall(original).apply { // not target as it will be replaced during lowering
passTypeArgumentsFrom(source)
for ((parameter, newParameter) in source.explicitParameters.zip(original.explicitParameters)) {
for ((parameter, newParameter) in sourceExplicitParameters.zip(original.explicitParameters)) {
putArgument(newParameter, irGet(parameter))
}
}).transform(this@JvmMultiFieldValueClassLowering, null)
@@ -360,7 +430,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
}
override fun addBindingsFor(original: IrFunction, replacement: IrFunction) {
val parametersStructure = replacements.bindingParameterTemplateStructure[original]!!
val parametersStructure = replacements.bindingOldFunctionToParameterTemplateStructure[original]!!
require(parametersStructure.size == original.explicitParameters.size) {
"Wrong value parameters structure: $parametersStructure"
}
@@ -462,7 +532,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
}
else ->
when (val newConstructor = (function as? IrConstructor)?.let { replacements.getReplacementRegularClassConstructor(it) }) {
null -> super.visitFunctionAccess(expression)
null -> return super.visitFunctionAccess(expression)
else -> context.createIrBuilder(currentScope.symbol).irBlock {
buildReplacement(function, expression, newConstructor)
}
@@ -472,21 +542,27 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
override fun visitCall(expression: IrCall): IrExpression {
val callee = expression.symbol.owner
val receiver = expression.dispatchReceiver?.transform(this, null)
val oldReceiver = expression.dispatchReceiver
val name = callee.correspondingPropertySymbol?.owner?.name
if (callee.isMultiFieldValueClassOriginalFieldGetter && receiver != null) {
if (callee.isMultiFieldValueClassOriginalFieldGetter && oldReceiver != null) {
with(valueDeclarationsRemapper) {
with(context.createIrBuilder(expression.symbol)) {
subfield(receiver, name!!)?.let { return it }
}
}
}
if (callee.isGetter && name != null && receiver is IrCall) {
val nextFunction = regularClassMFVCPropertyNextGetters[receiver.symbol.owner]?.get(name)
if (nextFunction != null) {
return with(context.createIrBuilder(expression.symbol)) {
irCall(nextFunction).apply {
this.dispatchReceiver = receiver.dispatchReceiver
val newReceiver = oldReceiver.transform(this@JvmMultiFieldValueClassLowering, null)
if (newReceiver is IrCall) {
val nextFunction = regularClassMFVCPropertyNextGetters[newReceiver.symbol.owner]?.get(name)
if (nextFunction != null) {
return irCall(nextFunction).apply {
this.dispatchReceiver = newReceiver.dispatchReceiver
}
}
}
subfield(newReceiver, name!!)?.let { return it }
return expression.apply {
dispatchReceiver = newReceiver
extensionReceiver = extensionReceiver?.transform(this@JvmMultiFieldValueClassLowering, null)
for (i in 0 until valueArgumentsCount) {
putValueArgument(i, getValueArgument(i)?.transform(this@JvmMultiFieldValueClassLowering, null))
}
}
}
}
@@ -511,7 +587,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
} else {
val equals = leftClass.functions.single { it.name.asString() == "equals" && it.overriddenSymbols.isNotEmpty() }
return super.visitCall(context.createIrBuilder(expression.symbol).run {
irCall(equals).apply {
irCall(equals).apply {
copyTypeArgumentsFrom(expression)
dispatchReceiver = leftArgument
putValueArgument(0, rightArgument)
@@ -520,16 +596,16 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
}
} else if (rightImplementation != null) {
if (leftArgument.isNullConst()) {
return context.createIrBuilder(expression.symbol).irBlock {
return context.createIrBuilder(expression.symbol).irBlock {
+rightArgument
+irFalse()
}.transform(this, null)
}
if (leftArgument.type.classOrNull == rightArgument.type.classOrNull && leftArgument.type.isNullable()) {
if (leftArgument.type.erasedUpperBound == rightArgument.type.erasedUpperBound && leftArgument.type.isNullable()) {
return context.createIrBuilder(expression.symbol).irBlock {
val leftValue = irTemporary(leftArgument)
+irIfNull(context.irBuiltIns.booleanType, irGet(leftValue), irFalse(), irBlock {
val nonNullLeftArgumentVariable =
val nonNullLeftArgumentVariable =
irTemporary(irImplicitCast(irGet(leftValue), leftArgument.type.makeNotNull()))
+irCall(context.irBuiltIns.eqeqSymbol).apply {
putValueArgument(0, irGet(nonNullLeftArgumentVariable))
@@ -556,7 +632,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
replacement: IrFunction
) {
val parameter2expression = typedArgumentList(originalFunction, original)
val structure = replacements.bindingParameterTemplateStructure[originalFunction]!!
val structure = replacements.bindingOldFunctionToParameterTemplateStructure[originalFunction]!!
require(parameter2expression.size == structure.size)
require(structure.sumOf { it.valueParameters.size } == replacement.explicitParametersCount)
val newArguments: List<IrExpression?> =
@@ -570,22 +646,72 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
}
}
override fun visitStringConcatenation(expression: IrStringConcatenation): IrExpression {
for (i in expression.arguments.indices) {
val argument = expression.arguments[i]
if (!argument.type.isNullable() && argument.type.isMultiFieldValueClassType()) {
expression.arguments[i] = context.createIrBuilder((currentScope!!.irElement as IrSymbolOwner).symbol).run {
val toString = argument.type.erasedUpperBound.functions.single {
it.name.asString() == "toString" && it.valueParameters.isEmpty()
}
irCall(toString).apply {
dispatchReceiver = argument
}
}
}
}
return super.visitStringConcatenation(expression)
}
private fun IrBlockBuilder.makeNewArguments(
oldArguments: List<IrExpression?>,
structure: List<List<ValueParameterTemplate>>
): List<IrExpression?> {
val variables = structure.flatMap { argTemplate -> argTemplate.map { irTemporary(irType = it.type) } }
val subVariables = structure.scan(0) { acc: Int, templates: List<ValueParameterTemplate> -> acc + templates.size }
.zipWithNext().map { (start, finish) -> variables.slice(start until finish) }
return (oldArguments zip subVariables).flatMap { (oldArgument, curSubVariables) ->
val oldArgumentTransformed = oldArgument?.transform(this@JvmMultiFieldValueClassLowering, null)
when {
oldArgumentTransformed == null -> List(curSubVariables.size) { null }
curSubVariables.size == 1 -> listOf(oldArgumentTransformed)
else -> flattenExpressionTo(oldArgumentTransformed, curSubVariables.toGettersAndSetters())
.let { curSubVariables.map { irGet(it) } }
var variables: List<IrVariable> = listOf()
var subVariables: List<List<IrVariable>> = listOf()
val declareVariables = irComposite {
variables = structure.flatMap { argTemplate -> argTemplate.map { irTemporary(irType = it.type) } }
subVariables = structure.scan(0) { acc: Int, templates: List<ValueParameterTemplate> -> acc + templates.size }
.zipWithNext().map { (start, finish) -> variables.slice(start until finish) }
}
val initializeVariables = irBlock {
(oldArguments zip subVariables).forEach { (oldArgument, curSubVariables) ->
when {
oldArgument == null -> Unit
curSubVariables.size == 1 -> {
val curSubVariable = curSubVariables.single()
+irSet(curSubVariable, oldArgument.transform(this@JvmMultiFieldValueClassLowering, null))
}
else -> flattenExpressionTo(oldArgument, curSubVariables.toGettersAndSetters())
}
}
}
val variablesSymbols2Index = variables.mapIndexed { index, variable -> variable.symbol to index }.toMap()
val inlinedArguments = run {
val result = mutableMapOf<IrValueSymbol, IrExpression>()
var lastIndex = -1 // we need to assign them in the same order
for (statement in initializeVariables.statements) {
if (statement !is IrSetValue) return@run null
val index = variablesSymbols2Index[statement.symbol] ?: return@run null
if (lastIndex >= index) return@run null
lastIndex = index
result[statement.symbol] = statement.value
}
result
}
if (inlinedArguments != null) {
return variables.map { inlinedArguments[it.symbol] }
}
+declareVariables
+initializeVariables
val newArguments: List<IrGetValueImpl?> = (oldArguments zip subVariables).flatMap { (oldArgument, curSubVariables) ->
when (oldArgument) {
null -> List(curSubVariables.size) { null }
else -> curSubVariables.map { irGet(it) }
}
}
return newArguments
}
// Note that reference equality (x === y) is not allowed on values of MFVC class type,
@@ -593,7 +719,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
private val IrCall.isSpecializedMFVCEqEq: Boolean
get() = symbol == context.irBuiltIns.eqeqSymbol &&
listOf(getValueArgument(0)!!, getValueArgument(1)!!)
.any { it.type.classOrNull?.owner?.takeIf { it.isMultiFieldValueClass } != null }
.any { it.type.erasedUpperBound.takeIf { it.isMultiFieldValueClass } != null }
override fun visitGetField(expression: IrGetField): IrExpression {
val field = expression.symbol.owner
@@ -630,11 +756,14 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
val replacementFields = regularClassMFVCPropertyFieldsMapping[field] ?: return super.visitSetField(expression)
return context.createIrBuilder(expression.symbol).irBlock {
val thisVar = irTemporary(expression.receiver!!.transform(this@JvmMultiFieldValueClassLowering, null))
val variables = replacementFields.map { irTemporary(irType = it.type, nameHint = it.name.asString()) }
// We flatten to temp variables because code can throw an exception otherwise and partially update variables
flattenExpressionTo(expression.value.transform(this@JvmMultiFieldValueClassLowering, null), variables.toGettersAndSetters())
for ((replacementField, variable) in replacementFields zip variables) {
+irSetField(irGet(thisVar), replacementField, irGet(variable))
val subValues = flattenExpressionToGetters(
expression = expression.value, // not modified
types = replacementFields.map { it.type },
additionalConditionForValue = { (_, value) -> value is IrGetValue }
)
for ((replacementField, subValue) in replacementFields zip subValues) {
+irSetField(irGet(thisVar), replacementField, subValue)
}
}
}
@@ -649,11 +778,19 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
val setters = valueDeclarationsRemapper.setter(expression.symbol) ?: return super.visitSetValue(expression)
return context.createIrBuilder(expression.symbol).irBlock {
val declarations = replacements.getDeclarations(expression.symbol.owner.type.erasedUpperBound)!!
val variables = declarations.leaves.map { irTemporary(irType = it.type) }
// We flatten to temp variables because code can throw an exception otherwise and partially update variables
flattenExpressionTo(expression.value.transform(this@JvmMultiFieldValueClassLowering, null), variables.toGettersAndSetters())
for ((setter, variable) in setters zip variables) {
setter?.invoke(this, Unit, irGet(variable))?.let { +it }
val modifiedExpression = expression.value.transform(this@JvmMultiFieldValueClassLowering, null)
val currentDeclarationReplacementSymbols = valueDeclarationsRemapper.implementationAgnostic(modifiedExpression)?.symbols
?.mapIndexedNotNull { index, symbol -> symbol?.to(index) }?.toMap() ?: emptyMap()
val subValues = flattenExpressionToGetters(
expression = expression.value, // not modified
types = declarations.leaves.map { it.type },
additionalConditionForValue = { (index, value) ->
value is IrGetValue && currentDeclarationReplacementSymbols[value.symbol].let { it == null || it <= index }
}
)
for ((setter, subValue) in setters zip subValues) {
setter?.invoke(this, Unit, subValue)?.let { +it }
}
}
}
@@ -706,22 +843,40 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
)
}
// expression takes not transformed first argument
private fun IrBlockBuilder.flattenExpressionToGetters(
expression: IrExpression,
types: List<IrType>,
additionalConditionForValue: (IndexedValue<IrExpression>) -> Boolean,
): List<IrExpression> {
val variables = types.map { irTemporary(irType = it) }
val temporaryBlock = irBlock {
flattenExpressionTo(expression, variables.toGettersAndSetters())
}
val satisfyingSetVariableSymbols = temporaryBlock.statements.mapIndexed { index, blockStatement ->
(blockStatement as? IrSetValue)?.takeIf { additionalConditionForValue(IndexedValue(index, it.value)) }?.symbol
}
return if (variables.map { it.symbol } == satisfyingSetVariableSymbols) {
temporaryBlock.statements.map { (it as IrSetValue).value }
} else {
+temporaryBlock
variables.map { irGet(it) }
}
}
fun IrBlockBuilder.flattenExpressionTo(
expression: IrExpression, variables: List<Pair<ExpressionGenerator<Unit>, ExpressionSupplier<Unit>>>
) {
valueDeclarationsRemapper.implementationAgnostic(expression)?.virtualFields?.map { it.makeGetter(this, Unit) }?.let {
require(variables.size == it.size)
for ((variable, subExpression) in variables zip it) {
+variable.second(this, Unit, subExpression)
}
return
val declarations = replacements.getDeclarations(expression.type.erasedUpperBound) ?: run {
val constructor = (expression as? IrConstructorCall)?.symbol?.owner ?: return@run null
replacements.getDeclarations(constructor.constructedClass)
}
if (expression.type.isNullable() || !expression.type.isMultiFieldValueClassType()) {
if (expression.type.isNullable() || declarations == null) {
require(variables.size == 1)
+variables.single().second(this, Unit, expression.transform(this@JvmMultiFieldValueClassLowering, null))
return
}
val declarations = replacements.getDeclarations(expression.type.erasedUpperBound)!!
require(variables.size == declarations.leaves.size)
if (expression is IrConstructorCall) {
val constructor = expression.symbol.owner
@@ -734,11 +889,11 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
var curOffset = 0
for ((treeField, argument) in root.fields zip oldArguments) {
val size = when (treeField.node) {
is InternalNode -> replacements.getDeclarations(treeField.node.irClass!!)!!.leaves.size
is InternalNode -> replacements.getDeclarations(treeField.node.irClass)!!.leaves.size
is MultiFieldValueClassTree.Leaf -> 1
}
val subVariables = variables.slice(curOffset until (curOffset + size)).also { curOffset += size }
argument?.let { flattenExpressionTo(it, subVariables) } ?: List(size) { null }
argument?.let { flattenExpressionTo(it, subVariables) }
}
+irCall(declarations.primaryConstructorImpl).apply {
variables.forEachIndexed { index, variable -> putValueArgument(index, variable.first(this@flattenExpressionTo, Unit)) }
@@ -747,6 +902,13 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
}
}
val transformedExpression = expression.transform(this@JvmMultiFieldValueClassLowering, null)
valueDeclarationsRemapper.implementationAgnostic(transformedExpression)?.virtualFields?.map { it.makeGetter(this, Unit) }?.let {
require(variables.size == it.size)
for ((variable, subExpression) in variables zip it) {
+variable.second(this, Unit, subExpression)
}
return
}
if (transformedExpression is IrCall) {
val callee = transformedExpression.symbol.owner
if (callee == declarations.boxMethod) {
@@ -763,10 +925,10 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
return
}
}
(transformedExpression as? IrCall)?.let { makeLeavesGetters(it.symbol.owner) }?.let { geters ->
(transformedExpression as? IrCall)?.let { makeLeavesGetters(it.symbol.owner) }?.let { getters ->
val receiver = irTemporary(transformedExpression.dispatchReceiver)
require(geters.size == variables.size) { "Number of getters must be equal to number of variables" }
for ((variable, getter) in variables zip geters) {
require(getters.size == variables.size) { "Number of getters must be equal to number of variables" }
for ((variable, getter) in variables zip getters) {
+variable.second(this, Unit, irCall(getter).apply { dispatchReceiver = irGet(receiver) })
}
return
@@ -785,43 +947,72 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
}
}
override fun visitStatementContainer(container: IrStatementContainer) {
super.visitStatementContainer(container)
deleteUselessBoxes(container)
override fun visitContainerExpression(expression: IrContainerExpression): IrExpression {
return super.visitContainerExpression(expression).apply { expression.accept(ExtraBoxesRemover(), false) }
}
private fun deleteUselessBoxes(container: IrStatementContainer) {
val statements = container.statements
override fun visitBlockBody(body: IrBlockBody): IrBody {
return super.visitBlockBody(body).apply { body.accept(ExtraBoxesRemover(), true) }
}
private val visitedContainersLastStatement = mutableMapOf<IrStatementContainer, Boolean>()
private inner class ExtraBoxesRemover : IrElementVisitor<Unit, Boolean> {
// Removing box-impl's but not getters because they are auto-generated
fun IrExpression.isBoxCallStatement() = this is IrCall && valueDeclarationsRemapper.implementationAgnostic(this) != null &&
private fun IrExpression.isBoxCallStatement() = this is IrCall && valueDeclarationsRemapper.implementationAgnostic(this) != null &&
List(valueArgumentsCount) { getValueArgument(it) }.all { it == null || it is IrGetField || it is IrGetValue }
fun IrStatement.coercionToUnitArgument() =
private fun IrStatement.coercionToUnitArgument() =
(this as? IrTypeOperatorCall)?.takeIf { it.operator == IrTypeOperator.IMPLICIT_COERCION_TO_UNIT }?.argument
fun IrStatement.isBoxCallStatement(): Boolean {
private fun IrStatement.isBoxCallStatement(): Boolean {
val coercionToUnitArgument = coercionToUnitArgument()
if (coercionToUnitArgument?.isBoxCallStatement() == true || this is IrExpression && this.isBoxCallStatement()) {
return true
}
if (coercionToUnitArgument is IrStatementContainer && (coercionToUnitArgument.statements.lastOrNull() as? IrExpression)?.isBoxCallStatement() == true) {
coercionToUnitArgument.statements.popLast()
if (coercionToUnitArgument is IrStatementContainer) {
coercionToUnitArgument.accept(this@ExtraBoxesRemover, true)
}
return false
}
if (statements.isEmpty()) return
override fun visitElement(element: IrElement, data: Boolean) = Unit
val last = statements.popLast()
statements.removeIf { it.isBoxCallStatement() }
for (statement in statements) {
if (statement is IrStatementContainer && statement.statements.lastOrNull()?.isBoxCallStatement() == true) {
statement.statements.removeLast()
}
override fun visitContainerExpression(expression: IrContainerExpression, data: Boolean) {
visitStatementContainer(expression, data)
}
override fun visitBlockBody(body: IrBlockBody, data: Boolean) {
visitStatementContainer(body, true) // we last body statement is always not used.
}
private fun visitStatementContainer(expression: IrStatementContainer, isInnerContainer: Boolean) {
visitedContainersLastStatement[expression]?.let { visitedLastStatement ->
if (!visitedLastStatement && isInnerContainer) {
visitedContainersLastStatement[expression] = true
expression.statements.lastOrNull()?.let {
if (it.isBoxCallStatement()) {
expression.statements.popLast()
} else {
it.accept(this, true)
}
}
}
return
}
visitedContainersLastStatement[expression] = isInnerContainer
val statementsToRemove = mutableListOf<IrStatement>()
for (i in 0 until expression.statements.size) {
val isInnerStatement = isInnerContainer || i < expression.statements.lastIndex
if (isInnerStatement && expression.statements[i].isBoxCallStatement()) {
statementsToRemove.add(expression.statements[i])
} else {
expression.statements[i].accept(this, isInnerStatement)
}
}
expression.statements.removeAll(statementsToRemove)
}
statements.add(last) // we don't check delete it anyway
}
private fun IrSimpleFunction.isDefaultGetter(field: IrField): Boolean =
@@ -7,14 +7,11 @@ package org.jetbrains.kotlin.backend.jvm.lower
import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
import org.jetbrains.kotlin.backend.common.ir.copyParameterDeclarationsFrom
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.pop
import org.jetbrains.kotlin.backend.common.push
import org.jetbrains.kotlin.backend.jvm.*
import org.jetbrains.kotlin.backend.jvm.ir.isInlineClassType
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.builders.declarations.buildFun
import org.jetbrains.kotlin.ir.builders.irReturn
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.*
@@ -139,7 +136,7 @@ internal abstract class JvmValueClassAbstractLowering(val context: JvmBackendCon
return super.visitReturn(expression)
}
protected open fun visitStatementContainer(container: IrStatementContainer) {
private fun visitStatementContainer(container: IrStatementContainer) {
container.statements.transformFlat { statement ->
if (statement is IrFunction)
transformFunctionFlat(statement)
@@ -148,12 +145,12 @@ internal abstract class JvmValueClassAbstractLowering(val context: JvmBackendCon
}
}
final override fun visitContainerExpression(expression: IrContainerExpression): IrExpression {
override fun visitContainerExpression(expression: IrContainerExpression): IrExpression {
visitStatementContainer(expression)
return expression
}
final override fun visitBlockBody(body: IrBlockBody): IrBody {
override fun visitBlockBody(body: IrBlockBody): IrBody {
visitStatementContainer(body)
return body
}
@@ -173,6 +170,7 @@ internal abstract class JvmValueClassAbstractLowering(val context: JvmBackendCon
): IrSimpleFunction {
val bridgeFunction = createBridgeDeclaration(
function,
replacement,
when {
// If the original function has signature which need mangling we still need to replace it with a mangled version.
(!function.isFakeOverride || function.findInterfaceImplementation(context.state.jvmDefaultMode) != null) &&
@@ -202,9 +200,10 @@ internal abstract class JvmValueClassAbstractLowering(val context: JvmBackendCon
return bridgeFunction
}
private fun IrSimpleFunction.signatureRequiresMangling() =
fullValueParameterList.any { it.type.getRequiresMangling() } ||
context.state.functionsWithInlineClassReturnTypesMangled && returnType.getRequiresMangling() && returnType.isInlineClassType()
private fun IrSimpleFunction.signatureRequiresMangling(includeInline: Boolean = true, includeMFVC: Boolean = true) =
fullValueParameterList.any { it.type.getRequiresMangling(includeInline, includeMFVC) } ||
context.state.functionsWithInlineClassReturnTypesMangled &&
returnType.getRequiresMangling(includeInline = includeInline, includeMFVC = false)
protected fun typedArgumentList(function: IrFunction, expression: IrMemberAccessExpression<*>) = listOfNotNull(
function.dispatchReceiverParameter?.let { it to expression.dispatchReceiver },
@@ -215,20 +214,7 @@ internal abstract class JvmValueClassAbstractLowering(val context: JvmBackendCon
// We may need to add a bridge method for inline class methods with static replacements. Ideally, we'd do this in BridgeLowering,
// but unfortunately this is a special case in the old backend. The bridge method is not marked as such and does not follow the normal
// visibility rules for bridge methods.
private fun createBridgeDeclaration(source: IrSimpleFunction, mangledName: Name) =
context.irFactory.buildFun {
updateFrom(source)
name = mangledName
returnType = source.returnType
}.apply {
copyParameterDeclarationsFrom(source)
annotations = source.annotations
parent = source.parent
// We need to ensure that this bridge has the same attribute owner as its static inline class replacement, since this
// is used in [CoroutineCodegen.isStaticInlineClassReplacementDelegatingCall] to identify the bridge and avoid generating
// a continuation class.
copyAttributes(source)
}
abstract fun createBridgeDeclaration(source: IrSimpleFunction, replacement: IrSimpleFunction, mangledName: Name): IrSimpleFunction
protected abstract fun createBridgeBody(source: IrSimpleFunction, target: IrSimpleFunction, original: IrFunction, inverted: Boolean)
}
@@ -251,7 +251,8 @@ class JvmCachedDeclarations(
defaultImplsRedirections.getOrPut(fakeOverride) {
assert(fakeOverride.isFakeOverride)
val irClass = fakeOverride.parentAsClass
context.irFactory.buildFun {
val mfvcReplacementStructure = context.multiFieldValueClassReplacements.bindingNewFunctionToParameterTemplateStructure
val redirectFunction = context.irFactory.buildFun {
origin = JvmLoweredDeclarationOrigin.SUPER_INTERFACE_METHOD_BRIDGE
name = fakeOverride.name
visibility = fakeOverride.visibility
@@ -275,6 +276,8 @@ class JvmCachedDeclarations(
annotations = fakeOverride.annotations
copyCorrespondingPropertyFrom(fakeOverride)
}
mfvcReplacementStructure[fakeOverride]?.let { mfvcReplacementStructure[redirectFunction] = it }
redirectFunction
}
fun getRepeatedAnnotationSyntheticContainer(annotationClass: IrClass): IrClass =
@@ -7,9 +7,7 @@ package org.jetbrains.kotlin.backend.jvm
import org.jetbrains.kotlin.backend.common.ir.copyTo
import org.jetbrains.kotlin.backend.common.ir.copyTypeParametersFrom
import org.jetbrains.kotlin.backend.jvm.ir.extensionReceiverName
import org.jetbrains.kotlin.backend.jvm.ir.isMultiFieldValueClassType
import org.jetbrains.kotlin.backend.jvm.ir.isStaticValueClassReplacement
import org.jetbrains.kotlin.backend.jvm.ir.*
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
import org.jetbrains.kotlin.ir.builders.declarations.buildConstructor
import org.jetbrains.kotlin.ir.declarations.*
@@ -17,7 +15,6 @@ import org.jetbrains.kotlin.ir.expressions.IrExpressionBody
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.IrTypeSystemContext
import org.jetbrains.kotlin.ir.types.getClass
import org.jetbrains.kotlin.ir.types.isNullable
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.name.Name
@@ -61,8 +58,17 @@ class MemoizedMultiFieldValueClassReplacements(
val type: IrType,
val origin: IrDeclarationOrigin?,
val defaultValue: IrExpressionBody?,
val original: IrValueParameter,
val original: IrValueParameter, // todo don't use it as it is not always correct
) {
constructor(valueParameter: IrValueParameter, origin: IrDeclarationOrigin?) : this(
name = valueParameter.name.asString(),
type = valueParameter.type,
origin = origin,
defaultValue = valueParameter.defaultValue,
original = valueParameter,
)
fun toParameter(irFunction: IrFunction, index: Int): IrValueParameter = original.copyTo(
irFunction = irFunction,
index = index,
@@ -83,7 +89,7 @@ class MemoizedMultiFieldValueClassReplacements(
private fun List<ValueParameterTemplate>.grouped(
originWhenFlattenedAndNotSpecified: IrDeclarationOrigin? = IrDeclarationOrigin.GENERATED_MULTI_FIELD_VALUE_CLASS_PARAMETER
): List<RemappedParameter> = map { parameter ->
val declarations = parameter.type.takeIf { !it.isNullable() }?.getClass()?.let { getDeclarations(it) }
val declarations = parameter.type.takeIf { !it.isNullable() }?.erasedUpperBound?.let { getDeclarations(it) }
?: return@map RemappedParameter.RegularMapping(parameter)
require(!parameter.original.hasDefaultValue()) { "Default parameters values are not supported for multi-field value classes" }
RemappedParameter.MultiFieldValueClassMapping(declarations, declarations.leaves.map { leaf ->
@@ -150,13 +156,7 @@ class MemoizedMultiFieldValueClassReplacements(
newFlattenedParameters.addAll(listOf(template).grouped())
}
newFlattenedParameters += function.valueParameters.drop(function.contextReceiverParametersCount).map {
ValueParameterTemplate(
name = it.name.asString(),
type = it.type,
defaultValue = it.defaultValue,
original = it,
origin = null,
)
ValueParameterTemplate(it, origin = null)
}.grouped()
return newFlattenedParameters
}
@@ -174,17 +174,19 @@ class MemoizedMultiFieldValueClassReplacements(
require(valueParameters.size > 1) { "MFVC must have > 1 fields" }
}
}
abstract val valueParameters: List<ValueParameterTemplate>
}
val bindingParameterTemplateStructure: MutableMap<IrFunction, List<RemappedParameter>> = ConcurrentHashMap()
val bindingOldFunctionToParameterTemplateStructure: MutableMap<IrFunction, List<RemappedParameter>> = ConcurrentHashMap()
val bindingNewFunctionToParameterTemplateStructure: MutableMap<IrFunction, List<RemappedParameter>> = ConcurrentHashMap()
override fun createStaticReplacement(function: IrFunction): IrSimpleFunction =
buildReplacement(function, JvmLoweredDeclarationOrigin.STATIC_MULTI_FIELD_VALUE_CLASS_REPLACEMENT, noFakeOverride = true) {
originalFunctionForStaticReplacement[this] = function
val newFlattenedParameters = makeGroupedValueParametersFrom(function, includeDispatcherReceiver = true)
bindingParameterTemplateStructure[function] = newFlattenedParameters
bindingOldFunctionToParameterTemplateStructure[function] = newFlattenedParameters
bindingNewFunctionToParameterTemplateStructure[this] = newFlattenedParameters
valueParameters = makeValueParametersFromTemplate(newFlattenedParameters)
}
@@ -193,22 +195,18 @@ class MemoizedMultiFieldValueClassReplacements(
dispatchReceiverParameter = function.dispatchReceiverParameter?.copyTo(this, index = -1)
val newFlattenedParameters = makeGroupedValueParametersFrom(function, includeDispatcherReceiver = false)
val receiver = dispatchReceiverParameter
val receiverTemplate = if (receiver != null) ValueParameterTemplate(
name = receiver.name.asString(),
type = receiver.type,
origin = receiver.origin,
defaultValue = receiver.defaultValue,
original = receiver,
) else null
bindingParameterTemplateStructure[function] =
val receiverTemplate = if (receiver != null) ValueParameterTemplate(receiver, origin = receiver.origin) else null
val remappedParameters =
if (receiverTemplate != null) listOf(RemappedParameter.RegularMapping(receiverTemplate)) + newFlattenedParameters else newFlattenedParameters
bindingOldFunctionToParameterTemplateStructure[function] = remappedParameters
bindingNewFunctionToParameterTemplateStructure[this] = remappedParameters
valueParameters = makeValueParametersFromTemplate(newFlattenedParameters)
}
private fun createConstructorReplacement(@Suppress("UNUSED_PARAMETER") constructor: IrConstructor): IrConstructor {
val newFlattenedParameters = makeGroupedValueParametersFrom(constructor, includeDispatcherReceiver = false)
bindingParameterTemplateStructure[constructor] = newFlattenedParameters
return irFactory.buildConstructor {
bindingOldFunctionToParameterTemplateStructure[constructor] = newFlattenedParameters
val newConstructor = irFactory.buildConstructor {
updateFrom(constructor)
returnType = constructor.returnType
}.apply {
@@ -218,6 +216,8 @@ class MemoizedMultiFieldValueClassReplacements(
parent = constructor.parent
originalConstructorForConstructorReplacement[this] = constructor
}
bindingNewFunctionToParameterTemplateStructure[newConstructor] = newFlattenedParameters
return newConstructor
}
private fun createGetterReplacement(function: IrFunction): IrSimpleFunction {
@@ -227,14 +227,10 @@ class MemoizedMultiFieldValueClassReplacements(
val newGetter = declarations.properties[node]!!.getter!!
originalFunctionForMethodReplacement[newGetter] = function
val receiver = function.dispatchReceiverParameter!!
val receiverTemplate = ValueParameterTemplate(
name = receiver.name.asString(),
type = receiver.type,
origin = receiver.origin,
defaultValue = receiver.defaultValue,
original = receiver
)
bindingParameterTemplateStructure[function] = listOf(RemappedParameter.RegularMapping(receiverTemplate))
val receiverTemplate = ValueParameterTemplate(receiver, origin = receiver.origin)
val parameterRemapping = listOf(RemappedParameter.RegularMapping(receiverTemplate))
bindingOldFunctionToParameterTemplateStructure[function] = parameterRemapping
bindingNewFunctionToParameterTemplateStructure[newGetter] = parameterRemapping
return newGetter
}
@@ -261,7 +257,9 @@ class MemoizedMultiFieldValueClassReplacements(
createStaticReplacement(function)
}
function is IrSimpleFunction && !function.isFromJava() &&
function.fullValueParameterList.any { it.type.isMultiFieldValueClassType() && !it.type.isNullable() } ->
function.fullValueParameterList.any { it.type.isMultiFieldValueClassType() && !it.type.isNullable() } &&
!(function.isFakeOverride &&
bindingOldFunctionToParameterTemplateStructure[findSuperDeclaration(function, false, context.state.jvmDefaultMode)] == null)->
createMethodReplacement(function)
else -> null
}
@@ -26,7 +26,11 @@ import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrGetField
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.IrTypeSystemContext
import org.jetbrains.kotlin.ir.types.isNullable
import org.jetbrains.kotlin.ir.types.isSubtypeOf
import org.jetbrains.kotlin.ir.util.constructedClass
import org.jetbrains.kotlin.ir.util.constructors
import org.jetbrains.kotlin.ir.util.defaultType
@@ -36,8 +40,8 @@ import org.jetbrains.kotlin.resolve.InlineClassDescriptorResolver
sealed class MultiFieldValueClassTree<out TI, out TL> {
abstract val type: IrType
val irClass: IrClass?
get() = type.getClass()
val irClass: IrClass
get() = type.erasedUpperBound
companion object {
@JvmStatic
@@ -56,7 +60,7 @@ sealed class MultiFieldValueClassTree<out TI, out TL> {
fun create(type: IrType, replacements: MemoizedMultiFieldValueClassReplacements) = create(type, Unit, Unit, replacements)
}
data class Leaf<out TL>(override val type: IrType, val leafValue: TL) : MultiFieldValueClassTree<Nothing, TL>() {
class Leaf<out TL>(override val type: IrType, val leafValue: TL) : MultiFieldValueClassTree<Nothing, TL>() {
init {
require(type.isNullable() || !type.isMultiFieldValueClassType())
}
@@ -64,7 +68,7 @@ sealed class MultiFieldValueClassTree<out TI, out TL> {
fun <RL> map(transformLeaf: Leaf<TL>.(TL) -> RL) = Leaf(type, transformLeaf(leafValue))
}
data class InternalNode<out TI, out TL> internal constructor(
class InternalNode<out TI, out TL> internal constructor(
override val type: IrType, val internalNodeValue: TI, val fields: List<TreeField<TI, TL>>
) : MultiFieldValueClassTree<TI, TL>() {
constructor(
@@ -84,7 +88,7 @@ sealed class MultiFieldValueClassTree<out TI, out TL> {
}
})
data class TreeField<out TI, out TL>(
class TreeField<out TI, out TL>(
val name: Name, val type: IrType, val visibility: DescriptorVisibility, val annotations: List<IrConstructorCall>,
val node: MultiFieldValueClassTree<TI, TL>
) {
@@ -192,7 +196,7 @@ class MultiFieldValueClassSpecificDeclarations(
private fun makeName() = Name.guessByFirstCharacter(parts.joinToString("$"))
})
}
init {
require(nodeFullNames.size == nodeFullNames.values.distinct().size) { "Ambiguous names found: ${nodeFullNames.values}" }
}
@@ -219,6 +223,9 @@ class MultiFieldValueClassSpecificDeclarations(
}
val oldPrimaryConstructor = valueClass.primaryConstructor ?: error("Value classes have primary constructors")
private val oldFields = replacements.getOldFields(valueClass)
val oldProperties = oldFields.map { it.correspondingPropertySymbol!!.owner }.associateBy { it.name }
val fields = leaves.map { leaf ->
irFactory.buildField {
@@ -279,6 +286,7 @@ class MultiFieldValueClassSpecificDeclarations(
type = it.type,
makeGetter = { receiver: IrValueParameter -> irGetField(irGet(receiver), it) },
assigner = { receiver: IrValueParameter, value: IrExpression -> irSetField(irGet(receiver), it, value) },
symbol = null,
)
}
)
@@ -377,17 +385,21 @@ class MultiFieldValueClassSpecificDeclarations(
val properties: Map<MultiFieldValueClassTree<Unit, Unit>, IrProperty> =
selfImplementationAgnosticDeclarations.nodeToExpressionGetters.filterKeys { it in nodeFullNames }.mapValues { (node, getter) ->
val propertyName = nodeFullNames[node]!!
val overrideable = oldProperties[propertyName]
irFactory.buildProperty {
name = nodeFullNames[node]!!
name = propertyName
origin = IrDeclarationOrigin.GENERATED_MULTI_FIELD_VALUE_CLASS_MEMBER
visibility = gettersVisibilities[node]!!
}.apply {
annotations = gettersAnnotations[node]!!
overrideable?.overriddenSymbols?.let { overriddenSymbols = it }
parent = valueClass
addGetter {
returnType = node.type
origin = IrDeclarationOrigin.GENERATED_MULTI_FIELD_VALUE_CLASS_MEMBER
}.apply {
overrideable?.getter?.overriddenSymbols?.let { overriddenSymbols = it }
createDispatchReceiverParameter()
body = with(context.createIrBuilder(this.symbol)) {
irExprBody(getter(this, dispatchReceiverParameter!!))
@@ -396,11 +408,17 @@ class MultiFieldValueClassSpecificDeclarations(
}
}
data class VirtualProperty<in T>(val type: IrType, val makeGetter: ExpressionGenerator<T>, val assigner: ExpressionSupplier<T>?) {
data class VirtualProperty<in T>(
val type: IrType,
val makeGetter: ExpressionGenerator<T>,
val assigner: ExpressionSupplier<T>?,
val symbol: IrValueSymbol?
) {
constructor(declaration: IrValueDeclaration) : this(
declaration.type,
{ irGet(declaration) },
if (declaration.isAssignable) { _, value -> irSet(declaration, value) } else null,
declaration.symbol,
)
val isAssignable: Boolean
@@ -410,6 +428,7 @@ class MultiFieldValueClassSpecificDeclarations(
type = type,
makeGetter = { makeGetter(f(it)) },
assigner = assigner?.let { assigner -> { additionalParam, value -> assigner(f(additionalParam), value) } },
symbol = symbol,
)
}
@@ -427,7 +446,8 @@ class MultiFieldValueClassSpecificDeclarations(
*/
inner class ImplementationAgnostic<T>(val virtualFields: List<VirtualProperty<T>>) {
val regularDeclarations = this@MultiFieldValueClassSpecificDeclarations
val symbols = virtualFields.map { it.symbol }
fun <R> map(f: (R) -> T) = ImplementationAgnostic(virtualFields.map { it.map(f) })
init {
@@ -444,7 +464,7 @@ class MultiFieldValueClassSpecificDeclarations(
indexesByInternalNode.mapValues { (node, indexes) ->
{ additionalParameter ->
val arguments = virtualFields.slice(indexes).map { it.makeGetter(this, additionalParameter) }
val innerDeclarations = replacements.getDeclarations(node.irClass!!)!!
val innerDeclarations = replacements.getDeclarations(node.irClass)!!
irCall(innerDeclarations.boxMethod).apply {
for (i in arguments.indices) {
putValueArgument(i, arguments[i])
@@ -465,7 +485,7 @@ class MultiFieldValueClassSpecificDeclarations(
else -> nodeToExpressionGetters[field.node]!! to when (field.node) {
is Leaf -> null
is InternalNode -> {
val irClass = field.node.irClass!!
val irClass = field.node.irClass
val declarations = replacements.getDeclarations(irClass)!!
declarations.ImplementationAgnostic(nodeToSymbols[field.node]!!)
}
@@ -0,0 +1,26 @@
// WITH_STDLIB
// TARGET_BACKEND: JVM_IR
// WORKS_WHEN_VALUE_CLASS
// LANGUAGE: +ValueClasses
@JvmInline
value class DPoint(val x: Double, val y: Double)
class A(var x: DPoint) {
init { x = DPoint(2.0, 3.0) }
}
class B() {
var a = DPoint(4.0, 5.0)
val b = a
init { a = DPoint(6.0, 7.0) }
val c = a
}
fun box(): String {
require(A(DPoint(0.0, 1.0)).x == DPoint(2.0, 3.0)) { "No init used" }
require(B().a == DPoint(6.0, 7.0)) { "No init used" }
require(B().b == DPoint(4.0, 5.0)) { "Wrong init order used" }
require(B().c == DPoint(6.0, 7.0)) { "Wrong init order used" }
return "OK"
}
@@ -66,7 +66,7 @@ fun <T : List<Int>> h(r: R<T>) {
g(r.z)
f(r)
r
C(2, B(3U), "") // todo fix box
C(2, B(3U), "")
D(C(2, B(3U), ""))
val x = D(C(2, B(3U), ""))
var y = D(C(4, B(5U), "1"))
@@ -172,4 +172,4 @@ fun equalsChecks(left: R<List<Int>>, right: R<List<Int>>) {
// todo add default parameters
fun box() = "OK"//.also { h(R(1, 2U, E(D(C(3, B(4U), "5"))), A(listOf(listOf(6))))) }
fun box() = "OK"
@@ -1,7 +1,7 @@
@kotlin.jvm.JvmInline
@kotlin.Metadata
public final class A {
// source: 'simple.kt'
// source: 'complex.kt'
private final @org.jetbrains.annotations.NotNull field x: java.util.List
private synthetic method <init>(p0: java.util.List): void
public synthetic final static method box-impl(p0: java.util.List): A
@@ -20,7 +20,7 @@ public final class A {
@kotlin.jvm.JvmInline
@kotlin.Metadata
public final class B {
// source: 'simple.kt'
// source: 'complex.kt'
private final field x: int
private synthetic method <init>(p0: int): void
public synthetic final static method box-impl(p0: int): B
@@ -38,7 +38,7 @@ public final class B {
@kotlin.Metadata
public final class Base1$DefaultImpls {
// source: 'simple.kt'
// source: 'complex.kt'
public static @org.jetbrains.annotations.NotNull method getFakeOverrideMFVC(@org.jetbrains.annotations.NotNull p0: Base1): R
public static method getFakeOverrideRegular(@org.jetbrains.annotations.NotNull p0: Base1): int
public final inner class Base1$DefaultImpls
@@ -46,7 +46,7 @@ public final class Base1$DefaultImpls {
@kotlin.Metadata
public interface Base1 {
// source: 'simple.kt'
// source: 'complex.kt'
public abstract @org.jetbrains.annotations.NotNull method getFakeOverrideMFVC(): R
public abstract method getFakeOverrideRegular(): int
public final inner class Base1$DefaultImpls
@@ -54,20 +54,20 @@ public interface Base1 {
@kotlin.Metadata
public interface Base2 {
// source: 'simple.kt'
// source: 'complex.kt'
public abstract @org.jetbrains.annotations.NotNull method getL(): R
public abstract method setL-Y_3tvh0(p0: int, p1: int, p2: int, p3: int, @org.jetbrains.annotations.NotNull p4: java.lang.String, @org.jetbrains.annotations.NotNull p5: java.util.List): void
}
@kotlin.Metadata
public interface Base3 {
// source: 'simple.kt'
// source: 'complex.kt'
public abstract @org.jetbrains.annotations.NotNull method getZ(): E
}
@kotlin.Metadata
public interface Base4 {
// source: 'simple.kt'
// source: 'complex.kt'
public abstract method getL(): java.lang.Object
public abstract method setL(p0: java.lang.Object): void
}
@@ -75,7 +75,7 @@ public interface Base4 {
@kotlin.jvm.JvmInline
@kotlin.Metadata
public final class C {
// source: 'simple.kt'
// source: 'complex.kt'
private field x: int
private field y: int
private @org.jetbrains.annotations.NotNull field z: java.lang.String
@@ -97,10 +97,26 @@ public final class C {
public synthetic final method unbox-impl2(): java.lang.String
}
@kotlin.Metadata
public final class ComplexKt {
// source: 'complex.kt'
public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String
public final static method equalsChecks-GPBa7dw-yJnZWq8(p0: int, p1: int, p2: int, p3: int, @org.jetbrains.annotations.NotNull p4: java.lang.String, @org.jetbrains.annotations.NotNull p5: java.util.List, p6: int, p7: int, p8: int, p9: int, @org.jetbrains.annotations.NotNull p10: java.lang.String, @org.jetbrains.annotations.NotNull p11: java.util.List): void
public final static method f-sUp7gFk-Y_3tvh0(p0: int, p1: int, p2: int, p3: int, @org.jetbrains.annotations.NotNull p4: java.lang.String, @org.jetbrains.annotations.NotNull p5: java.util.List): void
public final static method g-sUp7gFk-ZTiL54U(p0: int, p1: int, @org.jetbrains.annotations.NotNull p2: java.lang.String): void
public final static method h-sUp7gFk-Y_3tvh0(p0: int, p1: int, p2: int, p3: int, @org.jetbrains.annotations.NotNull p4: java.lang.String, @org.jetbrains.annotations.NotNull p5: java.util.List): void
public final static method h1(): void
public final static @org.jetbrains.annotations.NotNull method inlined-OsBMiQA(p0: int, p1: int, p2: int): D
public final static @org.jetbrains.annotations.NotNull method notInlined-OsBMiQA(p0: int, p1: int, p2: int): D
public final static method reuseBoxed(@org.jetbrains.annotations.NotNull p0: java.util.List): void
public final static method supply(p0: boolean): void
public final static method testVars(@org.jetbrains.annotations.NotNull p0: NotInlined): void
}
@kotlin.jvm.JvmInline
@kotlin.Metadata
public final class D {
// source: 'simple.kt'
// source: 'complex.kt'
private field x$x: int
private field x$y: int
private @org.jetbrains.annotations.NotNull field x$z: java.lang.String
@@ -127,7 +143,7 @@ public final class D {
@kotlin.jvm.JvmInline
@kotlin.Metadata
public final class E {
// source: 'simple.kt'
// source: 'complex.kt'
private field x$x$x: int
private field x$x$y: int
private @org.jetbrains.annotations.NotNull field x$x$z: java.lang.String
@@ -155,22 +171,22 @@ public final class E {
@kotlin.Metadata
public final class NotInlined {
// source: 'simple.kt'
// source: 'complex.kt'
private @org.jetbrains.annotations.NotNull field l$t: java.util.List
private field l$x: int
private field l$y: int
private field l$z$x$x$x$1: int
private field l$z$x$x$x: int
private field l$z$x$x$y: int
private @org.jetbrains.annotations.NotNull field l$z$x$x$z: java.lang.String
private @org.jetbrains.annotations.NotNull field withNonTrivialGettersWithBF$t: java.util.List
private field withNonTrivialGettersWithBF$x: int
private field withNonTrivialGettersWithBF$y: int
private field withNonTrivialGettersWithBF$z$x$x$x$1: int
private field withNonTrivialGettersWithBF$z$x$x$x: int
private field withNonTrivialGettersWithBF$z$x$x$y: int
private @org.jetbrains.annotations.NotNull field withNonTrivialGettersWithBF$z$x$x$z: java.lang.String
private @org.jetbrains.annotations.NotNull field withNonTrivialSettersWithBF$t: java.util.List
private field withNonTrivialSettersWithBF$x: int
private field withNonTrivialSettersWithBF$y: int
private field withNonTrivialSettersWithBF$z$x$x$x$1: int
private field withNonTrivialSettersWithBF$z$x$x$x: int
private field withNonTrivialSettersWithBF$z$x$x$y: int
private @org.jetbrains.annotations.NotNull field withNonTrivialSettersWithBF$z$x$x$z: java.lang.String
@@ -180,6 +196,7 @@ public final class NotInlined {
public @org.jetbrains.annotations.NotNull method getFakeOverrideMFVC(): R
public method getFakeOverrideRegular(): int
public final @org.jetbrains.annotations.NotNull method getL$t(): java.util.List
public final method getL$x(): int
public final method getL$y(): int
public final method getL$z$x$x$x(): int
public final method getL$z$x$x$y(): int
@@ -205,10 +222,10 @@ public final class NotInlined {
@kotlin.jvm.JvmInline
@kotlin.Metadata
public final class R {
// source: 'simple.kt'
// source: 'complex.kt'
private @org.jetbrains.annotations.NotNull field t: java.util.List
private field x: int
private field y: int
private field z$x$x$x$1: int
private field z$x$x$x: int
private field z$x$x$y: int
private @org.jetbrains.annotations.NotNull field z$x$x$z: java.lang.String
@@ -223,6 +240,7 @@ public final class R {
public method getFakeOverrideRegular(): int
public static method getFakeOverrideRegular-impl(p0: int, p1: int, p2: int, p3: int, @org.jetbrains.annotations.NotNull p4: java.lang.String, @org.jetbrains.annotations.NotNull p5: java.util.List): int
public final @org.jetbrains.annotations.NotNull method getT(): java.util.List
public final method getX(): int
public final method getY(): int
public final method getZ$x$x$x(): int
public final method getZ$x$x$y(): int
@@ -241,19 +259,3 @@ public final class R {
public synthetic final method unbox-impl4(): java.lang.String
public synthetic final method unbox-impl5(): java.util.List
}
@kotlin.Metadata
public final class SimpleKt {
// source: 'simple.kt'
public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String
public final static method equalsChecks-GPBa7dw-yJnZWq8(p0: int, p1: int, p2: int, p3: int, @org.jetbrains.annotations.NotNull p4: java.lang.String, @org.jetbrains.annotations.NotNull p5: java.util.List, p6: int, p7: int, p8: int, p9: int, @org.jetbrains.annotations.NotNull p10: java.lang.String, @org.jetbrains.annotations.NotNull p11: java.util.List): void
public final static method f-sUp7gFk-Y_3tvh0(p0: int, p1: int, p2: int, p3: int, @org.jetbrains.annotations.NotNull p4: java.lang.String, @org.jetbrains.annotations.NotNull p5: java.util.List): void
public final static method g-sUp7gFk-ZTiL54U(p0: int, p1: int, @org.jetbrains.annotations.NotNull p2: java.lang.String): void
public final static method h-sUp7gFk-Y_3tvh0(p0: int, p1: int, p2: int, p3: int, @org.jetbrains.annotations.NotNull p4: java.lang.String, @org.jetbrains.annotations.NotNull p5: java.util.List): void
public final static method h1(): void
public final static @org.jetbrains.annotations.NotNull method inlined-OsBMiQA(p0: int, p1: int, p2: int): D
public final static @org.jetbrains.annotations.NotNull method notInlined-OsBMiQA(p0: int, p1: int, p2: int): D
public final static method reuseBoxed(@org.jetbrains.annotations.NotNull p0: java.util.List): void
public final static method supply(p0: boolean): void
public final static method testVars(@org.jetbrains.annotations.NotNull p0: NotInlined): void
}
+277
View File
@@ -0,0 +1,277 @@
// WITH_STDLIB
// TARGET_BACKEND: JVM_IR
// WORKS_WHEN_VALUE_CLASS
// LANGUAGE: +ValueClasses
interface AbstractPoint<T> {
val x: T
val y: T
}
@JvmInline
value class DPoint(override val x: Double, override val y: Double): AbstractPoint<Double>
interface GenericMFVCHolder<T> {
var p: T
var p1: T
}
interface GenericMFVCHolderWithMFVCUpperBound<T : DPoint> {
var p: T
var p1: T
}
interface ReifiedMFVCHolder {
var p: DPoint
var p1: DPoint
}
data class DataClassException(val value: Any?): Exception()
interface GenericMFVCHolderWithImpls<T> {
var p: T
get() = throw DataClassException(1)
set(value) = throw DataClassException(2 to value)
var p1: T
get() = throw DataClassException(3)
set(value) = throw DataClassException(4 to value)
}
interface GenericMFVCHolderWithMFVCUpperBoundWithImpls<T : DPoint> {
var p: T
get() = throw DataClassException(5)
set(value) = throw DataClassException(6 to value)
var p1: T
get() = throw DataClassException(7)
set(value) = throw DataClassException(8 to value)
}
interface ReifiedMFVCHolderWithImpls {
var p: DPoint
get() = throw DataClassException(9)
set(value) = throw DataClassException(10 to value)
var p1: DPoint
get() = throw DataClassException(11)
set(value) = throw DataClassException(12 to value)
}
class RealOverride(override var p: DPoint) : GenericMFVCHolder<DPoint>, ReifiedMFVCHolder, GenericMFVCHolderWithMFVCUpperBound<DPoint> {
override var p1: DPoint
get() = throw DataClassException(13)
set(value) = throw DataClassException(14 to value)
}
class GenericFakeOverride : GenericMFVCHolderWithImpls<DPoint>
class ReifiedFakeOverride : ReifiedMFVCHolderWithImpls
class GenericFakeOverrideWithMFVCUpperBound : GenericMFVCHolderWithMFVCUpperBoundWithImpls<DPoint>
@JvmInline
value class GenericFakeOverrideMFVC(val field1: Double, val field2: Double) : GenericMFVCHolderWithImpls<DPoint>
@JvmInline
value class ReifiedFakeOverrideMFVC(val field1: Double, val field2: Double) : ReifiedMFVCHolderWithImpls
@JvmInline
value class GenericFakeOverrideMFVCWithMFVCUpperBound(val field1: Double, val field2: Double) : GenericMFVCHolderWithMFVCUpperBoundWithImpls<DPoint>
interface SomePointInterface<T> {
var somethingRegular: Int
var somethingGeneric: T
var somethingMFVC: DPoint
}
interface SomePointInterfaceWithMFVCBound<T : DPoint> {
var somethingRegular: Int
var somethingGeneric: T
var somethingMFVC: DPoint
}
@JvmInline
value class DPointWithInterface(val x: Double, val y: Double) : SomePointInterface<DPoint>, SomePointInterfaceWithMFVCBound<DPoint> {
override var somethingGeneric: DPoint
get() = throw DataClassException(15)
set(value) = throw DataClassException(16 to value)
override var somethingMFVC: DPoint
get() = throw DataClassException(17)
set(value) = throw DataClassException(18 to value)
override var somethingRegular: Int
get() = throw DataClassException(19)
set(value) = throw DataClassException(20 to value)
}
interface AbstractSegment<T> {
val p1: T
val p2: T
}
@JvmInline
value class DSegment(override val p1: DPoint, override val p2: DPoint): AbstractSegment<DPoint>
fun <T> equal(expected: () -> T, actual: () -> T) {
val expectedResult = runCatching { expected() }
val actualResult = runCatching { actual() }
require(expectedResult == actualResult) { "Expected: $expectedResult\nActual: $actualResult" }
}
fun box(): String {
val dPoint = DPoint(1.0, 2.0)
equal({ dPoint.toString() }, { (dPoint as Any).toString() })
equal({ dPoint.equals(dPoint) }, { dPoint.equals(dPoint as Any) })
equal({ dPoint.equals(dPoint) }, { (dPoint as Any).equals(dPoint) })
equal({ dPoint.equals(dPoint) }, { dPoint.equals(dPoint as Any) })
equal({ dPoint.equals(dPoint) }, { (dPoint as Any).equals(dPoint as Any) })
val otherDPoint = DPoint(3.0, 4.0)
equal({ dPoint.equals(otherDPoint) }, { dPoint.equals(otherDPoint as Any) })
equal({ dPoint.equals(otherDPoint) }, { (dPoint as Any).equals(otherDPoint) })
equal({ dPoint.equals(otherDPoint) }, { dPoint.equals(otherDPoint as Any) })
equal({ dPoint.equals(otherDPoint) }, { (dPoint as Any).equals(otherDPoint as Any) })
equal({ dPoint.hashCode() }, { (dPoint as Any).hashCode() })
equal({ dPoint.x }, { (dPoint as AbstractPoint<Double>).x })
equal({ dPoint.y }, { (dPoint as AbstractPoint<Double>).y })
val realOverride = RealOverride(dPoint)
equal({ realOverride.p }, { (realOverride as GenericMFVCHolder<DPoint>).p })
equal({ realOverride.p1 }, { (realOverride as GenericMFVCHolder<DPoint>).p1 })
equal({ realOverride.p }, { (realOverride as ReifiedMFVCHolder).p })
equal({ realOverride.p1 }, { (realOverride as ReifiedMFVCHolder).p1 })
equal({ realOverride.p }, { (realOverride as GenericMFVCHolderWithMFVCUpperBound<DPoint>).p })
equal({ realOverride.p1 }, { (realOverride as GenericMFVCHolderWithMFVCUpperBound<DPoint>).p1 })
equal({ realOverride.p = dPoint }, { (realOverride as GenericMFVCHolder<DPoint>).p = dPoint })
equal({ realOverride.p1 = dPoint }, { (realOverride as GenericMFVCHolder<DPoint>).p1 = dPoint })
equal({ realOverride.p = dPoint }, { (realOverride as ReifiedMFVCHolder).p = dPoint })
equal({ realOverride.p1 = dPoint }, { (realOverride as ReifiedMFVCHolder).p1 = dPoint })
equal({ realOverride.p = dPoint }, { (realOverride as GenericMFVCHolderWithMFVCUpperBound<DPoint>).p = dPoint })
equal({ realOverride.p1 = dPoint }, { (realOverride as GenericMFVCHolderWithMFVCUpperBound<DPoint>).p1 = dPoint })
val genericFakeOverride = GenericFakeOverride()
equal({ genericFakeOverride.p }, { (genericFakeOverride as GenericMFVCHolderWithImpls<DPoint>).p })
equal({ genericFakeOverride.p1 }, { (genericFakeOverride as GenericMFVCHolderWithImpls<DPoint>).p1 })
val reifiedFakeOverride = ReifiedFakeOverride()
equal({ reifiedFakeOverride.p }, { (reifiedFakeOverride as ReifiedMFVCHolderWithImpls).p })
equal({ reifiedFakeOverride.p1 }, { (reifiedFakeOverride as ReifiedMFVCHolderWithImpls).p1 })
val genericFakeOverrideWithMFVCUpperBound = GenericFakeOverrideWithMFVCUpperBound()
equal(
{ genericFakeOverrideWithMFVCUpperBound.p },
{ (genericFakeOverrideWithMFVCUpperBound as GenericMFVCHolderWithMFVCUpperBoundWithImpls<DPoint>).p }
)
equal(
{ genericFakeOverrideWithMFVCUpperBound.p1 },
{ (genericFakeOverrideWithMFVCUpperBound as GenericMFVCHolderWithMFVCUpperBoundWithImpls<DPoint>).p1 }
)
equal({ genericFakeOverride.p = dPoint }, { (genericFakeOverride as GenericMFVCHolderWithImpls<DPoint>).p = dPoint })
equal({ genericFakeOverride.p1 = dPoint }, { (genericFakeOverride as GenericMFVCHolderWithImpls<DPoint>).p1 = dPoint })
equal({ reifiedFakeOverride.p = dPoint }, { (reifiedFakeOverride as ReifiedMFVCHolderWithImpls).p = dPoint })
equal({ reifiedFakeOverride.p1 = dPoint }, { (reifiedFakeOverride as ReifiedMFVCHolderWithImpls).p1 = dPoint })
equal(
{ genericFakeOverrideWithMFVCUpperBound.p = dPoint },
{ (genericFakeOverrideWithMFVCUpperBound as GenericMFVCHolderWithMFVCUpperBoundWithImpls<DPoint>).p = dPoint }
)
equal(
{ genericFakeOverrideWithMFVCUpperBound.p1 = dPoint },
{ (genericFakeOverrideWithMFVCUpperBound as GenericMFVCHolderWithMFVCUpperBoundWithImpls<DPoint>).p1 = dPoint }
)
val genericFakeOverrideMFVC = GenericFakeOverrideMFVC(1.0, 2.0)
equal({ genericFakeOverrideMFVC.p }, { (genericFakeOverrideMFVC as GenericMFVCHolderWithImpls<DPoint>).p })
equal({ genericFakeOverrideMFVC.p1 }, { (genericFakeOverrideMFVC as GenericMFVCHolderWithImpls<DPoint>).p1 })
val reifiedFakeOverrideMFVC = ReifiedFakeOverrideMFVC(1.0, 2.0)
equal({ reifiedFakeOverrideMFVC.p }, { (reifiedFakeOverrideMFVC as ReifiedMFVCHolderWithImpls).p })
equal({ reifiedFakeOverrideMFVC.p1 }, { (reifiedFakeOverrideMFVC as ReifiedMFVCHolderWithImpls).p1 })
val genericFakeOverrideMFVCWithMFVCUpperBound = GenericFakeOverrideMFVCWithMFVCUpperBound(1.0, 2.0)
equal(
{ genericFakeOverrideMFVCWithMFVCUpperBound.p },
{ (genericFakeOverrideMFVCWithMFVCUpperBound as GenericMFVCHolderWithMFVCUpperBoundWithImpls<DPoint>).p },
)
equal(
{ genericFakeOverrideMFVCWithMFVCUpperBound.p1 },
{ (genericFakeOverrideMFVCWithMFVCUpperBound as GenericMFVCHolderWithMFVCUpperBoundWithImpls<DPoint>).p1 },
)
equal({ genericFakeOverrideMFVC.p = dPoint }, { (genericFakeOverrideMFVC as GenericMFVCHolderWithImpls<DPoint>).p = dPoint })
equal({ genericFakeOverrideMFVC.p1 = dPoint }, { (genericFakeOverrideMFVC as GenericMFVCHolderWithImpls<DPoint>).p1 = dPoint })
equal({ reifiedFakeOverrideMFVC.p = dPoint }, { (reifiedFakeOverrideMFVC as ReifiedMFVCHolderWithImpls).p = dPoint })
equal({ reifiedFakeOverrideMFVC.p1 = dPoint }, { (reifiedFakeOverrideMFVC as ReifiedMFVCHolderWithImpls).p1 = dPoint })
equal(
{ genericFakeOverrideMFVCWithMFVCUpperBound.p = dPoint },
{ (genericFakeOverrideMFVCWithMFVCUpperBound as GenericMFVCHolderWithMFVCUpperBoundWithImpls<DPoint>).p = dPoint },
)
equal(
{ genericFakeOverrideMFVCWithMFVCUpperBound.p1 = dPoint },
{ (genericFakeOverrideMFVCWithMFVCUpperBound as GenericMFVCHolderWithMFVCUpperBoundWithImpls<DPoint>).p1 = dPoint },
)
val dPointWithInterface = DPointWithInterface(1.0, 2.0)
equal({ dPointWithInterface.somethingGeneric }, { (dPointWithInterface as SomePointInterface<DPoint>).somethingGeneric })
equal({ dPointWithInterface.somethingRegular }, { (dPointWithInterface as SomePointInterface<DPoint>).somethingRegular })
equal({ dPointWithInterface.somethingMFVC }, { (dPointWithInterface as SomePointInterface<DPoint>).somethingMFVC })
equal({ dPointWithInterface.somethingGeneric }, { (dPointWithInterface as SomePointInterfaceWithMFVCBound<DPoint>).somethingGeneric })
equal({ dPointWithInterface.somethingRegular }, { (dPointWithInterface as SomePointInterfaceWithMFVCBound<DPoint>).somethingRegular })
equal({ dPointWithInterface.somethingMFVC }, { (dPointWithInterface as SomePointInterfaceWithMFVCBound<DPoint>).somethingMFVC })
equal(
{ dPointWithInterface.somethingGeneric = dPoint },
{ (dPointWithInterface as SomePointInterface<DPoint>).somethingGeneric = dPoint }
)
equal({ dPointWithInterface.somethingRegular = 1 }, { (dPointWithInterface as SomePointInterface<DPoint>).somethingRegular = 1 })
equal({ dPointWithInterface.somethingMFVC = dPoint }, { (dPointWithInterface as SomePointInterface<DPoint>).somethingMFVC = dPoint })
equal(
{ dPointWithInterface.somethingGeneric = dPoint },
{ (dPointWithInterface as SomePointInterfaceWithMFVCBound<DPoint>).somethingGeneric = dPoint }
)
equal(
{ dPointWithInterface.somethingRegular = 2 },
{ (dPointWithInterface as SomePointInterfaceWithMFVCBound<DPoint>).somethingRegular = 2 }
)
equal(
{ dPointWithInterface.somethingMFVC = dPoint},
{ (dPointWithInterface as SomePointInterfaceWithMFVCBound<DPoint>).somethingMFVC = dPoint }
)
val dSegment = DSegment(dPoint, otherDPoint)
equal({ dPoint }, { dSegment.p1 })
equal({ otherDPoint }, { dSegment.p2 })
equal({ dPoint.x }, { dSegment.p1.x })
equal({ otherDPoint.x }, { dSegment.p2.x })
equal({ dPoint.y }, { dSegment.p1.y })
equal({ otherDPoint.y }, { dSegment.p2.y })
equal({ dSegment.p1 }, { (dSegment as AbstractSegment<DPoint>).p1 })
equal({ dSegment.p2 }, { (dSegment as AbstractSegment<DPoint>).p2 })
equal({ dSegment.p1.x }, { (dSegment as AbstractSegment<DPoint>).p1.x })
equal({ dSegment.p2.x }, { (dSegment as AbstractSegment<DPoint>).p2.x })
equal({ dSegment.p1.y }, { (dSegment as AbstractSegment<DPoint>).p1.y })
equal({ dSegment.p2.y }, { (dSegment as AbstractSegment<DPoint>).p2.y })
return "OK"
}
@@ -0,0 +1,33 @@
// WITH_STDLIB
// TARGET_BACKEND: JVM_IR
// WORKS_WHEN_VALUE_CLASS
// LANGUAGE: +ValueClasses
@JvmInline
value class DPoint(val x: Double, val y: Double)
class PointBox(var value: DPoint)
fun box(): String {
var p = DPoint(1.0, 2.0)
try {
p = DPoint(3.0, error("Failure"))
} catch (_: Exception) {
}
if (p != DPoint(1.0, 2.0)) {
return "Partially reassigned variable"
}
val box = PointBox(p)
try {
box.value = DPoint(3.0, error("Failure"))
} catch (_: Exception) {
}
if (box.value != DPoint(1.0, 2.0)) {
return "Partially reassigned field"
}
return "OK"
}
@@ -0,0 +1,68 @@
// CHECK_BYTECODE_LISTING
// WITH_STDLIB
// TARGET_BACKEND: JVM_IR
// WORKS_WHEN_VALUE_CLASS
// LANGUAGE: +ValueClasses
@JvmInline
value class A<T : Any>(val x: List<T>)
@JvmInline
value class B(val x: UInt)
@JvmInline
value class C(val x: Int, val y: B, val z: String = "3")
@JvmInline
value class D(val x: C) {
constructor(x: Int, y: UInt, z: Int) : this(C(x, B(y), z.toString()))
init {
println(x.x)
}
}
fun functionWithoutBoxes(x: D, y: D) {
var z: D = x
val t: D = D(C(1, B(3U), "4"))
z = t
require(z == y)
}
// 2 public static toString-impl\(IILjava/lang/String;\)Ljava/lang/String;
// 2 INVOKESTATIC C.toString-impl \(IILjava/lang/String;\)Ljava/lang/String;
// 1 INVOKESTATIC D.toString-impl \(IILjava/lang/String;\)Ljava/lang/String;
// 2 public static hashCode-impl\(IILjava/lang/String;\)I
// 2 INVOKESTATIC C.hashCode-impl \(IILjava/lang/String;\)I
// 1 INVOKESTATIC D.hashCode-impl \(IILjava/lang/String;\)I
// 2 public static equals-impl\(IILjava/lang/String;Ljava/lang/Object;\)Z
// 2 public final static equals-impl0\(IILjava/lang/String;IILjava/lang/String;\)Z
// 1 public final static constructor-impl\(III\)LD;
// 2 public final static constructor-impl\(IILjava/lang/String;\)V
// 2 INVOKESTATIC D.constructor-impl \(IILjava/lang/String;\)V
// 2 INVOKESTATIC C.constructor-impl \(IILjava/lang/String;\)V
// 1 public final getX\(\)LC;
// 1 public final getX\$x\(\)I
// 1 public final getX\$y\(\)I
// 1 public final getX\$z\(\)Ljava/lang/String;
// 2 private synthetic <init>\(IILjava/lang/String;\)V
// 1 public final static synthetic box-impl\(IILjava/lang/String;\)LD;
// 1 public final static synthetic box-impl\(IILjava/lang/String;\)LC;
// 2 public final synthetic unbox-impl0\(\)I
// 2 public final synthetic unbox-impl1\(\)I
// 2 public final synthetic unbox-impl2\(\)Ljava/lang/String;
// 1 private I x\$x
// 1 private I x\$y
// 1 private Ljava/lang/String; x\$z
// 0 private LC; x
// 3 private I x
// 1 private I y
// 1 private Ljava/lang/String; z
// 1 INVOKESPECIAL C.<init> \(IILjava/lang/String;\)V
// 1 INVOKESPECIAL D.<init> \(IILjava/lang/String;\)V
// 1 INVOKESTATIC D.box-impl \(IILjava/lang/String;\)LD;
// 1 INVOKESTATIC D.box-impl \(IILjava/lang/String;\)LD;\n ARETURN
// 1 INVOKESTATIC C.box-impl \(IILjava/lang/String;\)LC;
// 1 INVOKESTATIC C.box-impl \(IILjava/lang/String;\)LC;\n ARETURN
// 1 public final static functionWithoutBoxes-GPBa7dw-AYZo7_8\(IILjava/lang/String;IILjava/lang/String;\)V
// 0 functionWithoutBoxes.*(\n {3}.*)*(\n {4}(NEW [ABCD]|.*(box|[ABCD]\.<init>|LA;|LB;|LC;|LD;)))
@@ -0,0 +1,73 @@
// CHECK_BYTECODE_LISTING
// WITH_STDLIB
// TARGET_BACKEND: JVM_IR
// WORKS_WHEN_VALUE_CLASS
// LANGUAGE: +ValueClasses
@JvmInline
value class DPoint(val x: Double, val y: Double)
class Box(var value: DPoint)
fun supplier(index: Int) {} // to make usage of the argument
fun supplier(index: Int, x: DPoint) {} // to make usage of the argument
fun reassignVariable(x: DPoint, box: Box) {
supplier(100)
var p = DPoint(1.0, 2.0) // should not use temporary variables
supplier(101, p)
p = p // should not use temporary variables
supplier(102, p)
p = DPoint(3.0, 4.0) // should use tempVars
supplier(103, p)
p = x // should not use temporary variables
supplier(104, p)
p = box.value // should use temporary variables
supplier(105, p)
p = listOf(p)[0] // should use temporary variables
supplier(106, p)
}
fun reassignField(x: DPoint, box: Box) {
supplier(107)
val p = DPoint(5.0, 6.0)
supplier(108, p)
var b = Box(p) // should not use temporary variables
supplier(109)
b.value = b.value // should not use temporary variables
supplier(110)
b.value = DPoint(7.0, 8.0) // should use tempVars
supplier(111)
b.value = x // should not use temporary variables
supplier(112)
b.value = box.value // should not use temporary variables
supplier(113)
b.value = listOf(p)[0] // should use temporary variables
supplier(114)
}
// 1 100(\D|\d\D|\d\d\D)*(DSTORE(\D|\d\D|\d\d\D)*){2}101
// 0 100(\D|\d\D|\d\d\D)*(DSTORE(\D|\d\D|\d\d\D)*){3}101
// 1 101(\D|\d\D|\d\d\D)*(DSTORE(\D|\d\D|\d\d\D)*){2}102
// 0 101(\D|\d\D|\d\d\D)*(DSTORE(\D|\d\D|\d\d\D)*){3}102
// 1 102(\D|\d\D|\d\d\D)*(DSTORE(\D|\d\D|\d\d\D)*){4}103
// 0 102(\D|\d\D|\d\d\D)*(DSTORE(\D|\d\D|\d\d\D)*){5}103
// 1 103(\D|\d\D|\d\d\D)*(DSTORE(\D|\d\D|\d\d\D)*){2}104
// 0 103(\D|\d\D|\d\d\D)*(DSTORE(\D|\d\D|\d\d\D)*){3}104
// 1 104(\D|\d\D|\d\d\D)*(DSTORE(\D|\d\D|\d\d\D)*){4}105
// 0 104(\D|\d\D|\d\d\D)*(DSTORE(\D|\d\D|\d\d\D)*){5}105
// 1 105(\D|\d\D|\d\d\D)*(DSTORE(\D|\d\D|\d\d\D)*){4}106
// 0 105(\D|\d\D|\d\d\D)*(DSTORE(\D|\d\D|\d\d\D)*){5}106
// 1 107(\D|\d\D|\d\d\D)*(DSTORE(\D|\d\D|\d\d\D)*){2}108
// 0 107(\D|\d\D|\d\d\D)*(DSTORE(\D|\d\D|\d\d\D)*){3}108
// 0 108(\D|\d\D|\d\d\D)*(DSTORE(\D|\d\D|\d\d\D)*){1}109
// 1 109(\D|\d\D|\d\d\D)*(DSTORE(\D|\d\D|\d\d\D)*){2}110
// 0 109(\D|\d\D|\d\d\D)*(DSTORE(\D|\d\D|\d\d\D)*){3}110
// 1 110(\D|\d\D|\d\d\D)*(DSTORE(\D|\d\D|\d\d\D)*){2}111
// 0 110(\D|\d\D|\d\d\D)*(DSTORE(\D|\d\D|\d\d\D)*){3}111
// 0 111(\D|\d\D|\d\d\D)*(DSTORE(\D|\d\D|\d\d\D)*){1}112
// 1 112(\D|\d\D|\d\d\D)*(DSTORE(\D|\d\D|\d\d\D)*){2}113
// 0 112(\D|\d\D|\d\d\D)*(DSTORE(\D|\d\D|\d\d\D)*){3}113
// 1 113(\D|\d\D|\d\d\D)*(DSTORE(\D|\d\D|\d\d\D)*){2}114
// 0 113(\D|\d\D|\d\d\D)*(DSTORE(\D|\d\D|\d\d\D)*){3}114
@@ -0,0 +1,42 @@
// CHECK_BYTECODE_LISTING
// WITH_STDLIB
// TARGET_BACKEND: JVM_IR
// WORKS_WHEN_VALUE_CLASS
// LANGUAGE: +ValueClasses
@JvmInline
value class DPoint(val x: Double, val y: Double)
fun require(index: Int, condition: Boolean) = require(condition) { "$index" }
fun DPoint.toObject() = this as Any
fun DPoint.toDPointOrNull() = this as DPoint?
fun Nothing?.toDPointOrNull() = this as DPoint?
fun equalsChecks(left: DPoint, right: DPoint) {
require(100, left == right)
require(101, left.toObject() == right)
require(102, left == right.toObject())
require(103, left.toObject() == right.toObject())
require(104, null == right)
require(105, left == null)
require(106, null as Any? == right)
require(107, left == null as Any?)
require(108, null.toDPointOrNull() == right)
require(109, left == null.toDPointOrNull())
require(110, left.toDPointOrNull() == right)
require(111, left == right.toDPointOrNull())
}
// 1 BIPUSH 100\n {4}DLOAD 0\n {4}DLOAD 2\n {4}DLOAD 4\n {4}DLOAD 6\n {4}INVOKESTATIC .*equals-impl0.*\n {4}INVOKESTATIC .*require
// 1 BIPUSH 101\n {4}DLOAD 0\n {4}DLOAD 2\n {4}.*toObject.*\n {4}DLOAD 4\n {4}DLOAD 6\n {4}.*box-impl.*\n {4}INVOKESTATIC .*Intrinsics.areEqual.*\n {4}INVOKESTATIC .*require
// 1 BIPUSH 102\n {4}DLOAD 0\n {4}DLOAD 2\n {4}DLOAD 4\n {4}DLOAD 6\n {4}.*toObject.*\n {4}INVOKESTATIC .*equals-impl .*\n {4}INVOKESTATIC .*require
// 1 BIPUSH 103\n {4}DLOAD 0\n {4}DLOAD 2\n {4}.*toObject.*\n {4}DLOAD 4\n {4}DLOAD 6\n {4}.*toObject.*\n {4}INVOKESTATIC .*Intrinsics.areEqual.*\n {4}INVOKESTATIC .*require
// 1 BIPUSH 104\n {4}ICONST_0\n {4}INVOKESTATIC .*require
// 1 BIPUSH 105\n {4}DLOAD 0\n {4}DLOAD 2\n {4}ACONST_NULL\n {4}INVOKESTATIC .*equals-impl .*\n {4}INVOKESTATIC .*require
// 1 BIPUSH 106\n {4}ACONST_NULL\n {4}DLOAD 4\n {4}DLOAD 6\n {4}.*box.*\n {4}INVOKESTATIC .*Intrinsics.areEqual.*\n {4}INVOKESTATIC .*require
// 1 BIPUSH 107\n {4}DLOAD 0\n {4}DLOAD 2\n {4}ACONST_NULL\n {4}INVOKESTATIC .*equals-impl .*\n {4}INVOKESTATIC .*require
// 1 BIPUSH 108\n {4}ACONST_NULL\n {4}.*toDPointOrNull.*\n {4}DUP\n {4}IFNONNULL.*(\n {3}([^b\n]|b[^o\n]|bo[^x\n]|box-impl\d)*)*\n {4}INVOKESTATIC .*require
// 1 BIPUSH 109\n {4}DLOAD 0\n {4}DLOAD 2\n {4}ACONST_NULL\n {4}.*toDPointOrNull.*\n {4}INVOKESTATIC .*equals-impl .*\n {4}INVOKESTATIC .*require
// 1 BIPUSH 110\n {4}DLOAD 0\n {4}DLOAD 2\n {4}.*toDPointOrNull.*\n {4}DUP\n {4}IFNONNULL.*(\n {3}([^b\n]|b[^o\n]|bo[^x\n]|box-impl\d)*)*\n {4}INVOKESTATIC .*require
// 1 BIPUSH 111\n {4}DLOAD 0\n {4}DLOAD 2\n {4}DLOAD 4\n {4}DLOAD 6\n {4}.*toDPointOrNull.*\n {4}INVOKESTATIC .*equals-impl .*\n {4}INVOKESTATIC .*require
@@ -0,0 +1,49 @@
// CHECK_BYTECODE_LISTING
// WITH_STDLIB
// TARGET_BACKEND: JVM_IR
// WORKS_WHEN_VALUE_CLASS
// LANGUAGE: +ValueClasses
@JvmInline
value class DPoint(val x: Double, val y: Double)
fun acceptBoxed(x: Any?) {}
fun acceptFlattened(x: DPoint) {}
fun returnBoxed() = DPoint(3.0, 4.0)
fun testFlattened2Boxed() {
acceptBoxed(DPoint(1.0, 2.0))
}
fun testBoxed2Boxed() {
acceptBoxed(returnBoxed())
}
fun testFlattened2Flattened() {
acceptFlattened(DPoint(1.0, 2.0))
}
fun testBoxed2Flattened() {
acceptFlattened(returnBoxed())
}
fun testIgnoredFlattened() {
DPoint(1.0, 2.0)
DPoint(1.0, 2.0)
}
fun testIgnoredBoxed() {
returnBoxed()
}
// 1 testFlattened2Boxed\(\)V(\n {3}.*)*((\n {3}.*box-impl .*)(\n {3}.*)*){1}
// 0 testFlattened2Boxed\(\)V(\n {3}.*)*((\n {3}.*box-impl.*)(\n {3}.*)*){2}
// 0 testBoxed2Boxed\(\)V(\n {3}.*)*((\n {3}.*(box-impl|DSTORE|DLOAD).*)(\n {3}.*)*){1}
// 0 testFlattened2Flattened\(\)V(\n {3}.*)*((\n {3}.*box-impl.*)(\n {3}.*)*){1}
// 1 testFlattened2Flattened\(\)V(\n {3}.*)*((\n {3}.*DSTORE.*)(\n {3}.*)*){2}
// 0 testFlattened2Flattened\(\)V(\n {3}.*)*((\n {3}.*DSTORE.*)(\n {3}.*)*){3}
// 0 testBoxed2Flattened\(\)V(\n {3}.*)*((\n {3}.*box-impl .*)(\n {3}.*)*){1}
// 1 testBoxed2Flattened\(\)V(\n {3}.*)*((\n {3}.*unbox-impl.*)(\n {3}.*)*){2}
// 0 testBoxed2Flattened\(\)V(\n {3}.*)*((\n {3}.*unbox-impl.*)(\n {3}.*)*){3}
// 0 testIgnoredFlattened\(\)V(\n {3}.*)*((\n {3}.*box-impl.*)(\n {3}.*)*){1}
// 0 testIgnoredBoxed\(\)V(\n {3}.*)*((\n {3}.*box-impl.*)(\n {3}.*)*){1}
@@ -0,0 +1,149 @@
// CHECK_BYTECODE_LISTING
// WITH_STDLIB
// TARGET_BACKEND: JVM_IR
// WORKS_WHEN_VALUE_CLASS
// LANGUAGE: +ValueClasses
@JvmInline
value class DPoint(val x: Double, val y: Double) {
val opposite: DPoint
get() = DPoint(-x, -y)
}
class DSegment(var p1: DPoint, var p2: DPoint) {
val center: DPoint
get() = DPoint(p1.x / 2 + p2.x / 2, p1.y / 2 + p2.y / 2)
var notImplemented: DPoint
get() = TODO()
set(_) = TODO()
var point1WithBackingFieldAndDefaultGetter: DPoint = p1
var point2WithBackingFieldAndDefaultGetter: DPoint = p1
get() = field
set(value) {
field = value
require("${2 + 2}" == "4")
}
var pointWithBackingFieldAndCustomGetter: DPoint = p1
get() = field.also { require("${2 + 2}" == "4") }
set(value) {
field = value
require("${2 + 2}" == "4")
}
init {
p1 = p1
}
}
fun tryGetSegment(segment: DSegment) {
segment.p1
segment.p1.x
segment.p1.y
segment.p2
segment.p2.x
segment.p2.y
segment.center
segment.center.x
segment.center.y
segment.notImplemented
segment.notImplemented.x
segment.notImplemented.y
segment.point1WithBackingFieldAndDefaultGetter
segment.point1WithBackingFieldAndDefaultGetter.x
segment.point1WithBackingFieldAndDefaultGetter.y
segment.point2WithBackingFieldAndDefaultGetter
segment.point2WithBackingFieldAndDefaultGetter.x
segment.point2WithBackingFieldAndDefaultGetter.y
segment.pointWithBackingFieldAndCustomGetter
segment.pointWithBackingFieldAndCustomGetter.x
segment.pointWithBackingFieldAndCustomGetter.y
}
fun trySetSegment(segment: DSegment) {
segment.notImplemented = segment.p1
segment.point1WithBackingFieldAndDefaultGetter = segment.p1
segment.point2WithBackingFieldAndDefaultGetter = segment.p1
segment.pointWithBackingFieldAndCustomGetter = segment.p1
segment.p1 = segment.p1
segment.p2 = segment.p2
}
// 0 public final getOpposite\(\)LDPoint;
// 1 public final static getOpposite-impl\(DD\)LDPoint;
// 1 private D p1\$x
// 1 private D p1\$y
// 0 private DPoint; p1
// 1 private D p2\$x
// 1 private D p2\$y
// 0 private DPoint; p2
// 1 private D point1WithBackingFieldAndDefaultGetter\$x
// 1 private D point1WithBackingFieldAndDefaultGetter\$y
// 0 private DPoint; point1WithBackingFieldAndDefaultGetter
// 1 private D point2WithBackingFieldAndDefaultGetter\$x
// 1 private D point2WithBackingFieldAndDefaultGetter\$y
// 0 private DPoint; point2WithBackingFieldAndDefaultGetter
// 1 private D pointWithBackingFieldAndCustomGetter\$x
// 1 private D pointWithBackingFieldAndCustomGetter\$y
// 0 private DPoint; pointWithBackingFieldAndCustomGetter
// 0 private DPoint; notImplemented
// 0 private D notImplemented
// 0 private DPoint; center
// 0 private D center
// 1 public <init>\(DDDD\)V
// 0 public <init>\(DDDD\)V.*(\n {3}.*)*(\n {4}.*box)
// 1 public final getP1\(\)LDPoint;
// 1 public final setP1-sUp7gFk\(DD\)V
// 1 public final getP2\(\)LDPoint;
// 1 public final setP2-sUp7gFk\(DD\)V
// 1 public final getCenter\(\)LDPoint;
// 1 public final getNotImplemented\(\)LDPoint;
// 1 public final setNotImplemented-sUp7gFk\(DD\)V
// 1 public final getPoint1WithBackingFieldAndDefaultGetter\(\)LDPoint;
// 1 public final setPoint1WithBackingFieldAndDefaultGetter-sUp7gFk\(DD\)V
// 1 public final getPoint2WithBackingFieldAndDefaultGetter\(\)LDPoint;
// 1 public final setPoint2WithBackingFieldAndDefaultGetter-sUp7gFk\(DD\)V
// 1 public final getPointWithBackingFieldAndCustomGetter\(\)LDPoint;
// 1 public final setPointWithBackingFieldAndCustomGetter-sUp7gFk\(DD\)V
// 1 public final getP1\$x\(\)D
// 1 public final getP1\$y\(\)D
// 1 public final getP2\$x\(\)D
// 1 public final getP2\$y\(\)D
// 1 public final getPoint1WithBackingFieldAndDefaultGetter\$x\(\)D
// 1 public final getPoint1WithBackingFieldAndDefaultGetter\$y\(\)D
// 1 public final getPoint2WithBackingFieldAndDefaultGetter\$x\(\)D
// 1 public final getPoint2WithBackingFieldAndDefaultGetter\$y\(\)D
// 0 public final getCenter\$
// 0 public final getNotImplemented\$
// 0 public final getPointWithBackingFieldAndCustomGetter\$
// 0 ^ {2}\b.*get.*\$.*(\n {3}.*)*(\n {4}.*\.box)
// 1 tryGetSegment\(LDSegment;\)V
// 0 try[GS]etSegment\(LDSegment;\)V.*(\n {3}.*)*(\n {4}.*\.box)
// 1 tryGetSegment\(LDSegment;\)V.*((\n {3}.*)*(\n {4}.*LDPoint;)){13}
// 0 tryGetSegment\(LDSegment;\)V.*((\n {3}.*)*(\n {4}.*LDPoint;)){14}
// 0 trySetSegment\(LDSegment;\)V.*(\n {3}.*)*(\n {4}.*LDPoint;)
// 1 trySetSegment\(LDSegment;\)V.*((\n {3}.*)*(\n {4}INVOKEVIRTUAL DSegment\.setNotImplemented-sUp7gFk \(DD\)V)){1}
// 0 trySetSegment\(LDSegment;\)V.*((\n {3}.*)*(\n {4}INVOKEVIRTUAL DSegment\.setNotImplemented-sUp7gFk \(DD\)V)){2}
// 1 trySetSegment\(LDSegment;\)V.*((\n {3}.*)*(\n {4}INVOKEVIRTUAL DSegment\.setPoint1WithBackingFieldAndDefaultGetter-sUp7gFk \(DD\)V)){1}
// 0 trySetSegment\(LDSegment;\)V.*((\n {3}.*)*(\n {4}INVOKEVIRTUAL DSegment\.setPoint1WithBackingFieldAndDefaultGetter-sUp7gFk \(DD\)V)){2}
// 1 trySetSegment\(LDSegment;\)V.*((\n {3}.*)*(\n {4}INVOKEVIRTUAL DSegment\.setPoint2WithBackingFieldAndDefaultGetter-sUp7gFk \(DD\)V)){1}
// 0 trySetSegment\(LDSegment;\)V.*((\n {3}.*)*(\n {4}INVOKEVIRTUAL DSegment\.setPoint2WithBackingFieldAndDefaultGetter-sUp7gFk \(DD\)V)){2}
// 1 trySetSegment\(LDSegment;\)V.*((\n {3}.*)*(\n {4}INVOKEVIRTUAL DSegment\.setPointWithBackingFieldAndCustomGetter-sUp7gFk \(DD\)V)){1}
// 0 trySetSegment\(LDSegment;\)V.*((\n {3}.*)*(\n {4}INVOKEVIRTUAL DSegment\.setPointWithBackingFieldAndCustomGetter-sUp7gFk \(DD\)V)){2}
// 1 trySetSegment\(LDSegment;\)V.*((\n {3}.*)*(\n {4}INVOKEVIRTUAL DSegment\.setP1-sUp7gFk \(DD\)V)){1}
// 0 trySetSegment\(LDSegment;\)V.*((\n {3}.*)*(\n {4}INVOKEVIRTUAL DSegment\.setP1-sUp7gFk \(DD\)V)){2}
// 1 trySetSegment\(LDSegment;\)V.*((\n {3}.*)*(\n {4}INVOKEVIRTUAL DSegment\.setP2-sUp7gFk \(DD\)V)){1}
// 0 trySetSegment\(LDSegment;\)V.*((\n {3}.*)*(\n {4}INVOKEVIRTUAL DSegment\.setP2-sUp7gFk \(DD\)V)){2}
// 1 tryGetSegment\(LDSegment;\)V.*((\n {3}.*)*(\n {4}INVOKEVIRTUAL DPoint\.getX \(\)D)){3}
// 0 tryGetSegment\(LDSegment;\)V.*((\n {3}.*)*(\n {4}INVOKEVIRTUAL DPoint\.getX \(\)D)){4}
// 0 trySetSegment\(LDSegment;\)V.*(\n {3}.*)*(\n {4}INVOKEVIRTUAL DPoint\.getX \(\)D)
// 1 tryGetSegment\(LDSegment;\)V.*((\n {3}.*)*(\n {4}INVOKEVIRTUAL DPoint\.getY \(\)D)){3}
// 0 tryGetSegment\(LDSegment;\)V.*((\n {3}.*)*(\n {4}INVOKEVIRTUAL DPoint\.getY \(\)D)){4}
// 0 trySetSegment\(LDSegment;\)V.*(\n {3}.*)*(\n {4}INVOKEVIRTUAL DPoint\.getY \(\)D)
// 1 tryGetSegment\(LDSegment;\)V.*((\n {3}.*)*?(\n {4}INVOKEVIRTUAL DSegment\.get.*\$[xy] \(\)D)){8}
// 0 tryGetSegment\(LDSegment;\)V.*((\n {3}.*)*?(\n {4}INVOKEVIRTUAL DSegment\.get.*\$[xy] \(\)D)){9}
// 1 trySetSegment\(LDSegment;\)V.*((\n {3}.*)*?(\n {4}INVOKEVIRTUAL DSegment\.get.*\$[xy] \(\)D)){12}
// 0 trySetSegment\(LDSegment;\)V.*((\n {3}.*)*?(\n {4}INVOKEVIRTUAL DSegment\.get.*\$[xy] \(\)D)){13}
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.test.runners.codegen;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.util.KtTestUtil;
import org.jetbrains.kotlin.test.TargetBackend;
import org.jetbrains.kotlin.test.utils.TransformersFunctions;
import org.jetbrains.kotlin.test.TestMetadata;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
@@ -5455,6 +5456,16 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
}
}
@Nested
@TestMetadata("compiler/testData/codegen/bytecodeText/valueClasses")
@TestDataPath("$PROJECT_ROOT")
public class ValueClasses {
@Test
public void testAllFilesPresentInValueClasses() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/bytecodeText/valueClasses"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
}
}
@Nested
@TestMetadata("compiler/testData/codegen/bytecodeText/varargs")
@TestDataPath("$PROJECT_ROOT")
@@ -50189,6 +50189,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/valueClasses/classFlattening.kt", TransformersFunctions.getReplaceOptionalJvmInlineAnnotationWithReal());
}
@Test
@TestMetadata("complex.kt")
public void testComplex() throws Exception {
runTest("compiler/testData/codegen/box/valueClasses/complex.kt", TransformersFunctions.getReplaceOptionalJvmInlineAnnotationWithReal());
}
@Test
@TestMetadata("equality.kt")
public void testEquality() throws Exception {
@@ -50196,9 +50202,21 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
}
@Test
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
runTest("compiler/testData/codegen/box/valueClasses/simple.kt", TransformersFunctions.getReplaceOptionalJvmInlineAnnotationWithReal());
@TestMetadata("MFVCFieldInitializationOrder.kt")
public void testMFVCFieldInitializationOrder() throws Exception {
runTest("compiler/testData/codegen/box/valueClasses/MFVCFieldInitializationOrder.kt", TransformersFunctions.getReplaceOptionalJvmInlineAnnotationWithReal());
}
@Test
@TestMetadata("overrides.kt")
public void testOverrides() throws Exception {
runTest("compiler/testData/codegen/box/valueClasses/overrides.kt", TransformersFunctions.getReplaceOptionalJvmInlineAnnotationWithReal());
}
@Test
@TestMetadata("throwingMFVCReassignments.kt")
public void testThrowingMFVCReassignments() throws Exception {
runTest("compiler/testData/codegen/box/valueClasses/throwingMFVCReassignments.kt", TransformersFunctions.getReplaceOptionalJvmInlineAnnotationWithReal());
}
}
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.test.runners.codegen;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.util.KtTestUtil;
import org.jetbrains.kotlin.test.TargetBackend;
import org.jetbrains.kotlin.test.utils.TransformersFunctions;
import org.jetbrains.kotlin.test.TestMetadata;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
@@ -5779,6 +5780,46 @@ public class IrBytecodeTextTestGenerated extends AbstractIrBytecodeTextTest {
}
}
@Nested
@TestMetadata("compiler/testData/codegen/bytecodeText/valueClasses")
@TestDataPath("$PROJECT_ROOT")
public class ValueClasses {
@Test
public void testAllFilesPresentInValueClasses() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/bytecodeText/valueClasses"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
}
@Test
@TestMetadata("equalsBoxTest.kt")
public void testEqualsBoxTest() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/valueClasses/equalsBoxTest.kt", TransformersFunctions.getReplaceOptionalJvmInlineAnnotationWithReal());
}
@Test
@TestMetadata("MFVCDeclaration.kt")
public void testMFVCDeclaration() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/valueClasses/MFVCDeclaration.kt", TransformersFunctions.getReplaceOptionalJvmInlineAnnotationWithReal());
}
@Test
@TestMetadata("MFVCReassignments.kt")
public void testMFVCReassignments() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/valueClasses/MFVCReassignments.kt", TransformersFunctions.getReplaceOptionalJvmInlineAnnotationWithReal());
}
@Test
@TestMetadata("passingMFVC2Functions.kt")
public void testPassingMFVC2Functions() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/valueClasses/passingMFVC2Functions.kt", TransformersFunctions.getReplaceOptionalJvmInlineAnnotationWithReal());
}
@Test
@TestMetadata("regularClassWithMFVC.kt")
public void testRegularClassWithMFVC() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/valueClasses/regularClassWithMFVC.kt", TransformersFunctions.getReplaceOptionalJvmInlineAnnotationWithReal());
}
}
@Nested
@TestMetadata("compiler/testData/codegen/bytecodeText/varargs")
@TestDataPath("$PROJECT_ROOT")