[IR] Add MFVC generation tests
#KT-1179
This commit is contained in:
committed by
teamcity
parent
894cdc2307
commit
765c212327
+21
-3
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+41
@@ -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")
|
||||
|
||||
+91
-23
@@ -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
|
||||
|
||||
+42
-7
@@ -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)) }
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
+17
@@ -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
|
||||
|
||||
+283
-92
@@ -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 =
|
||||
|
||||
+9
-23
@@ -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)
|
||||
}
|
||||
+4
-1
@@ -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 =
|
||||
|
||||
+33
-35
@@ -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
|
||||
}
|
||||
|
||||
+32
-12
@@ -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"
|
||||
}
|
||||
+2
-2
@@ -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"
|
||||
+34
-32
@@ -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
|
||||
}
|
||||
@@ -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}
|
||||
+11
@@ -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")
|
||||
|
||||
+21
-3
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+41
@@ -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")
|
||||
|
||||
Reference in New Issue
Block a user