[IR] Remove unused MFVC getters

Signed-off-by: Evgeniy.Zhelenskiy <Evgeniy.Zhelenskiy@jetbrains.com>

#KT-1179
diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/BridgeLowering.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/BridgeLowering.kt
index 85a2919..a1cd62c 100644
--- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/BridgeLowering.kt
+++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/BridgeLowering.kt
@@ -697,7 +697,7 @@
                             irCastIfNeeded(irGet(bridgeParameter), targetParameterType),
                             getOptimizedPublicAccess(target, targetRemappedParameter.rootMfvcNode.mfvc)
                         ) { error("Not applicable") }
-                        val newArguments = instance.makeFlattenedGetterExpressions()
+                        val newArguments = instance.makeFlattenedGetterExpressions(this)
                         for (newArgument in newArguments) {
                             irCall.putArgument(targetExplicitParameters[targetIndex++], newArgument)
                         }
diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmInlineClassLowering.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmInlineClassLowering.kt
index dce1555..7855228 100644
--- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmInlineClassLowering.kt
+++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmInlineClassLowering.kt
@@ -275,6 +275,8 @@
     private fun IrExpression.coerceToUnboxed() =
         coerceInlineClasses(this, this.type, this.type.unboxInlineClass())
 
+    override fun keepOldFunctionInsteadOfNew(function: IrFunction): Boolean = false
+
     // Precondition: left has an inline class type, but may not be unboxed
     private fun IrBuilderWithScope.specializeEqualsCall(left: IrExpression, right: IrExpression): IrExpression? {
         // There's already special handling for null-comparisons in the Equals intrinsic.
@@ -351,6 +353,7 @@
                     .specializeEqualsCall(expression.getValueArgument(0)!!, expression.getValueArgument(1)!!)
                     ?: expression
             }
+
             else ->
                 super.visitCall(expression)
         }
diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmMultiFieldValueClassLowering.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmMultiFieldValueClassLowering.kt
index fcba70c..28d7122 100644
--- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmMultiFieldValueClassLowering.kt
+++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmMultiFieldValueClassLowering.kt
@@ -26,8 +26,6 @@
 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.IrBlockImpl
-import org.jetbrains.kotlin.ir.expressions.impl.IrCompositeImpl
 import org.jetbrains.kotlin.ir.symbols.IrSymbol
 import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
 import org.jetbrains.kotlin.ir.symbols.impl.IrAnonymousInitializerSymbolImpl
@@ -88,7 +86,7 @@
         fun IrBuilderWithScope.makeReplacement(expression: IrGetValue): IrExpression? {
             oldValueSymbol2NewValueSymbol[expression.symbol]?.let { return irGet(it.owner) }
             val instance = oldSymbol2MfvcNodeInstance[expression.symbol] ?: return null
-            val res = instance.makeGetterExpression()
+            val res = instance.makeGetterExpression(this)
             expression2MfvcNodeInstanceAccessor[res] = MfvcNodeInstanceAccessor.Getter(instance)
             return res
         }
@@ -102,7 +100,7 @@
             oldValueSymbol2NewValueSymbol[expression.symbol]?.let { return irSet(it.owner, expression.value) }
             val instance = oldSymbol2MfvcNodeInstance[expression.symbol] ?: return null
             val values: List<IrExpression> = makeFlattenedExpressionsWithGivenSafety(instance.node, safe, expression.value)
-            val setterExpressions = instance.makeSetterExpressions(values)
+            val setterExpressions = instance.makeSetterExpressions(this, values)
             expression2MfvcNodeInstanceAccessor[setterExpressions] = MfvcNodeInstanceAccessor.Setter(instance, values)
             +setterExpressions
             return setterExpressions
@@ -131,12 +129,12 @@
 
         fun IrBlockBuilder.addReplacement(expression: IrGetField): IrExpression? {
             val property = expression.field.property ?: return null
-            expression.receiver?.get(property.name)?.let { +it; return it }
+            expression.receiver?.get(this, property.name)?.let { +it; return it }
             val node = replacements.getMfvcPropertyNode(property) ?: return null
             val typeArguments = makeTypeArgumentsFromField(expression)
             val instance: ReceiverBasedMfvcNodeInstance =
                 node.createInstanceFromBox(this, typeArguments, expression.receiver, AccessType.AlwaysPrivate, ::variablesSaver)
-            val getterExpression = instance.makeGetterExpression()
+            val getterExpression = instance.makeGetterExpression(this)
             expression2MfvcNodeInstanceAccessor[getterExpression] = MfvcNodeInstanceAccessor.Getter(instance)
             +getterExpression
             return getterExpression
@@ -144,13 +142,13 @@
 
         fun IrBlockBuilder.addReplacement(expression: IrSetField, safe: Boolean): IrExpression? {
             val property = expression.field.property ?: return null
-            expression.receiver?.get(property.name)?.let { +it; return it }
+            expression.receiver?.get(this, property.name)?.let { +it; return it }
             val node = replacements.getMfvcPropertyNode(property) ?: return null
             val typeArguments = makeTypeArgumentsFromField(expression)
             val instance: ReceiverBasedMfvcNodeInstance =
                 node.createInstanceFromBox(this, typeArguments, expression.receiver, AccessType.AlwaysPrivate, ::variablesSaver)
             val values: List<IrExpression> = makeFlattenedExpressionsWithGivenSafety(node, safe, expression.value)
-            val setterExpressions = instance.makeSetterExpressions(values)
+            val setterExpressions = instance.makeSetterExpressions(this, values)
             expression2MfvcNodeInstanceAccessor[setterExpressions] = MfvcNodeInstanceAccessor.Setter(instance, values)
             +setterExpressions
             return setterExpressions
@@ -160,7 +158,7 @@
             val function = expression.symbol.owner
             val property = function.property?.takeIf { function.isGetter } ?: return null
             val dispatchReceiver = expression.dispatchReceiver
-            dispatchReceiver?.get(property.name)?.let { +it; return it }
+            dispatchReceiver?.get(this, property.name)?.let { +it; return it }
             val node = replacements.getMfvcPropertyNode(property) ?: return null
             val typeArguments = makeTypeArgumentsFromFunction(expression)
             // Optimization: pure function access to leaf can be replaced with field access if the field itself is accessible
@@ -171,7 +169,7 @@
             }
             val instance: ReceiverBasedMfvcNodeInstance =
                 node.createInstanceFromBox(this, typeArguments, dispatchReceiver, accessType, ::variablesSaver)
-            val getterExpression = instance.makeGetterExpression()
+            val getterExpression = instance.makeGetterExpression(this)
             expression2MfvcNodeInstanceAccessor[getterExpression] = MfvcNodeInstanceAccessor.Getter(instance)
             +getterExpression
             return getterExpression
@@ -189,29 +187,26 @@
             expression.dispatchReceiver?.type?.let { putAll(makeTypeArgumentsFromType(it as IrSimpleType)) }
         }
 
