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 9ec29027a12..7e24bff9eee 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 @@ -15,10 +15,7 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrTypeOperatorCallImpl import org.jetbrains.kotlin.ir.symbols.impl.IrVariableSymbolImpl import org.jetbrains.kotlin.ir.types.IrSimpleType import org.jetbrains.kotlin.ir.types.IrType -import org.jetbrains.kotlin.ir.util.deepCopyWithSymbols -import org.jetbrains.kotlin.ir.util.dump -import org.jetbrains.kotlin.ir.util.render -import org.jetbrains.kotlin.ir.util.substitute +import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.name.Name interface MfvcNodeInstance { @@ -167,7 +164,12 @@ class ReceiverBasedMfvcNodeInstance( node is IntermediateMfvcNode && canUsePrivateAccessFor(node) && fields != null -> fields.map { scope.irGetField(makeReceiverCopy(), it) } - node is IntermediateMfvcNode && !node.hasPureUnboxMethod -> { + node !is IntermediateMfvcNode || node.hasPureUnboxMethod && (canUsePrivateAccessFor(node) || node.unboxMethod.parentAsClass.isMultiFieldValueClass) -> + // We cannot relay on purity of non-mfvc class getter because the incremental compiler will not recompile the code + // that relayed after the change of purity if it is not local for the class. + node.subnodes.flatMap { get(it.name)!!.makeFlattenedGetterExpressions(scope) } + + else -> { val value = makeGetterExpression(scope) val asVariable = scope.savableStandaloneVariableWithSetter( value, @@ -180,8 +182,6 @@ class ReceiverBasedMfvcNodeInstance( root.createInstanceFromBox(scope, typeArguments, scope.irGet(asVariable), accessType, saveVariable) variableInstance.makeFlattenedGetterExpressions(scope) } - - else -> node.subnodes.flatMap { get(it.name)!!.makeFlattenedGetterExpressions(scope) } } } diff --git a/compiler/testData/codegen/bytecodeText/valueClasses/mfvcReassignments.kt b/compiler/testData/codegen/bytecodeText/valueClasses/mfvcReassignments.kt index 176db91c10f..3197831d164 100644 --- a/compiler/testData/codegen/bytecodeText/valueClasses/mfvcReassignments.kt +++ b/compiler/testData/codegen/bytecodeText/valueClasses/mfvcReassignments.kt @@ -63,10 +63,14 @@ fun reassignField(x: DPoint, box: Box) { // 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 -// 0 109(\D|\d\D|\d\d\D)*([DA]STORE(\D|\d\D|\d\d\D)*){1}110 +// 0 109(\D|\d\D|\d\d\D)*(DSTORE(\D|\d\D|\d\d\D)*){1}110 +// 1 109(\D|\d\D|\d\d\D)*(ASTORE(\D|\d\D|\d\d\D)*){1}110 +// 0 109(\D|\d\D|\d\d\D)*(ASTORE(\D|\d\D|\d\d\D)*){2}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 -// 0 112(\D|\d\D|\d\d\D)*([DA]STORE(\D|\d\D|\d\d\D)*){1}113 +// 0 112(\D|\d\D|\d\d\D)*(DSTORE(\D|\d\D|\d\d\D)*){1}113 +// 1 112(\D|\d\D|\d\d\D)*(ASTORE(\D|\d\D|\d\d\D)*){1}113 +// 0 112(\D|\d\D|\d\d\D)*(ASTORE(\D|\d\D|\d\d\D)*){2}113 // 1 113(\D|\d\D|\d\d\D)*(ASTORE(\D|\d\D|\d\d\D)*){1}114 // 0 113(\D|\d\D|\d\d\D)*(ASTORE(\D|\d\D|\d\d\D)*){2}114 diff --git a/compiler/testData/codegen/bytecodeText/valueClasses/regularClassWithMFVC.kt b/compiler/testData/codegen/bytecodeText/valueClasses/regularClassWithMFVC.kt index 2de8fe6a486..face2e91037 100644 --- a/compiler/testData/codegen/bytecodeText/valueClasses/regularClassWithMFVC.kt +++ b/compiler/testData/codegen/bytecodeText/valueClasses/regularClassWithMFVC.kt @@ -123,9 +123,10 @@ fun trySetSegment(segment: DSegment) { // 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;)){7} -// 0 tryGetSegment\(LDSegment;\)V.*((\n {3}.*)*(\n {4}.*LDPoint;)){8} -// 0 trySetSegment\(LDSegment;\)V.*(\n {3}.*)*(\n {4}.*LDPoint;) +// 1 tryGetSegment\(LDSegment;\)V.*\n(( {3}.*\n)*( {4}.*LDPoint;\n)){7} +// 0 tryGetSegment\(LDSegment;\)V.*\n(( {3}.*\n)*( {4}.*LDPoint;\n)){8} +// 1 trySetSegment\(LDSegment;\)V.*\n(( {3}.*\n)*( {4}.*LDPoint;\n)){6} +// 0 trySetSegment\(LDSegment;\)V.*\n(( {3}.*\n)*( {4}.*LDPoint;\n)){7} // 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} @@ -141,5 +142,4 @@ fun trySetSegment(segment: DSegment) { // 0 try[GS]etSegment\(LDSegment;\)V.*(\n {3}.*)*(\n {4}INVOKEVIRTUAL DPoint\.get[XY] \(\)D) // 1 tryGetSegment\(LDSegment;\)V.*((\n {3}.*)*?(\n {4}INVOKEVIRTUAL DSegment\.get.*-[01] \(\)D)){14} // 0 tryGetSegment\(LDSegment;\)V.*((\n {3}.*)*?(\n {4}INVOKEVIRTUAL DSegment\.get.*-[01] \(\)D)){15} -// 1 trySetSegment\(LDSegment;\)V.*((\n {3}.*)*?(\n {4}INVOKEVIRTUAL DSegment\.get.*-[01] \(\)D)){12} -// 0 trySetSegment\(LDSegment;\)V.*((\n {3}.*)*?(\n {4}INVOKEVIRTUAL DSegment\.get.*-[01] \(\)D)){13} +// 0 trySetSegment\(LDSegment;\)V.*((\n {3}.*)*?(\n {4}INVOKEVIRTUAL DSegment\.get.*-[01] \(\)D)){1}