-        private fun handleSavedExpression(
-            expression: IrExpression, handler: IrBlockBuilder.(accessor: MfvcNodeInstanceAccessor) -> Unit?
+        private inline fun IrBuilderWithScope.irContainer(oldBlock: IrContainerExpression, builder: IrBlockBuilder.() -> Unit) =
+            oldBlock.run {
+                if (isTransparentScope) irComposite(startOffset, endOffset, origin, body = builder)
+                else irBlock(startOffset, endOffset, origin, body = builder)
+            }
+
+        private fun IrBuilderWithScope.handleSavedExpression(
+            expression: IrExpression, handler: IrBuilderWithScope.(accessor: MfvcNodeInstanceAccessor) -> IrExpression?
         ): IrExpression? {
             val accessor = expression2MfvcNodeInstanceAccessor[expression]
             return when {
-                accessor != null -> accessor.instance.scope.irBlock { handler(accessor) ?: return null }
+                accessor != null -> handler(accessor) ?: return null
                 expression !is IrContainerExpression -> null
                 else -> when (val lastExpression = expression.statements.lastOrNull()) {
-                    is IrExpression -> {
+                    is IrExpression -> irContainer(expression) {
                         val inner = handleSavedExpression(lastExpression, handler) ?: return null
-                        if (expression.isTransparentScope) IrCompositeImpl(
-                            startOffset = expression.startOffset,
-                            endOffset = expression.endOffset,
-                            type = inner.type,
-                            origin = expression.origin,
-                            statements = expression.statements.dropLast(1) + inner,
-                        ) else IrBlockImpl(
-                            startOffset = expression.startOffset,
-                            endOffset = expression.endOffset,
-                            type = inner.type,
-                            origin = expression.origin,
-                            statements = expression.statements.dropLast(1) + inner,
-                        )
+                        for (oldStatement in expression.statements.dropLast(1)) {
+                            +oldStatement
+                        }
+                        +inner
                     }
 
                     else -> null
@@ -219,21 +214,22 @@
             }
         }
 
-        operator fun IrExpression.get(name: Name): IrExpression? = handleSavedExpression(this) { accessor ->
+        fun IrExpression.get(scope: IrBuilderWithScope, name: Name): IrExpression? = scope.handleSavedExpression(this) { accessor ->
             val newAccessor = accessor[name] ?: return@handleSavedExpression null
             val expression = when (newAccessor) {
-                is MfvcNodeInstanceAccessor.Getter -> newAccessor.instance.makeGetterExpression()
-                is MfvcNodeInstanceAccessor.Setter -> newAccessor.instance.makeSetterExpressions(newAccessor.values)
+                is MfvcNodeInstanceAccessor.Getter -> newAccessor.instance.makeGetterExpression(scope)
+                is MfvcNodeInstanceAccessor.Setter -> newAccessor.instance.makeSetterExpressions(scope, newAccessor.values)
             }
             expression2MfvcNodeInstanceAccessor[expression] = newAccessor
-            +expression
+            expression
         }
 
         fun handleFlattenedGetterExpressions(
+            scope: IrBuilderWithScope,
             expression: IrExpression,
-            handler: IrBlockBuilder.(values: List<IrExpression>) -> Unit
+            handler: IrBlockBuilder.(values: List<IrExpression>) -> IrExpression
         ): IrExpression? =
-            handleSavedExpression(expression) { handler(it.instance.makeFlattenedGetterExpressions()) }
+            scope.handleSavedExpression(expression) { irBlock { +handler(it.instance.makeFlattenedGetterExpressions(this)) } }
 
         fun registerReplacement(expression: IrExpression, instance: MfvcNodeInstance) {
             expression2MfvcNodeInstanceAccessor[expression] = MfvcNodeInstanceAccessor.Getter(instance)
@@ -255,6 +251,9 @@
     override val specificMangle: SpecificMangle
         get() = SpecificMangle.MultiField
 
+    override fun keepOldFunctionInsteadOfNew(function: IrFunction): Boolean =
+        function.isMultiFieldValueClassFieldGetter
+
     private val variablesToAdd = mutableMapOf<IrDeclarationParent, MutableSet<IrVariable>>()
 
     private fun variablesSaver(variable: IrVariable) {
@@ -357,6 +356,7 @@
     override fun handleSpecificNewClass(declaration: IrClass) {
         val rootNode = replacements.getRootMfvcNode(declaration)!!
         rootNode.replaceFields()
+        declaration.declarations.removeIf { it is IrSimpleFunction && it.isMultiFieldValueClassFieldGetter && it.overriddenSymbols.isEmpty() }
         declaration.declarations += rootNode.run { allUnboxMethods + listOf(boxMethod, specializedEqualsMethod) }
         rootNode.replacePrimaryMultiFieldValueClassConstructor()
     }
@@ -545,7 +545,7 @@
                                     val instance = rootNode.createInstanceFromBox(
                                         this@irBlock, irGet(receiver), getOptimizedPublicAccess(rootNode.mfvc), ::variablesSaver,
                                     )
-                                    val flattenedExpressions = instance.makeFlattenedGetterExpressions()
+                                    val flattenedExpressions = instance.makeFlattenedGetterExpressions(this@irBlock)
                                     for (expression in flattenedExpressions) {
                                         putArgument(targetExplicitParameters[flattenedTargetIndex++], expression)
                                     }
@@ -607,13 +607,12 @@
             parametersStructure.scan(0) { partial: Int, templates: RemappedParameter -> partial + templates.valueParameters.size }
                 .zipWithNext { start: Int, finish: Int -> replacement.explicitParameters.slice(start until finish) }
         )
-        val scope = context.createIrBuilder(replacement.symbol)
         for (i in old2newList.indices) {
             val (param, newParamList) = old2newList[i]
             when (val structure = parametersStructure[i]) {
                 is MultiFieldValueClassMapping -> {
                     val mfvcNodeInstance = structure.rootMfvcNode.createInstanceFromValueDeclarationsAndBoxType(
-                        scope, structure.boxedType, newParamList
+                        structure.boxedType, newParamList
                     )
                     valueDeclarationsRemapper.registerReplacement(param, mfvcNodeInstance)
                 }
@@ -632,7 +631,7 @@
         val typeArguments = makeTypeParameterSubstitutionMap(mfvc, primaryConstructorImpl)
         primaryConstructorImpl.body = context.createIrBuilder(primaryConstructorImpl.symbol).irBlockBody {
             val mfvcNodeInstance =
-                ValueDeclarationMfvcNodeInstance(this, rootMfvcNode, typeArguments, primaryConstructorImpl.valueParameters)
+                ValueDeclarationMfvcNodeInstance(rootMfvcNode, typeArguments, primaryConstructorImpl.valueParameters)
             valueDeclarationsRemapper.registerReplacement(
                 oldPrimaryConstructor.constructedClass.thisReceiver!!,
                 mfvcNodeInstance
@@ -666,7 +665,7 @@
                         this, function.constructedClassType as IrSimpleType, Name.identifier("constructor_tmp"), ::variablesSaver
                     )
                     flattenExpressionTo(expression, instance)
-                    val getterExpression = instance.makeGetterExpression()
+                    val getterExpression = instance.makeGetterExpression(this)
                     valueDeclarationsRemapper.registerReplacement(getterExpression, instance)
                     +getterExpression
                 }
@@ -879,6 +878,9 @@
                         return true
                     } else {
                         require(statement.statements.isEmpty() || resultVariables.isEmpty()) { "Not all statements removed" }
+                        if (statement.statements.isEmpty()) {
+                            block.statements.removeLast()
+                        }
                     }
 
                     statement !is IrSetValue -> return true
@@ -984,7 +986,7 @@
                 saveVariable = ::variablesSaver
             )
         }
-        val instance = ValueDeclarationMfvcNodeInstance(this, rootMfvcNode, typeArguments, variables)
+        val instance = ValueDeclarationMfvcNodeInstance(rootMfvcNode, typeArguments, variables)
         val block = irBlock {
             flattenExpressionTo(expression, instance)
         }
@@ -1043,7 +1045,7 @@
                 }
                 +irCall(rootNode.primaryConstructorImpl).apply {
                     copyTypeArgumentsFrom(expression)
-                    for ((index, leafExpression) in instance.makeFlattenedGetterExpressions().withIndex()) {
+                    for ((index, leafExpression) in instance.makeFlattenedGetterExpressions(this@flattenExpressionTo).withIndex()) {
                         putValueArgument(index, leafExpression)
                     }
                 }
@@ -1051,9 +1053,9 @@
             }
         }
         val transformedExpression = expression.transform(this@JvmMultiFieldValueClassLowering, null)
-        val addedSettersToFlattened = valueDeclarationsRemapper.handleFlattenedGetterExpressions(transformedExpression) {
+        val addedSettersToFlattened = valueDeclarationsRemapper.handleFlattenedGetterExpressions(this, transformedExpression) {
             require(it.size == instance.size) { "Incompatible assignment sizes: ${it.size}, ${instance.size}" }
-            instance.addSetterStatements(this, it)
+            instance.makeSetterExpressions(this, it)
         }
         if (addedSettersToFlattened != null) {
             +addedSettersToFlattened
@@ -1063,7 +1065,7 @@
             this, transformedExpression, getOptimizedPublicAccess(rootNode.mfvc), ::variablesSaver,
         )
         require(expressionInstance.size == instance.size) { "Incompatible assignment sizes: ${expressionInstance.size}, ${instance.size}" }
-        instance.addSetterStatements(this, expressionInstance.makeFlattenedGetterExpressions())
+        instance.addSetterStatements(this, expressionInstance.makeFlattenedGetterExpressions(this))
     }
 
     private fun getOptimizedPublicAccess(parent: IrClass): AccessType =
diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmValueClassAbstractLowering.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmValueClassAbstractLowering.kt
index 0d97298..7f7e6fb 100644
--- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmValueClassAbstractLowering.kt
+++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmValueClassAbstractLowering.kt
@@ -42,6 +42,12 @@
 
         val replacement = replacements.getReplacementFunction(function)
 
+        if (keepOldFunctionInsteadOfNew(function)) {
+            function.transformChildrenVoid()
+            addBindingsFor(function, replacement!!)
+            return null
+        }
+
         if (replacement == null) {
             if (function is IrConstructor) {
                 val constructorReplacement = replacements.getReplacementForRegularClassConstructor(function)
@@ -119,6 +125,8 @@
         return listOf(replacement, bridgeFunction)
     }
 
+    abstract fun keepOldFunctionInsteadOfNew(function: IrFunction): Boolean
+
     final override fun visitReturn(expression: IrReturn): IrExpression {
         expression.returnTargetSymbol.owner.safeAs<IrFunction>()?.let { target ->
             val suffix = target.hashSuffix()
@@ -126,6 +134,7 @@
                 return super.visitReturn(expression)
 
             replacements.run {
+                if (keepOldFunctionInsteadOfNew(target)) return@run null
                 getReplacementFunction(target) ?: if (target is IrConstructor) getReplacementForRegularClassConstructor(target) else null
             }?.let {
                 return context.createIrBuilder(it.symbol, expression.startOffset, expression.endOffset).irReturn(
@@ -165,6 +174,7 @@
     protected abstract fun addBindingsFor(original: IrFunction, replacement: IrFunction)
 
     protected enum class SpecificMangle { Inline, MultiField }
+
     protected abstract val specificMangle: SpecificMangle
     private fun createBridgeFunction(
         function: IrSimpleFunction,
@@ -183,8 +193,10 @@
                 // names at this point.
                 replacement.isGetter ->
                     Name.identifier(JvmAbi.getterName(replacement.correspondingPropertySymbol!!.owner.name.asString()))
+
                 replacement.isSetter ->
                     Name.identifier(JvmAbi.setterName(replacement.correspondingPropertySymbol!!.owner.name.asString()))
+
                 else ->
                     function.name
             }
diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/MemoizedMultiFieldValueClassReplacements.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/MemoizedMultiFieldValueClassReplacements.kt
index 735a22e..0895070 100644
--- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/MemoizedMultiFieldValueClassReplacements.kt
+++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/MemoizedMultiFieldValueClassReplacements.kt
@@ -224,9 +224,10 @@
                         function.isStaticValueClassReplacement ||
                         function.origin == IrDeclarationOrigin.GENERATED_MULTI_FIELD_VALUE_CLASS_MEMBER && function.isAccessor ||
                         function.origin == JvmLoweredDeclarationOrigin.MULTI_FIELD_VALUE_CLASS_GENERATED_IMPL_METHOD ||
-                        function.origin.isSynthetic && function.origin != IrDeclarationOrigin.SYNTHETIC_GENERATED_SAM_IMPLEMENTATION ||
-                        function.isMultiFieldValueClassFieldGetter -> null
+                        function.origin.isSynthetic && function.origin != IrDeclarationOrigin.SYNTHETIC_GENERATED_SAM_IMPLEMENTATION -> null
 
+                // Do not check for overridden symbols because it makes previously overriding function not overriding would break a code.
+                function.isMultiFieldValueClassFieldGetter -> makeMultiFieldValueClassFieldGetterReplacement(function)
                 function.parent.safeAs<IrClass>()?.isMultiFieldValueClass == true -> when {
                     function.isRemoveAtSpecialBuiltinStub() ->
                         null
@@ -250,6 +251,16 @@
             }
         }
 
+    private fun makeMultiFieldValueClassFieldGetterReplacement(function: IrFunction): IrSimpleFunction {
+        require(function is IrSimpleFunction && function.isMultiFieldValueClassFieldGetter) { "Illegal function:\n${function.dump()}" }
+        val replacement = getMfvcPropertyNode(function.correspondingPropertySymbol!!.owner)!!.unboxMethod
+        originalFunctionForMethodReplacement[replacement] = function
+        val templateParameters = listOf(RemappedParameter.RegularMapping(replacement.dispatchReceiverParameter!!))
+        bindingNewFunctionToParameterTemplateStructure[replacement] = templateParameters
+        bindingOldFunctionToParameterTemplateStructure[function] = templateParameters
+        return replacement
+    }
+
     override val getReplacementForRegularClassConstructor: (IrConstructor) -> IrConstructor? =
         storageManager.createMemoizedFunctionWithNullableValues { constructor ->
             when {
diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/MfvcNode.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/MfvcNode.kt
index a8912f4..2af2d73 100644
--- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/MfvcNode.kt
+++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/MfvcNode.kt
@@ -60,13 +60,13 @@
             saveVariable = saveVariable
         )
     }
-    return ValueDeclarationMfvcNodeInstance(scope, this, typeArguments, valueDeclarations)
+    return ValueDeclarationMfvcNodeInstance(this, typeArguments, valueDeclarations)
 }
 
 fun MfvcNode.createInstanceFromValueDeclarationsAndBoxType(
-    scope: IrBuilderWithScope, type: IrSimpleType, fieldValues: List<IrValueDeclaration>
+    type: IrSimpleType, fieldValues: List<IrValueDeclaration>
 ): ValueDeclarationMfvcNodeInstance =
-    ValueDeclarationMfvcNodeInstance(scope, this, makeTypeArgumentsFromType(type), fieldValues)
+    ValueDeclarationMfvcNodeInstance(this, makeTypeArgumentsFromType(type), fieldValues)
 
 fun makeTypeArgumentsFromType(type: IrSimpleType): TypeArguments {
     if (type.classifierOrNull !is IrClassSymbol) return mapOf()
diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/MfvcNodeFactory.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/MfvcNodeFactory.kt
index 0cf287b..c4de020 100644
--- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/MfvcNodeFactory.kt
+++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/MfvcNodeFactory.kt
@@ -236,8 +236,9 @@
         rootNode.makeBoxedExpression(this, typeArguments, valueArguments)
     }
 
+    val hasPureUnboxMethod = defaultMethodsImplementationSourceNode.isPure() && subnodes.all { it.hasPureUnboxMethod }
     return IntermediateMfvcNode(
-        type, rootPropertyName, nameParts, subnodes, unboxMethod, defaultMethodsImplementationSourceNode.isPure(), rootNode
+        type, rootPropertyName, nameParts, subnodes, unboxMethod, hasPureUnboxMethod, rootNode
     )
 }
 
diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/MfvcNodeInstance.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/MfvcNodeInstance.kt
index 07f2d7c..9ec2902 100644
--- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/MfvcNodeInstance.kt
+++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/MfvcNodeInstance.kt
@@ -22,27 +22,26 @@
 import org.jetbrains.kotlin.name.Name
 
 interface MfvcNodeInstance {
-    val scope: IrBuilderWithScope
     val node: MfvcNode
     val typeArguments: TypeArguments
     val type: IrSimpleType
 
-    fun makeFlattenedGetterExpressions(): List<IrExpression>
-    fun makeGetterExpression(): IrExpression
+    fun makeFlattenedGetterExpressions(scope: IrBlockBuilder): List<IrExpression>
+    fun makeGetterExpression(scope: IrBuilderWithScope): IrExpression
     operator fun get(name: Name): MfvcNodeInstance?
-    fun makeStatements(values: List<IrExpression>): List<IrStatement>
+    fun makeStatements(scope: IrBuilderWithScope, values: List<IrExpression>): List<IrStatement>
 }
 
 private fun makeTypeFromMfvcNodeAndTypeArguments(node: MfvcNode, typeArguments: TypeArguments) =
     node.type.substitute(typeArguments) as IrSimpleType
 
 fun MfvcNodeInstance.addSetterStatements(scope: IrBlockBuilder, values: List<IrExpression>) = with(scope) {
-    for (statement in makeStatements(values)) {
+    for (statement in makeStatements(this, values)) {
         +statement
     }
 }
 
-fun MfvcNodeInstance.makeSetterExpressions(values: List<IrExpression>): IrExpression = scope.irBlock {
+fun MfvcNodeInstance.makeSetterExpressions(scope: IrBuilderWithScope, values: List<IrExpression>): IrExpression = scope.irBlock {
     addSetterStatements(this, values)
 }
 
@@ -51,7 +50,6 @@
 }
 
 class ValueDeclarationMfvcNodeInstance(
-    override val scope: IrBuilderWithScope,
     override val node: MfvcNode,
     override val typeArguments: TypeArguments,
     val valueDeclarations: List<IrValueDeclaration>,
@@ -62,19 +60,21 @@
 
     override val type: IrSimpleType = makeTypeFromMfvcNodeAndTypeArguments(node, typeArguments)
 
-    override fun makeFlattenedGetterExpressions(): List<IrExpression> = valueDeclarations.map { scope.irGet(it) }
+    override fun makeFlattenedGetterExpressions(scope: IrBlockBuilder): List<IrExpression> =
+        makeFlattenedGetterExpressions(scope as IrBuilderWithScope)
+    private fun makeFlattenedGetterExpressions(scope: IrBuilderWithScope): List<IrExpression> = valueDeclarations.map { scope.irGet(it) }
 
-    override fun makeGetterExpression(): IrExpression = when (node) {
-        is LeafMfvcNode -> makeFlattenedGetterExpressions().single()
-        is MfvcNodeWithSubnodes -> node.makeBoxedExpression(scope, typeArguments, makeFlattenedGetterExpressions())
+    override fun makeGetterExpression(scope: IrBuilderWithScope): IrExpression = when (node) {
+        is LeafMfvcNode -> makeFlattenedGetterExpressions(scope).single()
+        is MfvcNodeWithSubnodes -> node.makeBoxedExpression(scope, typeArguments, makeFlattenedGetterExpressions(scope))
     }
 
     override fun get(name: Name): ValueDeclarationMfvcNodeInstance? {
         val (newNode, indices) = node.getSubnodeAndIndices(name) ?: return null
-        return ValueDeclarationMfvcNodeInstance(scope, newNode, typeArguments, valueDeclarations.slice(indices))
+        return ValueDeclarationMfvcNodeInstance(newNode, typeArguments, valueDeclarations.slice(indices))
     }
 
-    override fun makeStatements(values: List<IrExpression>): List<IrStatement> {
+    override fun makeStatements(scope: IrBuilderWithScope, values: List<IrExpression>): List<IrStatement> {
         checkValuesCount(values)
         return valueDeclarations.zip(values) { declaration, value -> scope.irSet(declaration, value) }
     }
@@ -141,7 +141,7 @@
 enum class AccessType { AlwaysPublic, PrivateWhenNoBox, AlwaysPrivate }
 
 class ReceiverBasedMfvcNodeInstance(
-    override val scope: IrBlockBuilder,
+    private val scope: IrBlockBuilder,
     override val node: MfvcNode,
     override val typeArguments: TypeArguments,
     receiver: IrExpression?,
@@ -161,14 +161,14 @@
         require(node is RootMfvcNode == (unboxMethod == null)) { "Only root node has node getter" }
     }
 
-    override fun makeFlattenedGetterExpressions(): List<IrExpression> = when (node) {
-        is LeafMfvcNode -> listOf(makeGetterExpression())
+    override fun makeFlattenedGetterExpressions(scope: IrBlockBuilder): List<IrExpression> = when (node) {
+        is LeafMfvcNode -> listOf(makeGetterExpression(scope))
         is MfvcNodeWithSubnodes -> when {
             node is IntermediateMfvcNode && canUsePrivateAccessFor(node) && fields != null ->
                 fields.map { scope.irGetField(makeReceiverCopy(), it) }
 
             node is IntermediateMfvcNode && !node.hasPureUnboxMethod -> {
-                val value = makeGetterExpression()
+                val value = makeGetterExpression(scope)
                 val asVariable = scope.savableStandaloneVariableWithSetter(
                     value,
                     origin = IrDeclarationOrigin.GENERATED_MULTI_FIELD_VALUE_CLASS_PARAMETER,
@@ -178,14 +178,14 @@
                 val root = node.rootNode
                 val variableInstance =
                     root.createInstanceFromBox(scope, typeArguments, scope.irGet(asVariable), accessType, saveVariable)
-                variableInstance.makeFlattenedGetterExpressions()
+                variableInstance.makeFlattenedGetterExpressions(scope)
             }
 
-            else -> node.subnodes.flatMap { get(it.name)!!.makeFlattenedGetterExpressions() }
+            else -> node.subnodes.flatMap { get(it.name)!!.makeFlattenedGetterExpressions(scope) }
         }
     }
 
-    override fun makeGetterExpression(): IrExpression = with(scope) {
+    override fun makeGetterExpression(scope: IrBuilderWithScope): IrExpression = with(scope) {
         when {
             node is LeafMfvcNode && canUsePrivateAccessFor(node) && fields != null -> irGetField(makeReceiverCopy(), fields.single())
             node is IntermediateMfvcNode && accessType == AccessType.AlwaysPrivate && fields != null ->
@@ -215,7 +215,7 @@
         return newNode.createInstanceFromBox(scope, typeArguments, makeReceiverCopy(), accessType, saveVariable)
     }
 
-    override fun makeStatements(values: List<IrExpression>): List<IrStatement> {
+    override fun makeStatements(scope: IrBuilderWithScope, values: List<IrExpression>): List<IrStatement> {
         checkValuesCount(values)
         require(fields != null) { "$node is immutable as it has custom getter and so no backing fields" }
         return fields.zip(values) { field, expr -> scope.irSetField(makeReceiverCopy(), field, expr) }
diff --git a/compiler/testData/codegen/box/valueClasses/classFlattening.txt b/compiler/testData/codegen/box/valueClasses/classFlattening.txt
index 2b0613d..1c2e57c 100644
--- a/compiler/testData/codegen/box/valueClasses/classFlattening.txt
+++ b/compiler/testData/codegen/box/valueClasses/classFlattening.txt
@@ -85,9 +85,6 @@
     public method equals(@org.jetbrains.annotations.Nullable p0: java.lang.Object): boolean
     public static method equals-impl(p0: int, p1: int, p2: java.lang.String, p3: int, p4: int, p5: int, p6: java.lang.String, p7: java.lang.Object): boolean
     public final static method equals-impl0(p0: int, p1: int, p2: java.lang.String, p3: int, p4: int, p5: int, p6: java.lang.String, p7: int, p8: int, p9: java.lang.String, p10: int, p11: int, p12: int, p13: java.lang.String): boolean
-    public final @org.jetbrains.annotations.NotNull method getX(): SimpleMfvc
-    public final method getY-fhib4bs(): int
-    public final @org.jetbrains.annotations.NotNull method getZ(): SimpleMfvc
     public method hashCode(): int
     public static method hashCode-impl(p0: int, p1: int, p2: java.lang.String, p3: int, p4: int, p5: int, p6: java.lang.String): int
     public @org.jetbrains.annotations.NotNull method toString(): java.lang.String
@@ -167,9 +164,6 @@
     private final static method getPrivate2-sUp7gFk(p0: int, p1: int, p2: java.lang.String): SimpleMfvc
     private final static method getPrivate2-sUp7gFk(p0: int, p1: int, p2: java.lang.String, p3: int, p4: int, p5: java.lang.String): SimpleMfvc
     private final static method getPrivate4-sUp7gFk(p0: int, p1: int, p2: java.lang.String): SimpleMfvc
-    public final method getX-pVg5ArA(): int
-    public final method getY-fhib4bs(): int
-    public final @org.jetbrains.annotations.NotNull method getZ(): java.lang.String
     public method hashCode(): int
     public static method hashCode-impl(p0: int, p1: int, p2: java.lang.String): int
     public @org.jetbrains.annotations.NotNull method toString(): java.lang.String
diff --git a/compiler/testData/codegen/box/valueClasses/complex.kt b/compiler/testData/codegen/box/valueClasses/complex.kt
index 68366a8..aeee824 100644
--- a/compiler/testData/codegen/box/valueClasses/complex.kt
+++ b/compiler/testData/codegen/box/valueClasses/complex.kt
@@ -61,6 +61,7 @@
 }
 
 fun g(e: E) {
+    supply(e)
 }
 
 fun <T : List<Int>> h(r: R<T>) {
@@ -155,7 +156,11 @@
     list.add(list.last())
 }
 
-fun supply(x: Any) {}
+val lines = mutableListOf<String>()
+
+fun supply(x: Any) {
+    lines.add(x.toString())
+}
 
 fun equalsChecks1(x: A<List<Int>>) {}
 fun equalsChecks(left: R<List<Int>>, right: R<List<Int>>) {
@@ -175,4 +180,125 @@
 
 // todo add default parameters
 
-fun box() = "OK"
+fun box(): String {
+    supply("#1")
+    require(inlined(1, 2U, 3) == D(C(1, B(2U), "3")))
+    supply("#2")
+    require(notInlined(1, 2U, 3) == D(C(1, B(2U), "3")))
+    supply("#3")
+    val e = E(D(3, 4U, 5))
+    supply("#4")
+    val r = R(1, 2U, e, A(listOf(listOf(6))))
+    supply("#5")
+    f(r)
+    supply("#6")
+    g(e)
+    supply("#7")
+    h(r)
+    supply("#8")
+    h1()
+    supply("#9")
+    val ni = NotInlined(r, 7)
+    supply("#10")
+    ni.withNonTrivialGettersWithBF
+    supply("#11")
+    ni.withNonTrivialSettersWithBF = ni.withNonTrivialSettersWithBF
+    supply("#12")
+    supply(ni.toString())
+    supply("#13")
+    testVars(ni)
+    supply("#14")
+    reuseBoxed(mutableListOf(r))
+    supply("#15")
+    equalsChecks(r, r)
+    supply("#16")
+    equalsChecks1(A(listOf(listOf())))
+    supply("#17")
+
+    val log = lines.joinToString("\n")
+    val expectedLog =
+        """
+        #1
+        1
+        1
+        #2
+        1
+        1
+        #3
+        3
+        #4
+        #5
+        R(x=1, y=2, z=E(x=D(x=C(x=3, y=B(x=4), z=5))), t=A(x=[[6]]))
+        1
+        2
+        E(x=D(x=C(x=3, y=B(x=4), z=5)))
+        A(x=[[6]])
+        [[6]]
+        D(x=C(x=3, y=B(x=4), z=5))
+        C(x=3, y=B(x=4), z=5)
+        3
+        B(x=4)
+        5
+        4
+        #6
+        E(x=D(x=C(x=3, y=B(x=4), z=5)))
+        #7
+        E(x=D(x=C(x=3, y=B(x=4), z=5)))
+        R(x=1, y=2, z=E(x=D(x=C(x=3, y=B(x=4), z=5))), t=A(x=[[6]]))
+        1
+        2
+        E(x=D(x=C(x=3, y=B(x=4), z=5)))
+        A(x=[[6]])
+        [[6]]
+        D(x=C(x=3, y=B(x=4), z=5))
+        C(x=3, y=B(x=4), z=5)
+        3
+        B(x=4)
+        5
+        4
+        2
+        2
+        4
+        D(x=C(x=4, y=B(x=5), z=1))
+        6
+        6
+        6
+        6
+        D(x=C(x=6, y=B(x=7), z=2))
+        #8
+        1
+        D(x=C(x=1, y=B(x=2), z=3))
+        4
+        D(x=C(x=4, y=B(x=5), z=6))
+        #9
+        #10
+        1
+        #11
+        1
+        3
+        4
+        #12
+        R(x=1, y=2, z=E(x=D(x=C(x=3, y=B(x=4), z=5))), t=A(x=[[6]]))5
+        #13
+        R(x=1, y=2, z=E(x=D(x=C(x=3, y=B(x=4), z=5))), t=A(x=[[6]]))
+        #14
+        #15
+        true
+        true
+        true
+        true
+        false
+        false
+        false
+        false
+        false
+        false
+        true
+        true
+        #16
+        #17
+        """.trimIndent()
+    require(log == expectedLog) { log }
+    
+    return "OK"
+}
diff --git a/compiler/testData/codegen/box/valueClasses/complex.txt b/compiler/testData/codegen/box/valueClasses/complex.txt
index 3e01a88..0d7ed9b 100644
--- a/compiler/testData/codegen/box/valueClasses/complex.txt
+++ b/compiler/testData/codegen/box/valueClasses/complex.txt
@@ -117,9 +117,6 @@
     public method equals(@org.jetbrains.annotations.Nullable p0: java.lang.Object): boolean
     public static method equals-impl(p0: int, p1: int, p2: java.lang.String, p3: java.lang.Object): boolean
     public final static method equals-impl0(p0: int, p1: int, p2: java.lang.String, p3: int, p4: int, p5: java.lang.String): boolean
-    public final method getX(): int
-    public final method getY-GsR9Xnw(): int
-    public final @org.jetbrains.annotations.NotNull method getZ(): java.lang.String
     public method hashCode(): int
     public static method hashCode-impl(p0: int, p1: int, p2: java.lang.String): int
     public @org.jetbrains.annotations.NotNull method toString(): java.lang.String
@@ -132,11 +129,14 @@
 @kotlin.Metadata
 public final class ComplexKt {
     // source: 'complex.kt'
+    private final static @org.jetbrains.annotations.NotNull field lines: java.util.List
+    static method <clinit>(): void
     public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String
     public final static method equalsChecks-GPBa7dw(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 equalsChecks1-iUtXLc0(@org.jetbrains.annotations.NotNull p0: java.util.List): void
     public final static method f-sUp7gFk(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(p0: int, p1: int, @org.jetbrains.annotations.NotNull p2: java.lang.String): void
+    public final static @org.jetbrains.annotations.NotNull method getLines(): java.util.List
     public final static method h-sUp7gFk(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
@@ -160,7 +160,6 @@
     public method equals(@org.jetbrains.annotations.Nullable p0: java.lang.Object): boolean
     public static method equals-impl(p0: int, p1: int, p2: java.lang.String, p3: java.lang.Object): boolean
     public final static method equals-impl0(p0: int, p1: int, p2: java.lang.String, p3: int, p4: int, p5: java.lang.String): boolean
-    public final @org.jetbrains.annotations.NotNull method getX(): C
     public method hashCode(): int
     public static method hashCode-impl(p0: int, p1: int, p2: java.lang.String): int
     public @org.jetbrains.annotations.NotNull method toString(): java.lang.String
@@ -185,7 +184,6 @@
     public static method equals-impl(p0: int, p1: int, p2: java.lang.String, p3: java.lang.Object): boolean
     public final static method equals-impl0(p0: int, p1: int, p2: java.lang.String, p3: int, p4: int, p5: java.lang.String): boolean
     public final static @org.jetbrains.annotations.NotNull method getWithNonTrivialSetters-impl(p0: int, p1: int, @org.jetbrains.annotations.NotNull p2: java.lang.String): D
-    public final @org.jetbrains.annotations.NotNull method getX(): D
     public method hashCode(): int
     public static method hashCode-impl(p0: int, p1: int, p2: java.lang.String): int
     public final static method setWithNonTrivialSetters-sUp7gFk(p0: int, p1: int, @org.jetbrains.annotations.NotNull p2: java.lang.String, p3: int, p4: int, @org.jetbrains.annotations.NotNull p5: java.lang.String): void
@@ -296,9 +294,6 @@
     public static @org.jetbrains.annotations.NotNull method getFakeOverrideMFVC-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): 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-GKOAj6k(): java.util.List
-    public final method getX(): int
-    public final method getY-pVg5ArA(): int
     public @org.jetbrains.annotations.NotNull method getZ(): E
     public synthetic bridge method getZ-0(): D
     public synthetic bridge method getZ-0-0(): C
diff --git a/compiler/testData/codegen/box/valueClasses/conditionalExpressions.txt b/compiler/testData/codegen/box/valueClasses/conditionalExpressions.txt
index fa58131..9fc5090 100644
--- a/compiler/testData/codegen/box/valueClasses/conditionalExpressions.txt
+++ b/compiler/testData/codegen/box/valueClasses/conditionalExpressions.txt
@@ -38,8 +38,6 @@
     public static method equals-impl(p0: double, p1: double, p2: java.lang.Object): boolean
     public final static method equals-impl0(p0: double, p1: double, p2: double, p3: double): boolean
     public final static method getCounter(): int
-    public final method getX(): double
-    public final method getY(): double
     public method hashCode(): int
     public static method hashCode-impl(p0: double, p1: double): int
     public final static method setCounter(p0: int): void
diff --git a/compiler/testData/codegen/box/valueClasses/equality.txt b/compiler/testData/codegen/box/valueClasses/equality.txt
index 5b016a7..9cab488 100644
--- a/compiler/testData/codegen/box/valueClasses/equality.txt
+++ b/compiler/testData/codegen/box/valueClasses/equality.txt
@@ -18,15 +18,6 @@
     public method equals(@org.jetbrains.annotations.Nullable p0: java.lang.Object): boolean
     public static method equals-impl(p0: int, p1: int, p2: int, p3: int, p4: int, p5: int, p6: java.lang.String, p7: int, p8: int, p9: java.lang.String, p10: java.lang.Object): boolean
     public final static method equals-impl0(p0: int, p1: int, p2: int, p3: int, p4: int, p5: int, p6: java.lang.String, p7: int, p8: int, p9: java.lang.String, p10: int, p11: int, p12: int, p13: int, p14: int, p15: int, p16: java.lang.String, p17: int, p18: int, p19: java.lang.String): boolean
-    public final method getF1-DbFnDB4(): int
-    public final method getF2-ejSTSP4(): int
-    public final @org.jetbrains.annotations.NotNull method getF3(): F3
-    public final method getF4-4yoqybc(): int
-    public final method getF5-z3qHWqM(): int
-    public final @org.jetbrains.annotations.NotNull method getF6-OgMO970(): java.lang.String
-    public final method getF7(): int
-    public final method getF8-pVg5ArA(): int
-    public final @org.jetbrains.annotations.NotNull method getF9(): java.lang.String
     public method hashCode(): int
     public static method hashCode-impl(p0: int, p1: int, p2: int, p3: int, p4: int, p5: int, p6: java.lang.String, p7: int, p8: int, p9: java.lang.String): int
     public @org.jetbrains.annotations.NotNull method toString(): java.lang.String
@@ -74,8 +65,6 @@
     public method equals(@org.jetbrains.annotations.Nullable p0: java.lang.Object): boolean
     public static method equals-impl(p0: int, p1: int, p2: int, p3: int, p4: int, p5: int, p6: java.lang.String, p7: int, p8: int, p9: java.lang.String, p10: int, p11: int, p12: int, p13: int, p14: int, p15: int, p16: java.lang.String, p17: int, p18: int, p19: java.lang.String, p20: java.lang.Object): boolean
     public final static method equals-impl0(p0: int, p1: int, p2: int, p3: int, p4: int, p5: int, p6: java.lang.String, p7: int, p8: int, p9: java.lang.String, p10: int, p11: int, p12: int, p13: int, p14: int, p15: int, p16: java.lang.String, p17: int, p18: int, p19: java.lang.String, p20: int, p21: int, p22: int, p23: int, p24: int, p25: int, p26: java.lang.String, p27: int, p28: int, p29: java.lang.String, p30: int, p31: int, p32: int, p33: int, p34: int, p35: int, p36: java.lang.String, p37: int, p38: int, p39: java.lang.String): boolean
-    public final @org.jetbrains.annotations.NotNull method getA1(): A
-    public final @org.jetbrains.annotations.NotNull method getA2(): A
     public method hashCode(): int
     public static method hashCode-impl(p0: int, p1: int, p2: int, p3: int, p4: int, p5: int, p6: java.lang.String, p7: int, p8: int, p9: java.lang.String, p10: int, p11: int, p12: int, p13: int, p14: int, p15: int, p16: java.lang.String, p17: int, p18: int, p19: java.lang.String): int
     public @org.jetbrains.annotations.NotNull method toString(): java.lang.String
@@ -162,8 +151,6 @@
     public method equals(@org.jetbrains.annotations.Nullable p0: java.lang.Object): boolean
     public static method equals-impl(p0: int, p1: int, p2: java.lang.Object): boolean
     public final static method equals-impl0(p0: int, p1: int, p2: int, p3: int): boolean
-    public final method getX-DbFnDB4(): int
-    public final method getY-ejSTSP4(): int
     public method hashCode(): int
     public static method hashCode-impl(p0: int, p1: int): int
     public @org.jetbrains.annotations.NotNull method toString(): java.lang.String
diff --git a/compiler/testData/codegen/box/valueClasses/forStatement.kt b/compiler/testData/codegen/box/valueClasses/forStatement.kt
index 4de0f97..3c0b96b 100644
--- a/compiler/testData/codegen/box/valueClasses/forStatement.kt
+++ b/compiler/testData/codegen/box/valueClasses/forStatement.kt
@@ -1,5 +1,3 @@
-// https://youtrack.jetbrains.com/issue/KT-52236/Different-modality-in-psi-and-fir
-// CHECK_BYTECODE_LISTING
 // WITH_STDLIB
 // TARGET_BACKEND: JVM_IR
 // WORKS_WHEN_VALUE_CLASS
diff --git a/compiler/testData/codegen/box/valueClasses/forStatement.txt b/compiler/testData/codegen/box/valueClasses/forStatement.txt
deleted file mode 100644
index 98f635e..0000000
--- a/compiler/testData/codegen/box/valueClasses/forStatement.txt
+++ /dev/null
@@ -1,27 +0,0 @@
-@kotlin.jvm.JvmInline
-@kotlin.Metadata
-public final class DPoint {
-    // source: 'forStatement.kt'
-    private final field field-0: double
-    private final field field-1: double
-    private synthetic method <init>(p0: double, p1: double): void
-    public synthetic final static method box-impl(p0: double, p1: double): DPoint
-    public final static method constructor-impl(p0: double, p1: double): void
-    public method equals(@org.jetbrains.annotations.Nullable p0: java.lang.Object): boolean
-    public static method equals-impl(p0: double, p1: double, p2: java.lang.Object): boolean
-    public final static method equals-impl0(p0: double, p1: double, p2: double, p3: double): boolean
-    public final method getX(): double
-    public final method getY(): double
-    public method hashCode(): int
-    public static method hashCode-impl(p0: double, p1: double): int
-    public @org.jetbrains.annotations.NotNull method toString(): java.lang.String
-    public static method toString-impl(p0: double, p1: double): java.lang.String
-    public synthetic final method unbox-impl-0(): double
-    public synthetic final method unbox-impl-1(): double
-}
-
-@kotlin.Metadata
-public final class ForStatementKt {
-    // source: 'forStatement.kt'
-    public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String
-}
diff --git a/compiler/testData/codegen/box/valueClasses/mfvcFieldInitializationOrder.txt b/compiler/testData/codegen/box/valueClasses/mfvcFieldInitializationOrder.txt
index c4f7b3b..fe8f71e 100644
--- a/compiler/testData/codegen/box/valueClasses/mfvcFieldInitializationOrder.txt
+++ b/compiler/testData/codegen/box/valueClasses/mfvcFieldInitializationOrder.txt
@@ -44,8 +44,6 @@
     public method equals(@org.jetbrains.annotations.Nullable p0: java.lang.Object): boolean
     public static method equals-impl(p0: double, p1: double, p2: java.lang.Object): boolean
     public final static method equals-impl0(p0: double, p1: double, p2: double, p3: double): boolean
-    public final method getX(): double
-    public final method getY(): double
     public method hashCode(): int
     public static method hashCode-impl(p0: double, p1: double): int
     public @org.jetbrains.annotations.NotNull method toString(): java.lang.String
diff --git a/compiler/testData/codegen/box/valueClasses/overrides.txt b/compiler/testData/codegen/box/valueClasses/overrides.txt
index 829bb00..2cba3eb 100644
--- a/compiler/testData/codegen/box/valueClasses/overrides.txt
+++ b/compiler/testData/codegen/box/valueClasses/overrides.txt
@@ -55,8 +55,6 @@
     public static @org.jetbrains.annotations.NotNull method getSomethingMFVC-impl(p0: double, p1: double): DPoint
     public method getSomethingRegular(): int
     public static method getSomethingRegular-impl(p0: double, p1: double): int
-    public final method getX(): double
-    public final method getY(): double
     public method hashCode(): int
     public static method hashCode-impl(p0: double, p1: double): int
     public synthetic bridge method setSomethingGeneric(p0: java.lang.Object): void
@@ -143,8 +141,6 @@
     public method equals(@org.jetbrains.annotations.Nullable p0: java.lang.Object): boolean
     public static method equals-impl(p0: double, p1: double, p2: java.lang.Object): boolean
     public final static method equals-impl0(p0: double, p1: double, p2: double, p3: double): boolean
-    public final method getField1(): double
-    public final method getField2(): double
     public @org.jetbrains.annotations.NotNull method getP(): DPoint
     public synthetic bridge method getP(): java.lang.Object
     public static @org.jetbrains.annotations.NotNull method getP-impl(p0: double, p1: double): DPoint
@@ -178,8 +174,6 @@
     public method equals(@org.jetbrains.annotations.Nullable p0: java.lang.Object): boolean
     public static method equals-impl(p0: double, p1: double, p2: java.lang.Object): boolean
     public final static method equals-impl0(p0: double, p1: double, p2: double, p3: double): boolean
-    public final method getField1(): double
-    public final method getField2(): double
     public @org.jetbrains.annotations.NotNull method getP(): DPoint
     public static @org.jetbrains.annotations.NotNull method getP-impl(p0: double, p1: double): DPoint
     public @org.jetbrains.annotations.NotNull method getP1(): DPoint
@@ -2505,8 +2499,6 @@
     public method equals(@org.jetbrains.annotations.Nullable p0: java.lang.Object): boolean
     public static method equals-impl(p0: double, p1: double, p2: java.lang.Object): boolean
     public final static method equals-impl0(p0: double, p1: double, p2: double, p3: double): boolean
-    public final method getField1(): double
-    public final method getField2(): double
     public @org.jetbrains.annotations.NotNull method getP(): DPoint
     public static @org.jetbrains.annotations.NotNull method getP-impl(p0: double, p1: double): DPoint
     public @org.jetbrains.annotations.NotNull method getP1(): DPoint
diff --git a/compiler/testData/codegen/box/valueClasses/overrides_inlineClass.txt b/compiler/testData/codegen/box/valueClasses/overrides_inlineClass.txt
index faa05b5..697dc29 100644
--- a/compiler/testData/codegen/box/valueClasses/overrides_inlineClass.txt
+++ b/compiler/testData/codegen/box/valueClasses/overrides_inlineClass.txt
@@ -55,8 +55,6 @@
     public static @org.jetbrains.annotations.NotNull method getSomethingMFVC-impl(p0: double, p1: double): DPoint
     public method getSomethingRegular(): int
     public static method getSomethingRegular-impl(p0: double, p1: double): int
-    public final method getX-3cLST_U(): double
-    public final method getY-3cLST_U(): double
     public method hashCode(): int
     public static method hashCode-impl(p0: double, p1: double): int
     public synthetic bridge method setSomethingGeneric(p0: java.lang.Object): void
@@ -143,8 +141,6 @@
     public method equals(@org.jetbrains.annotations.Nullable p0: java.lang.Object): boolean
     public static method equals-impl(p0: double, p1: double, p2: java.lang.Object): boolean
     public final static method equals-impl0(p0: double, p1: double, p2: double, p3: double): boolean
-    public final method getField1-3cLST_U(): double
-    public final method getField2-3cLST_U(): double
     public @org.jetbrains.annotations.NotNull method getP(): DPoint
     public synthetic bridge method getP(): java.lang.Object
     public static @org.jetbrains.annotations.NotNull method getP-impl(p0: double, p1: double): DPoint
@@ -178,8 +174,6 @@
     public method equals(@org.jetbrains.annotations.Nullable p0: java.lang.Object): boolean
     public static method equals-impl(p0: double, p1: double, p2: java.lang.Object): boolean
     public final static method equals-impl0(p0: double, p1: double, p2: double, p3: double): boolean
-    public final method getField1-3cLST_U(): double
-    public final method getField2-3cLST_U(): double
     public @org.jetbrains.annotations.NotNull method getP(): DPoint
     public static @org.jetbrains.annotations.NotNull method getP-impl(p0: double, p1: double): DPoint
     public @org.jetbrains.annotations.NotNull method getP1(): DPoint
@@ -2522,8 +2516,6 @@
     public method equals(@org.jetbrains.annotations.Nullable p0: java.lang.Object): boolean
     public static method equals-impl(p0: double, p1: double, p2: java.lang.Object): boolean
     public final static method equals-impl0(p0: double, p1: double, p2: double, p3: double): boolean
-    public final method getField1-3cLST_U(): double
-    public final method getField2-3cLST_U(): double
     public @org.jetbrains.annotations.NotNull method getP(): DPoint
     public static @org.jetbrains.annotations.NotNull method getP-impl(p0: double, p1: double): DPoint
     public @org.jetbrains.annotations.NotNull method getP1(): DPoint
diff --git a/compiler/testData/codegen/box/valueClasses/overrides_typeParameters.txt b/compiler/testData/codegen/box/valueClasses/overrides_typeParameters.txt
index 0cd4daa..de1c921 100644
--- a/compiler/testData/codegen/box/valueClasses/overrides_typeParameters.txt
+++ b/compiler/testData/codegen/box/valueClasses/overrides_typeParameters.txt
@@ -53,8 +53,6 @@
     public method equals(@org.jetbrains.annotations.Nullable p0: java.lang.Object): boolean
     public static method equals-impl(p0: java.lang.Object, p1: java.lang.Object, p2: java.lang.Object): boolean
     public final static method equals-impl0(p0: java.lang.Object, p1: java.lang.Object, p2: java.lang.Object, p3: java.lang.Object): boolean
-    public final method getField1(): java.lang.Object
-    public final method getField2(): java.lang.Object
     public @org.jetbrains.annotations.NotNull method getP(): XPoint
     public synthetic bridge method getP(): java.lang.Object
     public static @org.jetbrains.annotations.NotNull method getP-impl(p0: java.lang.Object, p1: java.lang.Object): XPoint
@@ -88,8 +86,6 @@
     public method equals(@org.jetbrains.annotations.Nullable p0: java.lang.Object): boolean
     public static method equals-impl(p0: java.lang.Object, p1: java.lang.Object, p2: java.lang.Object): boolean
     public final static method equals-impl0(p0: java.lang.Object, p1: java.lang.Object, p2: java.lang.Object, p3: java.lang.Object): boolean
-    public final method getField1(): java.lang.Object
-    public final method getField2(): java.lang.Object
     public @org.jetbrains.annotations.NotNull method getP(): XPoint
     public static @org.jetbrains.annotations.NotNull method getP-impl(p0: java.lang.Object, p1: java.lang.Object): XPoint
     public @org.jetbrains.annotations.NotNull method getP1(): XPoint
@@ -2417,8 +2413,6 @@
     public method equals(@org.jetbrains.annotations.Nullable p0: java.lang.Object): boolean
     public static method equals-impl(p0: java.lang.Object, p1: java.lang.Object, p2: java.lang.Object): boolean
     public final static method equals-impl0(p0: java.lang.Object, p1: java.lang.Object, p2: java.lang.Object, p3: java.lang.Object): boolean
-    public final method getField1(): java.lang.Object
-    public final method getField2(): java.lang.Object
     public @org.jetbrains.annotations.NotNull method getP(): XPoint
     public static @org.jetbrains.annotations.NotNull method getP-impl(p0: java.lang.Object, p1: java.lang.Object): XPoint
     public @org.jetbrains.annotations.NotNull method getP1(): XPoint
@@ -2566,8 +2560,6 @@
     public static @org.jetbrains.annotations.NotNull method getSomethingMFVC-impl(p0: java.lang.Object, p1: java.lang.Object): XPoint
     public method getSomethingRegular(): int
     public static method getSomethingRegular-impl(p0: java.lang.Object, p1: java.lang.Object): int
-    public final method getX(): java.lang.Object
-    public final method getY(): java.lang.Object
     public method hashCode(): int
     public static method hashCode-impl(p0: java.lang.Object, p1: java.lang.Object): int
     public synthetic bridge method setSomethingGeneric(p0: java.lang.Object): void
diff --git a/compiler/testData/codegen/box/valueClasses/throwingMFVCReassignments.txt b/compiler/testData/codegen/box/valueClasses/throwingMFVCReassignments.txt
index acf12a7..a644d18 100644
--- a/compiler/testData/codegen/box/valueClasses/throwingMFVCReassignments.txt
+++ b/compiler/testData/codegen/box/valueClasses/throwingMFVCReassignments.txt
@@ -10,8 +10,6 @@
     public method equals(@org.jetbrains.annotations.Nullable p0: java.lang.Object): boolean
     public static method equals-impl(p0: double, p1: double, p2: java.lang.Object): boolean
     public final static method equals-impl0(p0: double, p1: double, p2: double, p3: double): boolean
-    public final method getX(): double
-    public final method getY(): double
     public method hashCode(): int
     public static method hashCode-impl(p0: double, p1: double): int
     public @org.jetbrains.annotations.NotNull method toString(): java.lang.String
diff --git a/compiler/testData/codegen/box/valueClasses/tryExpressions.txt b/compiler/testData/codegen/box/valueClasses/tryExpressions.txt
index ad19332..eb2ecb0 100644
--- a/compiler/testData/codegen/box/valueClasses/tryExpressions.txt
+++ b/compiler/testData/codegen/box/valueClasses/tryExpressions.txt
@@ -10,8 +10,6 @@
     public method equals(@org.jetbrains.annotations.Nullable p0: java.lang.Object): boolean
     public static method equals-impl(p0: double, p1: double, p2: java.lang.Object): boolean
     public final static method equals-impl0(p0: double, p1: double, p2: double, p3: double): boolean
-    public final method getX(): double
-    public final method getY(): double
     public method hashCode(): int
     public static method hashCode-impl(p0: double, p1: double): int
     public @org.jetbrains.annotations.NotNull method toString(): java.lang.String
diff --git a/compiler/testData/codegen/box/valueClasses/visibility.txt b/compiler/testData/codegen/box/valueClasses/visibility.txt
index 3a2b8f5..8189433e5 100644
--- a/compiler/testData/codegen/box/valueClasses/visibility.txt
+++ b/compiler/testData/codegen/box/valueClasses/visibility.txt
@@ -41,9 +41,7 @@
     public static method equals-impl(p0: int, p1: int, p2: java.lang.Object): boolean
     public final static method equals-impl0(p0: int, p1: int, p2: int, p3: int): boolean
     public final static @org.jetbrains.annotations.NotNull method getT(): Internal
-    public final method getX$main(): int
     public final static method getX(): int
-    public final method getY$main(): int
     public final static method getY(): int
     public method hashCode(): int
     public static method hashCode-impl(p0: int, p1: int): int
@@ -67,7 +65,6 @@
     public method equals(@org.jetbrains.annotations.Nullable p0: java.lang.Object): boolean
     public static method equals-impl(p0: int, p1: int, p2: java.lang.Object): boolean
     public final static method equals-impl0(p0: int, p1: int, p2: int, p3: int): boolean
-    public final @org.jetbrains.annotations.NotNull method getValue$main(): Internal
     public method hashCode(): int
     public static method hashCode-impl(p0: int, p1: int): int
     public @org.jetbrains.annotations.NotNull method toString(): java.lang.String
@@ -89,7 +86,6 @@
     public method equals(@org.jetbrains.annotations.Nullable p0: java.lang.Object): boolean
     public static method equals-impl(p0: int, p1: int, p2: java.lang.Object): boolean
     public final static method equals-impl0(p0: int, p1: int, p2: int, p3: int): boolean
-    public final @org.jetbrains.annotations.NotNull method getValue$main(): Private
     public method hashCode(): int
     public static method hashCode-impl(p0: int, p1: int): int
     public @org.jetbrains.annotations.NotNull method toString(): java.lang.String
@@ -111,7 +107,6 @@
     public method equals(@org.jetbrains.annotations.Nullable p0: java.lang.Object): boolean
     public static method equals-impl(p0: int, p1: int, p2: java.lang.Object): boolean
     public final static method equals-impl0(p0: int, p1: int, p2: int, p3: int): boolean
-    public final @org.jetbrains.annotations.NotNull method getValue$main(): Public
     public method hashCode(): int
     public static method hashCode-impl(p0: int, p1: int): int
     public @org.jetbrains.annotations.NotNull method toString(): java.lang.String
@@ -243,8 +238,6 @@
     public method equals(@org.jetbrains.annotations.Nullable p0: java.lang.Object): boolean
     public static method equals-impl(p0: int, p1: int, p2: java.lang.Object): boolean
     public final static method equals-impl0(p0: int, p1: int, p2: int, p3: int): boolean
-    public final method getX(): int
-    public final method getY(): int
     public method hashCode(): int
     public static method hashCode-impl(p0: int, p1: int): int
     public @org.jetbrains.annotations.NotNull method toString(): java.lang.String
@@ -266,7 +259,6 @@
     public method equals(@org.jetbrains.annotations.Nullable p0: java.lang.Object): boolean
     public static method equals-impl(p0: int, p1: int, p2: java.lang.Object): boolean
     public final static method equals-impl0(p0: int, p1: int, p2: int, p3: int): boolean
-    public final @org.jetbrains.annotations.NotNull method getValue(): Internal
     public method hashCode(): int
     public static method hashCode-impl(p0: int, p1: int): int
     public @org.jetbrains.annotations.NotNull method toString(): java.lang.String
@@ -288,7 +280,6 @@
     public method equals(@org.jetbrains.annotations.Nullable p0: java.lang.Object): boolean
     public static method equals-impl(p0: int, p1: int, p2: java.lang.Object): boolean
     public final static method equals-impl0(p0: int, p1: int, p2: int, p3: int): boolean
-    public final @org.jetbrains.annotations.NotNull method getValue(): Private
     public method hashCode(): int
     public static method hashCode-impl(p0: int, p1: int): int
     public @org.jetbrains.annotations.NotNull method toString(): java.lang.String
@@ -310,7 +301,6 @@
     public method equals(@org.jetbrains.annotations.Nullable p0: java.lang.Object): boolean
     public static method equals-impl(p0: int, p1: int, p2: java.lang.Object): boolean
     public final static method equals-impl0(p0: int, p1: int, p2: int, p3: int): boolean
-    public final @org.jetbrains.annotations.NotNull method getValue(): Public
     public method hashCode(): int
     public static method hashCode-impl(p0: int, p1: int): int
     public @org.jetbrains.annotations.NotNull method toString(): java.lang.String
diff --git a/compiler/testData/codegen/bytecodeText/valueClasses/mfvcDeclaration.kt b/compiler/testData/codegen/bytecodeText/valueClasses/mfvcDeclaration.kt
index 756d7ef..dbb658f 100644
--- a/compiler/testData/codegen/bytecodeText/valueClasses/mfvcDeclaration.kt
+++ b/compiler/testData/codegen/bytecodeText/valueClasses/mfvcDeclaration.kt
@@ -49,7 +49,7 @@
 // 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;
+// 0 public final getX\(\)LC;
 // 1 public final synthetic unbox-impl-0-0\(\)I
 // 1 public final synthetic unbox-impl-0-1\(\)I
 // 1 public final synthetic unbox-impl-0-2\(\)Ljava/lang/String;
@@ -70,7 +70,7 @@
 // 1 INVOKESPECIAL C.<init> \(IILjava/lang/String;\)V
 // 1 INVOKESPECIAL D.<init> \(IILjava/lang/String;\)V
 // 2 INVOKESTATIC D.box-impl \(IILjava/lang/String;\)LD;
-// 3 INVOKESTATIC C.box-impl \(IILjava/lang/String;\)LC;
+// 2 INVOKESTATIC C.box-impl \(IILjava/lang/String;\)LC;
 // 1 public final static functionWithoutBoxes-GPBa7dw\(IILjava/lang/String;IILjava/lang/String;\)V
 // 0 functionWithoutBoxes.*(\n {3}.*)*(\n {4}(NEW [ABCD]|.*(box|[ABCD]\.<init>|LA;|LB;|LC;|LD;)))
 // 1 privateAccess.*(\n   .+)*(\n    GETFIELD Regular\.x-0-0 : I)(\n   .+)*(\n    INVOKEVIRTUAL Regular\.getX-0 \(\)LC;)(\n   .+)*(\n    INVOKESPECIAL Regular\.getX \(\)LD;)