[IR] Fix compiler bugs with MFVC to let KorGE run
Signed-off-by: Evgeniy.Zhelenskiy <Evgeniy.Zhelenskiy@jetbrains.com> #KT-1179
This commit is contained in:
committed by
Space Team
parent
9b3fc34f78
commit
3b5ad0681f
+2
-2
@@ -684,9 +684,9 @@ internal class BridgeLowering(val context: JvmBackendContext) : FileLoweringPass
|
||||
val instance = targetRemappedParameter.rootMfvcNode.createInstanceFromBox(
|
||||
this,
|
||||
irCastIfNeeded(irGet(bridgeParameter), targetParameterType),
|
||||
getOptimizedPublicAccess(target, targetRemappedParameter.rootMfvcNode.mfvc)
|
||||
AccessType.ChooseEffective
|
||||
) { error("Not applicable") }
|
||||
val newArguments = instance.makeFlattenedGetterExpressions(this, registerPossibleExtraBoxCreation = {})
|
||||
val newArguments = instance.makeFlattenedGetterExpressions(this, bridge.parentAsClass, registerPossibleExtraBoxCreation = {})
|
||||
for (newArgument in newArguments) {
|
||||
irCall.putArgument(targetExplicitParameters[targetIndex++], newArgument)
|
||||
}
|
||||
|
||||
+129
-56
@@ -26,7 +26,11 @@ import org.jetbrains.kotlin.ir.builders.*
|
||||
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.IrConstructorCallImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrDelegatingConstructorCallImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrEnumConstructorCallImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrFunctionReferenceImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
|
||||
@@ -64,6 +68,8 @@ internal class JvmMultiFieldValueClassLowering(
|
||||
|
||||
private val irCurrentScope
|
||||
get() = currentScope!!.irElement as IrDeclaration
|
||||
private val irCurrentClass
|
||||
get() = currentClass!!.irElement as IrClass
|
||||
|
||||
private fun registerPossibleExtraBoxUsage() {
|
||||
possibleExtraBoxUsageGenerated.add(irCurrentScope)
|
||||
@@ -95,7 +101,7 @@ internal class JvmMultiFieldValueClassLowering(
|
||||
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(this, ::registerPossibleExtraBoxUsage)
|
||||
val res = instance.makeGetterExpression(this, irCurrentClass, ::registerPossibleExtraBoxUsage)
|
||||
expression2MfvcNodeInstanceAccessor[res] = MfvcNodeInstanceAccessor.Getter(instance)
|
||||
return res
|
||||
}
|
||||
@@ -146,8 +152,8 @@ internal class JvmMultiFieldValueClassLowering(
|
||||
val node = replacements.getMfvcFieldNode(field) ?: return null
|
||||
val typeArguments = makeTypeArgumentsFromField(expression)
|
||||
val instance: ReceiverBasedMfvcNodeInstance =
|
||||
node.createInstanceFromBox(this, typeArguments, expression.receiver, AccessType.AlwaysPrivate, ::variablesSaver)
|
||||
val getterExpression = instance.makeGetterExpression(this, ::registerPossibleExtraBoxUsage)
|
||||
node.createInstanceFromBox(this, typeArguments, expression.receiver, AccessType.UseFields, ::variablesSaver)
|
||||
val getterExpression = instance.makeGetterExpression(this, irCurrentClass, ::registerPossibleExtraBoxUsage)
|
||||
expression2MfvcNodeInstanceAccessor[getterExpression] = MfvcNodeInstanceAccessor.Getter(instance)
|
||||
+getterExpression
|
||||
return getterExpression
|
||||
@@ -162,7 +168,7 @@ internal class JvmMultiFieldValueClassLowering(
|
||||
scope = this,
|
||||
typeArguments = makeTypeArgumentsFromField(expression),
|
||||
receiver = expression.receiver,
|
||||
accessType = AccessType.AlwaysPrivate,
|
||||
accessType = AccessType.UseFields,
|
||||
saveVariable = ::variablesSaver
|
||||
)
|
||||
val values: List<IrExpression> = makeFlattenedExpressionsWithGivenSafety(
|
||||
@@ -182,14 +188,9 @@ internal class JvmMultiFieldValueClassLowering(
|
||||
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
|
||||
val accessType = when {
|
||||
!node.hasPureUnboxMethod -> AccessType.AlwaysPublic
|
||||
dispatchReceiver == null -> AccessType.PrivateWhenNoBox
|
||||
else -> getOptimizedPublicAccess(dispatchReceiver.type.erasedUpperBound)
|
||||
}
|
||||
val instance: ReceiverBasedMfvcNodeInstance =
|
||||
node.createInstanceFromBox(this, typeArguments, dispatchReceiver, accessType, ::variablesSaver)
|
||||
val getterExpression = instance.makeGetterExpression(this, ::registerPossibleExtraBoxUsage)
|
||||
node.createInstanceFromBox(this, typeArguments, dispatchReceiver, AccessType.ChooseEffective, ::variablesSaver)
|
||||
val getterExpression = instance.makeGetterExpression(this, irCurrentClass, ::registerPossibleExtraBoxUsage)
|
||||
expression2MfvcNodeInstanceAccessor[getterExpression] = MfvcNodeInstanceAccessor.Getter(instance)
|
||||
+getterExpression
|
||||
return getterExpression
|
||||
@@ -238,7 +239,9 @@ internal class JvmMultiFieldValueClassLowering(
|
||||
val newAccessor = accessor[name] ?: return@handleSavedExpression null
|
||||
val expression = when (newAccessor) {
|
||||
is MfvcNodeInstanceAccessor.Setter -> newAccessor.instance.makeSetterExpressions(scope, newAccessor.values)
|
||||
is MfvcNodeInstanceAccessor.Getter -> newAccessor.instance.makeGetterExpression(scope, ::registerPossibleExtraBoxUsage)
|
||||
is MfvcNodeInstanceAccessor.Getter -> newAccessor.instance.makeGetterExpression(
|
||||
scope, irCurrentClass, ::registerPossibleExtraBoxUsage
|
||||
)
|
||||
}
|
||||
expression2MfvcNodeInstanceAccessor[expression] = newAccessor
|
||||
expression
|
||||
@@ -249,7 +252,8 @@ internal class JvmMultiFieldValueClassLowering(
|
||||
expression: IrExpression,
|
||||
handler: IrBlockBuilder.(values: List<IrExpression>) -> IrExpression
|
||||
): IrExpression? = scope.handleSavedExpression(expression) {
|
||||
irBlock { +handler(it.instance.makeFlattenedGetterExpressions(this, ::registerPossibleExtraBoxUsage)) }.unwrapBlock()
|
||||
irBlock { +handler(it.instance.makeFlattenedGetterExpressions(this, irCurrentClass, ::registerPossibleExtraBoxUsage)) }
|
||||
.unwrapBlock()
|
||||
}
|
||||
|
||||
fun registerReplacement(expression: IrExpression, instance: MfvcNodeInstance) {
|
||||
@@ -354,6 +358,9 @@ internal class JvmMultiFieldValueClassLowering(
|
||||
val newDeclarations = makeNewDeclarationsForRegularClass(fieldsToRemove, propertiesOrFieldsReplacement, irClass)
|
||||
irClass.declarations.replaceAll(newDeclarations)
|
||||
}
|
||||
for (field in fieldsToRemove) {
|
||||
field.correspondingPropertySymbol?.owner?.backingField = null
|
||||
}
|
||||
}
|
||||
|
||||
private fun collectRegularClassMfvcPropertiesOrFieldsReplacement(propertiesOrFields: LinkedHashSet<IrPropertyOrIrField>) =
|
||||
@@ -416,17 +423,35 @@ internal class JvmMultiFieldValueClassLowering(
|
||||
|
||||
override fun handleSpecificNewClass(declaration: IrClass) {
|
||||
val rootNode = replacements.getRootMfvcNode(declaration)
|
||||
rootNode.replaceFields()
|
||||
rootNode.replaceMfvcNotStaticFields()
|
||||
declaration.declarations += rootNode.allUnboxMethods + listOfNotNull(
|
||||
// `takeIf` is a workaround for double addition problem: user-defined typed equals is already defined in the class
|
||||
rootNode.boxMethod, rootNode.specializedEqualsMethod.takeIf { rootNode.createdNewSpecializedEqualsMethod }
|
||||
)
|
||||
rootNode.replacePrimaryMultiFieldValueClassConstructor()
|
||||
|
||||
replaceMfvcStaticFields(declaration)
|
||||
}
|
||||
|
||||
private fun replaceMfvcStaticFields(declaration: IrClass) {
|
||||
val staticFieldMapping: Map<IrField, List<IrDeclaration>> = buildMap {
|
||||
for (staticField in declaration.fields.filter { it.isStatic }) {
|
||||
val node = replacements.getMfvcFieldNode(staticField) ?: continue
|
||||
val fields = node.fields ?: listOf()
|
||||
val initializer = staticField.initializer?.let { makeInitializerReplacement(declaration, staticField, it) }
|
||||
staticField.correspondingPropertySymbol?.owner?.backingField = null
|
||||
put(staticField, fields + listOfNotNull(initializer))
|
||||
}
|
||||
}
|
||||
if (staticFieldMapping.isNotEmpty()) {
|
||||
declaration.declarations.replaceAll(declaration.declarations.flatMap { staticFieldMapping[it] ?: listOf(it) })
|
||||
}
|
||||
}
|
||||
|
||||
override fun transformSecondaryConstructorFlat(constructor: IrConstructor, replacement: IrSimpleFunction): List<IrDeclaration> {
|
||||
for (param in replacement.valueParameters) {
|
||||
param.transformChildrenVoid()
|
||||
param.defaultValue?.patchDeclarationParents(replacement)
|
||||
visitParameter(param)
|
||||
}
|
||||
|
||||
allScopes.push(createScope(replacement))
|
||||
@@ -478,9 +503,13 @@ internal class JvmMultiFieldValueClassLowering(
|
||||
|
||||
private object UNSAFE_MFVC_SET_ORIGIN : IrStatementOrigin
|
||||
|
||||
private fun RootMfvcNode.replaceFields() {
|
||||
mfvc.declarations.removeIf { it is IrField && (!it.isStatic || it.type.needsMfvcFlattening()) }
|
||||
mfvc.declarations += fields
|
||||
private fun RootMfvcNode.replaceMfvcNotStaticFields() {
|
||||
val fieldsToRemove = mfvc.fields.filter { !it.isStatic }.toList()
|
||||
for (field in fieldsToRemove) {
|
||||
field.correspondingPropertySymbol?.owner?.backingField = null
|
||||
}
|
||||
mfvc.declarations.removeAll(fieldsToRemove)
|
||||
mfvc.declarations += fields ?: emptyList()
|
||||
}
|
||||
|
||||
override fun createBridgeDeclaration(source: IrSimpleFunction, replacement: IrSimpleFunction, mangledName: Name): IrSimpleFunction =
|
||||
@@ -613,10 +642,11 @@ internal class JvmMultiFieldValueClassLowering(
|
||||
val receiver = sourceExplicitParameters[flattenedSourceIndex++]
|
||||
val rootNode = remappedTargetParameter.rootMfvcNode
|
||||
val instance = rootNode.createInstanceFromBox(
|
||||
this@irBlock, irGet(receiver), getOptimizedPublicAccess(rootNode.mfvc), ::variablesSaver,
|
||||
this@irBlock, irGet(receiver), AccessType.ChooseEffective, ::variablesSaver,
|
||||
)
|
||||
val flattenedExpressions = instance.makeFlattenedGetterExpressions(
|
||||
this@irBlock, irCurrentClass, ::registerPossibleExtraBoxUsage
|
||||
)
|
||||
val flattenedExpressions =
|
||||
instance.makeFlattenedGetterExpressions(this@irBlock, ::registerPossibleExtraBoxUsage)
|
||||
for (expression in flattenedExpressions) {
|
||||
putArgument(targetExplicitParameters[flattenedTargetIndex++], expression)
|
||||
}
|
||||
@@ -706,22 +736,43 @@ internal class JvmMultiFieldValueClassLowering(
|
||||
val defaultValue = replacements.oldMfvcDefaultArguments[param] ?: continue
|
||||
val structure = parametersStructure[i]
|
||||
if (structure is MultiFieldValueClassMapping) {
|
||||
newParamList[0].defaultValue = with(context.createJvmIrBuilder(replacement.symbol)) {
|
||||
irExprBody(irBlock {
|
||||
val mfvcNodeInstance = structure.rootMfvcNode.createInstanceFromValueDeclarationsAndBoxType(
|
||||
param.type as IrSimpleType, newParamList
|
||||
)
|
||||
flattenExpressionTo(defaultValue, mfvcNodeInstance)
|
||||
+irGet(newParamList[0])
|
||||
})
|
||||
val fakeFunction = context.irFactory.buildFun {
|
||||
returnType = context.irBuiltIns.unitType
|
||||
name = Name.identifier("fake")
|
||||
visibility = DescriptorVisibilities.LOCAL
|
||||
}.apply { parent = replacement }
|
||||
newParamList[0].defaultValue = with(context.createJvmIrBuilder(fakeFunction.symbol)) {
|
||||
withinScope(fakeFunction) {
|
||||
fakeFunction.body = irExprBody(irBlock {
|
||||
val mfvcNodeInstance = structure.rootMfvcNode.createInstanceFromValueDeclarationsAndBoxType(
|
||||
param.type as IrSimpleType, newParamList
|
||||
)
|
||||
flattenExpressionTo(defaultValue, mfvcNodeInstance)
|
||||
+irGet(newParamList[0])
|
||||
})
|
||||
postActionAfterTransformingClassDeclaration(fakeFunction)
|
||||
fakeFunction.body?.patchDeclarationParents(replacement) as IrExpressionBody
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitParameter(parameter: IrValueParameter) {
|
||||
if (parameter.origin != JvmLoweredDeclarationOrigin.GENERATED_MULTI_FIELD_VALUE_CLASS_PARAMETER) {
|
||||
super.visitParameter(parameter)
|
||||
// default MFVC parameter is the special case, it is handled separately
|
||||
if (parameter.origin == JvmLoweredDeclarationOrigin.GENERATED_MULTI_FIELD_VALUE_CLASS_PARAMETER) return
|
||||
if (parameter.defaultValue == null) return
|
||||
val fakeFunction = context.irFactory.buildFun {
|
||||
returnType = context.irBuiltIns.unitType
|
||||
name = Name.identifier("fake")
|
||||
visibility = DescriptorVisibilities.LOCAL
|
||||
}.apply { parent = parameter.parent }
|
||||
parameter.defaultValue = with(context.createJvmIrBuilder(fakeFunction.symbol)) {
|
||||
withinScope(fakeFunction) {
|
||||
fakeFunction.body = irExprBody(parameter.defaultValue!!.expression).transform(this@JvmMultiFieldValueClassLowering, null)
|
||||
postActionAfterTransformingClassDeclaration(fakeFunction)
|
||||
fakeFunction.body?.patchDeclarationParents(parameter.parent) as IrExpressionBody
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -732,17 +783,19 @@ internal class JvmMultiFieldValueClassLowering(
|
||||
|
||||
val initializersBlocks = mfvc.declarations.filterIsInstance<IrAnonymousInitializer>()
|
||||
val typeArguments = makeTypeParameterSubstitutionMap(mfvc, primaryConstructorImpl)
|
||||
primaryConstructorImpl.body = context.createJvmIrBuilder(primaryConstructorImpl.symbol).irBlockBody {
|
||||
val mfvcNodeInstance =
|
||||
ValueDeclarationMfvcNodeInstance(rootMfvcNode, typeArguments, primaryConstructorImpl.valueParameters)
|
||||
valueDeclarationsRemapper.registerReplacement(
|
||||
oldPrimaryConstructor.constructedClass.thisReceiver!!,
|
||||
mfvcNodeInstance
|
||||
)
|
||||
for (initializer in initializersBlocks) {
|
||||
+irBlock {
|
||||
for (stmt in initializer.body.statements) {
|
||||
+stmt.patchDeclarationParents(primaryConstructorImpl) // transformation is done later
|
||||
if (!mfvc.isKotlinExternalStub()) {
|
||||
primaryConstructorImpl.body = context.createJvmIrBuilder(primaryConstructorImpl.symbol).irBlockBody {
|
||||
val mfvcNodeInstance =
|
||||
ValueDeclarationMfvcNodeInstance(rootMfvcNode, typeArguments, primaryConstructorImpl.valueParameters)
|
||||
valueDeclarationsRemapper.registerReplacement(
|
||||
oldPrimaryConstructor.constructedClass.thisReceiver!!,
|
||||
mfvcNodeInstance
|
||||
)
|
||||
for (initializer in initializersBlocks) {
|
||||
+irBlock {
|
||||
for (stmt in initializer.body.statements) {
|
||||
+stmt.patchDeclarationParents(primaryConstructorImpl) // transformation is done later
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -793,8 +846,8 @@ internal class JvmMultiFieldValueClassLowering(
|
||||
// thus it is useless to show it in debugger
|
||||
parameter.origin = JvmLoweredDeclarationOrigin.TEMPORARY_MULTI_FIELD_VALUE_CLASS_PARAMETER
|
||||
val rootNode = replacements.getRootMfvcNode(parameter.type.erasedUpperBound)
|
||||
rootNode.createInstanceFromBox(this, irGet(parameter), AccessType.AlwaysPublic, ::variablesSaver)
|
||||
.makeFlattenedGetterExpressions(this, ::registerPossibleExtraBoxUsage)
|
||||
rootNode.createInstanceFromBox(this, irGet(parameter), AccessType.ChooseEffective, ::variablesSaver)
|
||||
.makeFlattenedGetterExpressions(this, irCurrentClass, ::registerPossibleExtraBoxUsage)
|
||||
.mapIndexed { index, expression ->
|
||||
savableStandaloneVariableWithSetter(
|
||||
expression = expression,
|
||||
@@ -826,8 +879,8 @@ internal class JvmMultiFieldValueClassLowering(
|
||||
}.unwrapBlock()
|
||||
}
|
||||
|
||||
private fun IrFunction.getReplacement(): IrFunction? =
|
||||
replacements.getReplacementFunction(this) ?: (this as? IrConstructor)?.let { replacements.getReplacementForRegularClassConstructor(it) }
|
||||
private fun IrFunction.getReplacement(): IrFunction? = replacements.getReplacementFunction(this)
|
||||
?: (this as? IrConstructor)?.let { replacements.getReplacementForRegularClassConstructor(it) }
|
||||
|
||||
private fun makeNewLambda(
|
||||
originalFunction: IrFunction, expression: IrFunctionReference, makeBody: (wrapper: IrSimpleFunction) -> IrBody
|
||||
@@ -886,8 +939,8 @@ internal class JvmMultiFieldValueClassLowering(
|
||||
|
||||
override fun visitFunctionAccess(expression: IrFunctionAccessExpression): IrExpression {
|
||||
val function = expression.symbol.owner
|
||||
val replacement = replacements.getReplacementFunction(function)
|
||||
val currentScope = currentScope!!.irElement as IrDeclaration
|
||||
val replacement = replacements.getReplacementFunction(function)
|
||||
return when {
|
||||
function is IrConstructor && function.isPrimary && function.constructedClass.isMultiFieldValueClass &&
|
||||
currentScope.origin != JvmLoweredDeclarationOrigin.SYNTHETIC_MULTI_FIELD_VALUE_CLASS_MEMBER -> {
|
||||
@@ -904,7 +957,7 @@ internal class JvmMultiFieldValueClassLowering(
|
||||
valueDeclaration.origin = JvmLoweredDeclarationOrigin.TEMPORARY_MULTI_FIELD_VALUE_CLASS_VARIABLE
|
||||
}
|
||||
flattenExpressionTo(expression, instance)
|
||||
val getterExpression = instance.makeGetterExpression(this, ::registerPossibleExtraBoxUsage)
|
||||
val getterExpression = instance.makeGetterExpression(this, irCurrentClass, ::registerPossibleExtraBoxUsage)
|
||||
valueDeclarationsRemapper.registerReplacement(getterExpression, instance)
|
||||
+getterExpression
|
||||
}
|
||||
@@ -918,8 +971,27 @@ internal class JvmMultiFieldValueClassLowering(
|
||||
val newConstructor = (function as? IrConstructor)
|
||||
?.let { replacements.getReplacementForRegularClassConstructor(it) }
|
||||
?: return super.visitFunctionAccess(expression)
|
||||
val callFactory: (IrConstructorSymbol) -> IrFunctionAccessExpression = when (expression) {
|
||||
is IrConstructorCall -> { constructorSymbol ->
|
||||
IrConstructorCallImpl.fromSymbolOwner(
|
||||
expression.startOffset, expression.endOffset, expression.type, constructorSymbol, expression.origin
|
||||
)
|
||||
}
|
||||
is IrDelegatingConstructorCall -> { constructorSymbol ->
|
||||
IrDelegatingConstructorCallImpl.fromSymbolOwner(
|
||||
expression.startOffset, expression.endOffset, expression.type, constructorSymbol
|
||||
)
|
||||
}
|
||||
is IrEnumConstructorCall -> { constructorSymbol ->
|
||||
IrEnumConstructorCallImpl(
|
||||
expression.startOffset, expression.endOffset, expression.type, constructorSymbol,
|
||||
expression.typeArgumentsCount, expression.valueArgumentsCount
|
||||
)
|
||||
}
|
||||
else -> error("Unknown constructor call type:\n${expression.dump()}")
|
||||
}
|
||||
context.createJvmIrBuilder(currentScope.symbol, expression).irBlock {
|
||||
buildReplacement(function, expression, newConstructor)
|
||||
buildReplacement(function, expression, newConstructor) { callFactory(it as IrConstructorSymbol) }
|
||||
}.unwrapBlock()
|
||||
}
|
||||
}
|
||||
@@ -1039,7 +1111,9 @@ internal class JvmMultiFieldValueClassLowering(
|
||||
return super.visitStringConcatenation(expression)
|
||||
}
|
||||
|
||||
private fun IrBlockBuilder.makeNewArguments(oldArguments: List<IrExpression?>, structure: List<RemappedParameter>): List<IrExpression?> {
|
||||
private fun IrBlockBuilder.makeNewArguments(
|
||||
oldArguments: List<IrExpression?>, structure: List<RemappedParameter>
|
||||
): List<IrExpression?> {
|
||||
val argumentSizes: List<Int> = structure.map { argTemplate -> argTemplate.valueParameters.size }
|
||||
val newArguments = (oldArguments zip argumentSizes).flatMapIndexed { index, (oldArgument, parametersCount) ->
|
||||
when {
|
||||
@@ -1271,7 +1345,7 @@ internal class JvmMultiFieldValueClassLowering(
|
||||
+irCall(rootNode.primaryConstructorImpl).apply {
|
||||
copyTypeArgumentsFrom(expression)
|
||||
val flattenedGetterExpressions =
|
||||
instance.makeFlattenedGetterExpressions(this@flattenExpressionTo, ::registerPossibleExtraBoxUsage)
|
||||
instance.makeFlattenedGetterExpressions(this@flattenExpressionTo, irCurrentClass, ::registerPossibleExtraBoxUsage)
|
||||
for ((index, leafExpression) in flattenedGetterExpressions.withIndex()) {
|
||||
putValueArgument(index, leafExpression)
|
||||
}
|
||||
@@ -1290,15 +1364,14 @@ internal class JvmMultiFieldValueClassLowering(
|
||||
return
|
||||
}
|
||||
val expressionInstance = rootNode.createInstanceFromBox(
|
||||
this, transformedExpression, getOptimizedPublicAccess(rootNode.mfvc), ::variablesSaver,
|
||||
this, transformedExpression, AccessType.ChooseEffective, ::variablesSaver,
|
||||
)
|
||||
require(expressionInstance.size == instance.size) { "Incompatible assignment sizes: ${expressionInstance.size}, ${instance.size}" }
|
||||
instance.addSetterStatements(this, expressionInstance.makeFlattenedGetterExpressions(this, ::registerPossibleExtraBoxUsage))
|
||||
instance.addSetterStatements(
|
||||
this, expressionInstance.makeFlattenedGetterExpressions(this, irCurrentClass, ::registerPossibleExtraBoxUsage)
|
||||
)
|
||||
}
|
||||
|
||||
private fun getOptimizedPublicAccess(parent: IrClass): AccessType =
|
||||
currentScope?.irElement?.let { getOptimizedPublicAccess(it, parent) } ?: AccessType.AlwaysPublic
|
||||
|
||||
/**
|
||||
* Removes boxing when the result is not used
|
||||
*/
|
||||
|
||||
+4
-4
@@ -82,10 +82,10 @@ internal abstract class JvmValueClassAbstractLowering(
|
||||
|
||||
private fun transformFlattenedConstructor(function: IrConstructor, replacement: IrConstructor): List<IrDeclaration> {
|
||||
replacement.valueParameters.forEach {
|
||||
visitParameter(it)
|
||||
it.defaultValue?.patchDeclarationParents(replacement)
|
||||
visitParameter(it)
|
||||
}
|
||||
allScopes.push(createScope(function))
|
||||
allScopes.push(createScope(replacement))
|
||||
replacement.body = function.body?.transform(this, null)?.patchDeclarationParents(replacement)
|
||||
allScopes.pop()
|
||||
return listOf(replacement)
|
||||
@@ -110,8 +110,8 @@ internal abstract class JvmValueClassAbstractLowering(
|
||||
|
||||
private fun transformSimpleFunctionFlat(function: IrSimpleFunction, replacement: IrSimpleFunction): List<IrDeclaration> {
|
||||
replacement.valueParameters.forEach {
|
||||
visitParameter(it)
|
||||
it.defaultValue?.patchDeclarationParents(replacement)
|
||||
visitParameter(it)
|
||||
}
|
||||
allScopes.push(createScope(replacement))
|
||||
replacement.body = function.body?.transform(this, null)?.patchDeclarationParents(replacement)
|
||||
@@ -170,7 +170,7 @@ internal abstract class JvmValueClassAbstractLowering(
|
||||
|
||||
// Anonymous initializers in inline classes are processed when building the primary constructor.
|
||||
final override fun visitAnonymousInitializerNew(declaration: IrAnonymousInitializer): IrStatement =
|
||||
if ((declaration.parent as? IrClass)?.isSpecificLoweringLogicApplicable() == true)
|
||||
if ((declaration.parent as? IrClass)?.isSpecificLoweringLogicApplicable() == true && !declaration.isStatic)
|
||||
declaration
|
||||
else
|
||||
super.visitAnonymousInitializerNew(declaration)
|
||||
|
||||
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.backend.jvm
|
||||
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.erasedUpperBound
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.isInlineClassType
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.isValueClassType
|
||||
import org.jetbrains.kotlin.builtins.StandardNames
|
||||
import org.jetbrains.kotlin.codegen.state.InfoForMangling
|
||||
import org.jetbrains.kotlin.codegen.state.collectFunctionSignatureForManglingSuffix
|
||||
@@ -107,7 +108,7 @@ object InlineClassAbi {
|
||||
// TODO: Move suspend function view creation before JvmInlineClassLowering.
|
||||
if (addContinuation)
|
||||
valueParameters.map { it.asInfoForMangling() } +
|
||||
InfoForMangling(FqNameUnsafe("kotlin.coroutines.Continuation"), isInline = false, isNullable = false)
|
||||
InfoForMangling(FqNameUnsafe("kotlin.coroutines.Continuation"), isValue = false, isNullable = false)
|
||||
else
|
||||
valueParameters.map { it.asInfoForMangling() },
|
||||
returnType?.asInfoForMangling()
|
||||
@@ -116,7 +117,7 @@ object InlineClassAbi {
|
||||
private fun IrType.asInfoForMangling(): InfoForMangling =
|
||||
InfoForMangling(
|
||||
erasedUpperBound.fqNameWhenAvailable!!.toUnsafe(),
|
||||
isInline = isInlineClassType(),
|
||||
isValue = isValueClassType(),
|
||||
isNullable = isNullable()
|
||||
)
|
||||
|
||||
|
||||
+11
-8
@@ -271,12 +271,11 @@ class MemoizedMultiFieldValueClassReplacements(
|
||||
createStaticReplacement(function)
|
||||
}
|
||||
|
||||
function is IrSimpleFunction && !function.isFromJava() &&
|
||||
function.fullValueParameterList.any { it.type.needsMfvcFlattening() } &&
|
||||
(!function.isFakeOverride ||
|
||||
findSuperDeclaration(function, false, context.state.jvmDefaultMode)
|
||||
in bindingOldFunctionToParameterTemplateStructure) ->
|
||||
createMethodReplacement(function)
|
||||
function is IrSimpleFunction && !function.isFromJava() && function.fullValueParameterList.any { it.type.needsMfvcFlattening() } && run {
|
||||
if (!function.isFakeOverride) return@run true
|
||||
val superDeclaration = findSuperDeclaration(function, false, context.state.jvmDefaultMode)
|
||||
getReplacementFunction(superDeclaration) != null
|
||||
} -> createMethodReplacement(function)
|
||||
|
||||
else -> null
|
||||
}
|
||||
@@ -341,7 +340,9 @@ class MemoizedMultiFieldValueClassReplacements(
|
||||
|
||||
private fun getRegularClassMfvcPropertyNode(property: IrProperty): IntermediateMfvcNode? {
|
||||
val parent = property.parent
|
||||
val types = listOfNotNull(property.backingField?.takeUnless { property.isDelegated }?.type, property.getter?.returnType)
|
||||
val types = listOfNotNull(
|
||||
property.backingFieldIfNotToRemove?.takeUnless { property.isDelegated }?.type, property.getter?.returnType
|
||||
)
|
||||
return when {
|
||||
types.isEmpty() || types.any { !it.needsMfvcFlattening() } -> null
|
||||
parent !is IrClass -> null
|
||||
@@ -364,6 +365,8 @@ class MemoizedMultiFieldValueClassReplacements(
|
||||
private fun useRootNode(parent: IrClass, property: IrProperty): Boolean {
|
||||
val getter = property.getter
|
||||
if (getter != null && (getter.contextReceiverParametersCount > 0 || getter.extensionReceiverParameter != null)) return false
|
||||
return parent.isMultiFieldValueClass && (getter?.isStatic ?: property.backingField?.isStatic) == false
|
||||
return parent.isMultiFieldValueClass && (getter?.isStatic ?: property.backingFieldIfNotToRemove?.isStatic) == false
|
||||
}
|
||||
|
||||
private val IrProperty.backingFieldIfNotToRemove get() = backingField?.takeUnless { it in getFieldsToRemove(this.parentAsClass) }
|
||||
}
|
||||
|
||||
+9
-2
@@ -96,8 +96,15 @@ abstract class MemoizedValueClassAbstractReplacements(
|
||||
// In case this property is declared in an object in another file which is not yet lowered, its backing field will
|
||||
// be made static later. We have to handle it here though, because this new property will be saved to the cache
|
||||
// and reused when lowering the same call in all subsequent files, which would be incorrect if it was not lowered.
|
||||
backingField = context.cachedDeclarations.getStaticBackingField(propertySymbol.owner)
|
||||
?: propertySymbol.owner.backingField
|
||||
val existingBackingField = propertySymbol.owner.backingField
|
||||
val skipExistingBackingField = existingBackingField != null && with(context.multiFieldValueClassReplacements) {
|
||||
getMfvcFieldNode(existingBackingField)
|
||||
existingBackingField in getFieldsToRemove(propertySymbol.owner.parentAsClass)
|
||||
}
|
||||
if (!skipExistingBackingField) {
|
||||
backingField = context.cachedDeclarations.getStaticBackingField(propertySymbol.owner)
|
||||
?: existingBackingField
|
||||
}
|
||||
}
|
||||
}
|
||||
correspondingPropertySymbol = property.symbol
|
||||
|
||||
@@ -6,7 +6,8 @@
|
||||
package org.jetbrains.kotlin.backend.jvm
|
||||
|
||||
import org.jetbrains.kotlin.backend.jvm.NameableMfvcNodeImpl.Companion.MethodFullNameMode
|
||||
import org.jetbrains.kotlin.backend.jvm.NameableMfvcNodeImpl.Companion.MethodFullNameMode.*
|
||||
import org.jetbrains.kotlin.backend.jvm.NameableMfvcNodeImpl.Companion.MethodFullNameMode.Getter
|
||||
import org.jetbrains.kotlin.backend.jvm.NameableMfvcNodeImpl.Companion.MethodFullNameMode.UnboxFunction
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.erasedUpperBound
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.isMultiFieldValueClassType
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
||||
@@ -84,6 +85,7 @@ fun makeTypeArgumentsFromType(type: IrSimpleType): TypeArguments {
|
||||
|
||||
sealed interface NameableMfvcNode : MfvcNode {
|
||||
val namedNodeImpl: NameableMfvcNodeImpl
|
||||
val hasPureUnboxMethod: Boolean
|
||||
}
|
||||
|
||||
val NameableMfvcNode.nameParts: List<Name>
|
||||
@@ -96,15 +98,12 @@ val NameableMfvcNode.fullMethodName: Name
|
||||
get() = namedNodeImpl.fullMethodName
|
||||
val NameableMfvcNode.fullFieldName: Name
|
||||
get() = namedNodeImpl.fullFieldName
|
||||
val NameableMfvcNode.hasPureUnboxMethod: Boolean
|
||||
get() = namedNodeImpl.hasPureUnboxMethod
|
||||
|
||||
|
||||
class NameableMfvcNodeImpl(
|
||||
methodFullNameMode: MethodFullNameMode,
|
||||
val nameParts: List<Name>,
|
||||
val unboxMethod: IrSimpleFunction,
|
||||
val hasPureUnboxMethod: Boolean,
|
||||
) {
|
||||
val fullMethodName = makeFullMethodName(methodFullNameMode, nameParts)
|
||||
val fullFieldName = makeFullFieldName(nameParts)
|
||||
@@ -239,8 +238,8 @@ val MfvcNodeWithSubnodes.leaves: List<LeafMfvcNode>
|
||||
get() = subnodesImpl.leaves
|
||||
val MfvcNodeWithSubnodes.fields: List<IrField>?
|
||||
get() = subnodesImpl.fields
|
||||
val RootMfvcNode.fields: List<IrField>
|
||||
get() = subnodesImpl.fields!!
|
||||
val RootMfvcNode.fields: List<IrField>?
|
||||
get() = subnodesImpl.fields
|
||||
val MfvcNodeWithSubnodes.indices: IntRange
|
||||
get() = subnodesImpl.indices
|
||||
val MfvcNodeWithSubnodes.subnodeIndices: Map<NameableMfvcNode, IntRange>
|
||||
@@ -286,9 +285,11 @@ class LeafMfvcNode(
|
||||
nameParts: List<Name>,
|
||||
val field: IrField?,
|
||||
unboxMethod: IrSimpleFunction,
|
||||
hasPureUnboxMethod: Boolean,
|
||||
defaultMethodsImplementationSourceNode: UnboxFunctionImplementation
|
||||
) : NameableMfvcNode {
|
||||
override val namedNodeImpl: NameableMfvcNodeImpl = NameableMfvcNodeImpl(methodFullNameMode, nameParts, unboxMethod, hasPureUnboxMethod)
|
||||
|
||||
override val hasPureUnboxMethod: Boolean = defaultMethodsImplementationSourceNode.hasPureUnboxMethod
|
||||
override val namedNodeImpl: NameableMfvcNodeImpl = NameableMfvcNodeImpl(methodFullNameMode, nameParts, unboxMethod)
|
||||
|
||||
override val leavesCount: Int
|
||||
get() = 1
|
||||
@@ -327,10 +328,12 @@ class IntermediateMfvcNode(
|
||||
nameParts: List<Name>,
|
||||
subnodes: List<NameableMfvcNode>,
|
||||
unboxMethod: IrSimpleFunction,
|
||||
hasPureUnboxMethod: Boolean,
|
||||
defaultMethodsImplementationSourceNode: UnboxFunctionImplementation,
|
||||
val rootNode: RootMfvcNode, // root node corresponding type of the node
|
||||
) : NameableMfvcNode, MfvcNodeWithSubnodes {
|
||||
override val namedNodeImpl: NameableMfvcNodeImpl = NameableMfvcNodeImpl(methodFullNameMode, nameParts, unboxMethod, hasPureUnboxMethod)
|
||||
override val hasPureUnboxMethod: Boolean =
|
||||
defaultMethodsImplementationSourceNode.hasPureUnboxMethod && subnodes.all { it.hasPureUnboxMethod }
|
||||
override val namedNodeImpl: NameableMfvcNodeImpl = NameableMfvcNodeImpl(methodFullNameMode, nameParts, unboxMethod)
|
||||
override val subnodesImpl: MfvcNodeWithSubnodesImpl = MfvcNodeWithSubnodesImpl(subnodes, unboxMethod)
|
||||
override val leavesCount
|
||||
get() = leaves.size
|
||||
@@ -401,7 +404,7 @@ class RootMfvcNode internal constructor(
|
||||
override val leavesUnboxMethods: List<IrSimpleFunction> = collectLeavesUnboxMethods()
|
||||
|
||||
init {
|
||||
require(type.needsMfvcFlattening()) { "MFVC type expected but got% ${type.render()}" }
|
||||
require(type.needsMfvcFlattening()) { "MFVC type expected but got: ${type.render()}" }
|
||||
for (constructor in listOf(oldPrimaryConstructor, newPrimaryConstructor)) {
|
||||
require(constructor.isPrimary) { "Expected a primary constructor but got:\n${constructor.dump()}" }
|
||||
}
|
||||
|
||||
@@ -7,10 +7,10 @@ package org.jetbrains.kotlin.backend.jvm
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||
import org.jetbrains.kotlin.backend.common.lower.irBlockBody
|
||||
import org.jetbrains.kotlin.backend.common.lower.parents
|
||||
import org.jetbrains.kotlin.backend.jvm.IrPropertyOrIrField.Field
|
||||
import org.jetbrains.kotlin.backend.jvm.IrPropertyOrIrField.Property
|
||||
import org.jetbrains.kotlin.backend.jvm.NameableMfvcNodeImpl.Companion.MethodFullNameMode
|
||||
import org.jetbrains.kotlin.backend.jvm.UnboxFunctionImplementation.*
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.createJvmIrBuilder
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.erasedUpperBound
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.upperBound
|
||||
@@ -18,7 +18,6 @@ import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.descriptors.MultiFieldValueClassRepresentation
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.builders.*
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.buildConstructor
|
||||
@@ -36,7 +35,7 @@ import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
|
||||
fun createLeafMfvcNode(
|
||||
parent: IrDeclarationContainer,
|
||||
parent: IrClass,
|
||||
context: JvmBackendContext,
|
||||
type: IrType,
|
||||
methodFullNameMode: MethodFullNameMode,
|
||||
@@ -44,7 +43,7 @@ fun createLeafMfvcNode(
|
||||
fieldAnnotations: List<IrConstructorCall>,
|
||||
static: Boolean,
|
||||
overriddenNode: LeafMfvcNode?,
|
||||
defaultMethodsImplementationSourceNode: Pair<IrSimpleFunction?, LeafMfvcNode>?, // used if the getter was custom and need to call it.
|
||||
defaultMethodsImplementationSourceNode: UnboxFunctionImplementation,
|
||||
oldGetter: IrSimpleFunction?,
|
||||
modality: Modality,
|
||||
oldPropertyBackingField: IrField?,
|
||||
@@ -79,22 +78,19 @@ fun createLeafMfvcNode(
|
||||
modality,
|
||||
) { receiver -> irGetField(if (field!!.isStatic) null else irGet(receiver!!), field) }
|
||||
|
||||
return LeafMfvcNode(type, methodFullNameMode, nameParts, field, unboxMethod, defaultMethodsImplementationSourceNode.isPure())
|
||||
return LeafMfvcNode(type, methodFullNameMode, nameParts, field, unboxMethod, defaultMethodsImplementationSourceNode)
|
||||
}
|
||||
|
||||
private fun Pair<IrSimpleFunction?, NameableMfvcNode>?.isPure(): Boolean {
|
||||
val (outer, inner) = this ?: return true
|
||||
return outer == null && inner.hasPureUnboxMethod
|
||||
}
|
||||
fun IrClass.isKotlinExternalStub() = origin == IrDeclarationOrigin.IR_EXTERNAL_DECLARATION_STUB
|
||||
|
||||
private fun makeUnboxMethod(
|
||||
context: JvmBackendContext,
|
||||
fullMethodName: Name,
|
||||
type: IrType,
|
||||
parent: IrDeclarationParent,
|
||||
parent: IrClass,
|
||||
overriddenNode: NameableMfvcNode?,
|
||||
static: Boolean,
|
||||
defaultMethodsImplementationSourceNode: Pair<IrSimpleFunction?, NameableMfvcNode>?,
|
||||
defaultMethodsImplementationSourceNode: UnboxFunctionImplementation,
|
||||
oldGetter: IrSimpleFunction?,
|
||||
modality: Modality,
|
||||
makeOptimizedExpression: IrBuilderWithScope.(receiver: IrValueDeclaration?) -> IrExpression,
|
||||
@@ -113,23 +109,63 @@ private fun makeUnboxMethod(
|
||||
}
|
||||
|
||||
return res.apply {
|
||||
body = with(context.createJvmIrBuilder(this.symbol)) {
|
||||
val receiver = dispatchReceiverParameter
|
||||
if (defaultMethodsImplementationSourceNode == null) {
|
||||
irExprBody(makeOptimizedExpression(receiver))
|
||||
} else {
|
||||
val (outer, inner) = defaultMethodsImplementationSourceNode
|
||||
val receiverExpression = receiver?.let { irGet(it) }
|
||||
val outerCall = if (outer == null) receiverExpression else irCall(outer).apply { dispatchReceiver = receiverExpression }
|
||||
val innerCall = irCall(inner.unboxMethod).apply { dispatchReceiver = outerCall }
|
||||
irExprBody(innerCall)
|
||||
if (!parent.isKotlinExternalStub()) {
|
||||
body = with(context.createJvmIrBuilder(this.symbol)) {
|
||||
val receiver = dispatchReceiverParameter
|
||||
if (defaultMethodsImplementationSourceNode.hasPureUnboxMethod) {
|
||||
irExprBody(makeOptimizedExpression(receiver))
|
||||
} else {
|
||||
val receiverExpression: IrExpression? = receiver?.let { irGet(it) }
|
||||
val unboxMethodsToCall = when (defaultMethodsImplementationSourceNode) {
|
||||
DefaultUnboxFunctionImplementation -> error("$defaultMethodsImplementationSourceNode is expected to be pure")
|
||||
ExternalUnboxFunctionImplementation -> error("${parent.render()} is expected to be external")
|
||||
is DelegatingUnboxFunctionImplementation -> listOf(defaultMethodsImplementationSourceNode.node.unboxMethod)
|
||||
is CustomUnboxFunctionImplementation -> listOfNotNull(
|
||||
defaultMethodsImplementationSourceNode.getter,
|
||||
(defaultMethodsImplementationSourceNode.node as? NameableMfvcNode)?.unboxMethod
|
||||
)
|
||||
}
|
||||
val expression = unboxMethodsToCall.fold(receiverExpression) { arg, f -> irCall(f).apply { dispatchReceiver = arg } }
|
||||
irExprBody(expression!!)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sealed class UnboxFunctionImplementation {
|
||||
abstract val hasPureUnboxMethod: Boolean
|
||||
|
||||
object DefaultUnboxFunctionImplementation : UnboxFunctionImplementation() {
|
||||
override val hasPureUnboxMethod: Boolean get() = true
|
||||
}
|
||||
|
||||
object ExternalUnboxFunctionImplementation : UnboxFunctionImplementation() {
|
||||
override val hasPureUnboxMethod: Boolean get() = false
|
||||
}
|
||||
|
||||
data class DelegatingUnboxFunctionImplementation(val node: NameableMfvcNode) : UnboxFunctionImplementation() {
|
||||
override val hasPureUnboxMethod: Boolean = node.hasPureUnboxMethod
|
||||
}
|
||||
|
||||
data class CustomUnboxFunctionImplementation(val getter: IrSimpleFunction, val node: MfvcNode) : UnboxFunctionImplementation() {
|
||||
override val hasPureUnboxMethod: Boolean get() = false
|
||||
}
|
||||
|
||||
operator fun get(name: Name): UnboxFunctionImplementation {
|
||||
fun nextNode(node: MfvcNode) = (node as MfvcNodeWithSubnodes)[name]!!
|
||||
return when (this) {
|
||||
is CustomUnboxFunctionImplementation -> copy(node = nextNode(node))
|
||||
is DelegatingUnboxFunctionImplementation -> copy(node = nextNode(node))
|
||||
DefaultUnboxFunctionImplementation -> DefaultUnboxFunctionImplementation
|
||||
ExternalUnboxFunctionImplementation -> ExternalUnboxFunctionImplementation
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun createNameableMfvcNodes(
|
||||
parent: IrDeclarationContainer,
|
||||
parent: IrClass,
|
||||
context: JvmBackendContext,
|
||||
type: IrSimpleType,
|
||||
typeArguments: TypeArguments,
|
||||
@@ -138,7 +174,7 @@ fun createNameableMfvcNodes(
|
||||
fieldAnnotations: List<IrConstructorCall>,
|
||||
static: Boolean,
|
||||
overriddenNode: NameableMfvcNode?,
|
||||
defaultMethodsImplementationSourceNode: Pair<IrSimpleFunction?, NameableMfvcNode>?, // used if the getter was custom and need to call it.
|
||||
defaultMethodsImplementationSourceNode: UnboxFunctionImplementation,
|
||||
oldGetter: IrSimpleFunction?,
|
||||
modality: Modality,
|
||||
oldPropertyBackingField: IrField?,
|
||||
@@ -152,7 +188,7 @@ fun createNameableMfvcNodes(
|
||||
fieldAnnotations,
|
||||
static,
|
||||
overriddenNode as IntermediateMfvcNode?,
|
||||
defaultMethodsImplementationSourceNode?.let { (outer, inner) -> outer to (inner as IntermediateMfvcNode) },
|
||||
defaultMethodsImplementationSourceNode,
|
||||
oldGetter,
|
||||
modality,
|
||||
oldPropertyBackingField,
|
||||
@@ -165,14 +201,14 @@ fun createNameableMfvcNodes(
|
||||
fieldAnnotations,
|
||||
static,
|
||||
overriddenNode as LeafMfvcNode?,
|
||||
defaultMethodsImplementationSourceNode?.let { (outer, inner) -> outer to (inner as LeafMfvcNode) },
|
||||
defaultMethodsImplementationSourceNode,
|
||||
oldGetter,
|
||||
modality,
|
||||
oldPropertyBackingField
|
||||
)
|
||||
|
||||
fun createIntermediateMfvcNode(
|
||||
parent: IrDeclarationContainer,
|
||||
parent: IrClass,
|
||||
context: JvmBackendContext,
|
||||
type: IrSimpleType,
|
||||
typeArguments: TypeArguments,
|
||||
@@ -181,7 +217,7 @@ fun createIntermediateMfvcNode(
|
||||
fieldAnnotations: List<IrConstructorCall>,
|
||||
static: Boolean,
|
||||
overriddenNode: IntermediateMfvcNode?,
|
||||
defaultMethodsImplementationSourceNode: Pair<IrSimpleFunction?, IntermediateMfvcNode>?, // used if the getter was custom and need to call it.
|
||||
defaultMethodsImplementationSourceNode: UnboxFunctionImplementation?,
|
||||
oldGetter: IrSimpleFunction?,
|
||||
modality: Modality,
|
||||
oldPropertyBackingField: IrField?,
|
||||
@@ -202,15 +238,12 @@ fun createIntermediateMfvcNode(
|
||||
val newType = type.substitute(typeArguments) as IrSimpleType
|
||||
val newTypeArguments = typeArguments.toMutableMap().apply { putAll(makeTypeArgumentsFromType(newType)) }
|
||||
val newDefaultMethodsImplementationSourceNode = when {
|
||||
defaultMethodsImplementationSourceNode != null -> {
|
||||
val (outer, inner) = defaultMethodsImplementationSourceNode
|
||||
require(!useOldGetter) { "Multiple non-default getters:\n\n${outer?.dump()}\n\n${oldGetter?.dump()}" }
|
||||
outer to inner[name]!!
|
||||
}
|
||||
|
||||
shadowBackingFieldProperty != null -> null to replacements.getMfvcPropertyNode(shadowBackingFieldProperty)!!
|
||||
useOldGetter -> oldGetter!! to rootNode[name]!!
|
||||
else -> null
|
||||
defaultMethodsImplementationSourceNode != null -> defaultMethodsImplementationSourceNode[name]
|
||||
shadowBackingFieldProperty != null -> DelegatingUnboxFunctionImplementation(
|
||||
replacements.getMfvcPropertyNode(shadowBackingFieldProperty)!!
|
||||
)
|
||||
useOldGetter -> CustomUnboxFunctionImplementation(oldGetter!!, rootNode[name]!!)
|
||||
else -> DefaultUnboxFunctionImplementation
|
||||
}
|
||||
createNameableMfvcNodes(
|
||||
parent,
|
||||
@@ -231,56 +264,78 @@ fun createIntermediateMfvcNode(
|
||||
|
||||
val fullMethodName = NameableMfvcNodeImpl.makeFullMethodName(methodFullNameMode, nameParts)
|
||||
|
||||
val unboxMethod = if (useOldGetter) oldGetter!! else makeUnboxMethod(
|
||||
context, fullMethodName, type, parent, overriddenNode, static, defaultMethodsImplementationSourceNode, oldGetter, modality
|
||||
) { receiver ->
|
||||
val valueArguments = subnodes.flatMap { it.fields!! }
|
||||
.map { field -> irGetField(if (field.isStatic) null else irGet(receiver!!), field) }
|
||||
rootNode.makeBoxedExpression(this, typeArguments, valueArguments, registerPossibleExtraBoxCreation = {})
|
||||
val unboxMethod: IrSimpleFunction
|
||||
val unboxFunctionImplementation: UnboxFunctionImplementation
|
||||
if (useOldGetter) {
|
||||
unboxMethod = oldGetter!!
|
||||
unboxFunctionImplementation = defaultMethodsImplementationSourceNode ?: CustomUnboxFunctionImplementation(unboxMethod, rootNode)
|
||||
} else {
|
||||
unboxFunctionImplementation = defaultMethodsImplementationSourceNode ?: DefaultUnboxFunctionImplementation
|
||||
unboxMethod = makeUnboxMethod(
|
||||
context, fullMethodName, type, parent, overriddenNode, static, unboxFunctionImplementation, oldGetter, modality
|
||||
) { receiver ->
|
||||
val valueArguments = subnodes.flatMap { it.fields!! }
|
||||
.map { field -> irGetField(if (field.isStatic) null else irGet(receiver!!), field) }
|
||||
rootNode.makeBoxedExpression(this, typeArguments, valueArguments, registerPossibleExtraBoxCreation = {})
|
||||
}
|
||||
}
|
||||
|
||||
val hasPureUnboxMethod = defaultMethodsImplementationSourceNode.isPure() && subnodes.all { it.hasPureUnboxMethod }
|
||||
return IntermediateMfvcNode(
|
||||
type, methodFullNameMode, nameParts, subnodes, unboxMethod, hasPureUnboxMethod, rootNode
|
||||
)
|
||||
return IntermediateMfvcNode(type, methodFullNameMode, nameParts, subnodes, unboxMethod, unboxFunctionImplementation, rootNode)
|
||||
}
|
||||
|
||||
fun collectPropertiesAfterLowering(irClass: IrClass, context: JvmBackendContext): LinkedHashSet<IrProperty> =
|
||||
LinkedHashSet(collectPropertiesOrFieldsAfterLowering(irClass, context).map { (it as Property).property })
|
||||
|
||||
sealed class IrPropertyOrIrField {
|
||||
data class Property(val property: IrProperty) : IrPropertyOrIrField()
|
||||
data class Field(val field: IrField) : IrPropertyOrIrField()
|
||||
data class Property(val property: IrProperty) : IrPropertyOrIrField() {
|
||||
override fun toString(): String = property.dump()
|
||||
}
|
||||
|
||||
data class Field(val field: IrField) : IrPropertyOrIrField() {
|
||||
override fun toString(): String = field.dump()
|
||||
}
|
||||
}
|
||||
|
||||
fun collectPropertiesOrFieldsAfterLowering(irClass: IrClass, context: JvmBackendContext): LinkedHashSet<IrPropertyOrIrField> =
|
||||
LinkedHashSet<IrPropertyOrIrField>().apply {
|
||||
for (element in irClass.declarations) {
|
||||
if (element is IrField) {
|
||||
val property = element.correspondingPropertySymbol?.owner
|
||||
if (
|
||||
property != null && !property.isDelegated &&
|
||||
!context.multiFieldValueClassReplacements.getFieldsToRemove(element.parentAsClass).contains(element)
|
||||
) {
|
||||
add(Property(property))
|
||||
} else {
|
||||
add(Field(element))
|
||||
}
|
||||
} else if (element is IrSimpleFunction && element.extensionReceiverParameter == null && element.contextReceiverParametersCount == 0) {
|
||||
fun handleField(element: IrField) {
|
||||
val property = element.correspondingPropertySymbol?.owner
|
||||
if (
|
||||
property != null && !property.isDelegated &&
|
||||
!context.multiFieldValueClassReplacements.getFieldsToRemove(element.parentAsClass).contains(element)
|
||||
) {
|
||||
add(Property(property))
|
||||
} else {
|
||||
add(Field(element))
|
||||
}
|
||||
}
|
||||
|
||||
fun handleAccessor(element: IrSimpleFunction) {
|
||||
if (element.extensionReceiverParameter == null && element.contextReceiverParametersCount == 0) {
|
||||
element.correspondingPropertySymbol?.owner?.let { add(Property(it)) }
|
||||
}
|
||||
}
|
||||
|
||||
for (element in irClass.declarations) {
|
||||
when (element) {
|
||||
is IrField -> handleField(element)
|
||||
is IrSimpleFunction -> handleAccessor(element)
|
||||
is IrProperty -> {
|
||||
element.backingField?.let(::handleField)
|
||||
element.getter?.let(::handleAccessor)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrProperty.isStatic(currentContainer: IrDeclarationContainer) =
|
||||
getterIfDeclared(currentContainer)?.isStatic
|
||||
?: backingFieldIfNotDelegate?.isStatic
|
||||
?: error("Property without both getter and backing field")
|
||||
?: error("Property without both getter and backing field:\n${dump()}")
|
||||
|
||||
fun getRootNode(context: JvmBackendContext, mfvc: IrClass): RootMfvcNode {
|
||||
require(mfvc.isMultiFieldValueClass) { "${mfvc.defaultType.render()} does not require flattening" }
|
||||
val oldPrimaryConstructor = mfvc.primaryConstructor!!
|
||||
val oldFields = mfvc.fields.filter { !it.isStatic }.toList()
|
||||
val oldFields = mfvc.declarations.mapNotNull { it as? IrField ?: (it as? IrProperty)?.backingField }.filter { !it.isStatic }
|
||||
val representation = mfvc.multiFieldValueClassRepresentation!!
|
||||
val properties = collectPropertiesAfterLowering(mfvc, context).associateBy { it.isStatic(mfvc) to it.name }
|
||||
|
||||
@@ -288,7 +343,7 @@ fun getRootNode(context: JvmBackendContext, mfvc: IrClass): RootMfvcNode {
|
||||
|
||||
val mfvcNodeWithSubnodesImpl = MfvcNodeWithSubnodesImpl(subnodes, null)
|
||||
val leaves = mfvcNodeWithSubnodesImpl.leaves
|
||||
val fields = mfvcNodeWithSubnodesImpl.fields!!
|
||||
val fields = mfvcNodeWithSubnodesImpl.fields
|
||||
|
||||
val newPrimaryConstructor = makeMfvcPrimaryConstructor(context, oldPrimaryConstructor, mfvc, leaves, fields)
|
||||
val primaryConstructorImpl = makePrimaryConstructorImpl(context, oldPrimaryConstructor, mfvc, leaves, mfvcNodeWithSubnodesImpl)
|
||||
@@ -328,23 +383,24 @@ private fun makeSpecializedEqualsMethod(
|
||||
name = Name.identifier("other")
|
||||
type = mfvc.defaultType.upperBound
|
||||
}
|
||||
|
||||
body = with(context.createJvmIrBuilder(this.symbol)) {
|
||||
if (customEqualsAny != null) {
|
||||
irExprBody(irCall(customEqualsAny).apply {
|
||||
dispatchReceiver = irGet(dispatchReceiverParameter!!)
|
||||
putValueArgument(0, irGet(other))
|
||||
})
|
||||
} else {
|
||||
val leftArgs = oldFields.map { irGetField(irGet(dispatchReceiverParameter!!), it) }
|
||||
val rightArgs = oldFields.map { irGetField(irGet(other), it) }
|
||||
val conjunctions = leftArgs.zip(rightArgs) { l, r -> irEquals(l, r) }
|
||||
irExprBody(conjunctions.reduce { acc, current ->
|
||||
irCall(context.irBuiltIns.andandSymbol).apply {
|
||||
putValueArgument(0, acc)
|
||||
putValueArgument(1, current)
|
||||
}
|
||||
})
|
||||
if (!mfvc.isKotlinExternalStub()) {
|
||||
body = with(context.createJvmIrBuilder(this.symbol)) {
|
||||
if (customEqualsAny != null) {
|
||||
irExprBody(irCall(customEqualsAny).apply {
|
||||
dispatchReceiver = irGet(dispatchReceiverParameter!!)
|
||||
putValueArgument(0, irGet(other))
|
||||
})
|
||||
} else {
|
||||
val leftArgs = oldFields.map { irGetField(irGet(dispatchReceiverParameter!!), it) }
|
||||
val rightArgs = oldFields.map { irGetField(irGet(other), it) }
|
||||
val conjunctions = leftArgs.zip(rightArgs) { l, r -> irEquals(l, r) }
|
||||
irExprBody(conjunctions.reduce { acc, current ->
|
||||
irCall(context.irBuiltIns.andandSymbol).apply {
|
||||
putValueArgument(0, acc)
|
||||
putValueArgument(1, current)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -366,12 +422,14 @@ private fun makeBoxMethod(
|
||||
}.toMap()
|
||||
returnType = returnType.substitute(mapping)
|
||||
val parameters = leaves.map { leaf -> addValueParameter(leaf.fullFieldName, leaf.type.substitute(mapping)) }
|
||||
body = with(context.createJvmIrBuilder(this.symbol)) {
|
||||
irExprBody(irCall(newPrimaryConstructor).apply {
|
||||
for ((index, parameter) in parameters.withIndex()) {
|
||||
putValueArgument(index, irGet(parameter))
|
||||
}
|
||||
})
|
||||
if (!mfvc.isKotlinExternalStub()) {
|
||||
body = with(context.createJvmIrBuilder(this.symbol)) {
|
||||
irExprBody(irCall(newPrimaryConstructor).apply {
|
||||
for ((index, parameter) in parameters.withIndex()) {
|
||||
putValueArgument(index, irGet(parameter))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -414,7 +472,7 @@ private fun makeMfvcPrimaryConstructor(
|
||||
oldPrimaryConstructor: IrConstructor,
|
||||
mfvc: IrClass,
|
||||
leaves: List<LeafMfvcNode>,
|
||||
fields: List<IrField>
|
||||
fields: List<IrField>?
|
||||
) = context.irFactory.buildConstructor {
|
||||
updateFrom(oldPrimaryConstructor)
|
||||
visibility = DescriptorVisibilities.PRIVATE
|
||||
@@ -425,10 +483,12 @@ private fun makeMfvcPrimaryConstructor(
|
||||
this.parent = mfvc
|
||||
val parameters = leaves.map { addValueParameter(it.fullFieldName, it.type) }
|
||||
val irConstructor = this@apply
|
||||
body = context.createIrBuilder(irConstructor.symbol).irBlockBody(irConstructor) {
|
||||
+irDelegatingConstructorCall(context.irBuiltIns.anyClass.owner.constructors.single())
|
||||
for ((field, parameter) in fields zip parameters) {
|
||||
+irSetField(irGet(mfvc.thisReceiver!!), field, irGet(parameter))
|
||||
if (!mfvc.isKotlinExternalStub()) {
|
||||
body = context.createIrBuilder(irConstructor.symbol).irBlockBody(irConstructor) {
|
||||
+irDelegatingConstructorCall(context.irBuiltIns.anyClass.owner.constructors.single())
|
||||
for ((field, parameter) in fields!! zip parameters) {
|
||||
+irSetField(irGet(mfvc.thisReceiver!!), field, irGet(parameter))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -455,7 +515,7 @@ private fun makeRootMfvcNodeSubnodes(
|
||||
oldBackingField?.annotations ?: listOf(),
|
||||
static,
|
||||
overriddenNode,
|
||||
null,
|
||||
DefaultUnboxFunctionImplementation,
|
||||
oldGetter.takeIf { static },
|
||||
Modality.FINAL,
|
||||
oldBackingField,
|
||||
@@ -471,12 +531,13 @@ private fun updateAnnotationsAndPropertyFromOldProperty(
|
||||
node: MfvcNode,
|
||||
) {
|
||||
if (node is LeafMfvcNode) return
|
||||
oldProperty.backingField?.let { context.multiFieldValueClassReplacements.addFieldToRemove(it.parentAsClass, it) }
|
||||
oldProperty.backingField = null
|
||||
oldProperty.backingField?.let {
|
||||
context.multiFieldValueClassReplacements.addFieldToRemove(it.parentAsClass, it)
|
||||
}
|
||||
}
|
||||
|
||||
fun createIntermediateNodeForMfvcPropertyOfRegularClass(
|
||||
parent: IrDeclarationContainer,
|
||||
parent: IrClass,
|
||||
context: JvmBackendContext,
|
||||
oldProperty: IrProperty,
|
||||
): IntermediateMfvcNode {
|
||||
@@ -488,16 +549,17 @@ fun createIntermediateNodeForMfvcPropertyOfRegularClass(
|
||||
val static = oldProperty.isStatic(parent)
|
||||
val overriddenNode = oldGetter?.let { getOverriddenNode(context.multiFieldValueClassReplacements, it) as IntermediateMfvcNode? }
|
||||
val modality = if (oldGetter == null || oldGetter.modality == Modality.FINAL) Modality.FINAL else oldGetter.modality
|
||||
val defaultMethodsImplementationSourceNode = if (parent.isKotlinExternalStub()) ExternalUnboxFunctionImplementation else null
|
||||
return createIntermediateMfvcNode(
|
||||
parent, context, type, makeTypeArgumentsFromType(type), MethodFullNameMode.Getter, listOf(oldProperty.name),
|
||||
fieldAnnotations, static, overriddenNode, null, oldGetter, modality, oldField
|
||||
fieldAnnotations, static, overriddenNode, defaultMethodsImplementationSourceNode, oldGetter, modality, oldField
|
||||
).also {
|
||||
updateAnnotationsAndPropertyFromOldProperty(oldProperty, context, it)
|
||||
}
|
||||
}
|
||||
|
||||
fun createIntermediateNodeForStandaloneMfvcField(
|
||||
parent: IrDeclarationContainer,
|
||||
parent: IrClass,
|
||||
context: JvmBackendContext,
|
||||
oldField: IrField,
|
||||
): IntermediateMfvcNode {
|
||||
@@ -514,19 +576,7 @@ private fun getOverriddenNode(replacements: MemoizedMultiFieldValueClassReplacem
|
||||
.firstOrNull { !it.owner.isFakeOverride }
|
||||
?.let { replacements.getMfvcPropertyNode(it.owner.correspondingPropertySymbol!!.owner) }
|
||||
|
||||
fun getOptimizedPublicAccess(currentElement: IrElement?, parent: IrClass): AccessType {
|
||||
val declaration = currentElement as? IrDeclaration ?: return AccessType.AlwaysPublic
|
||||
for (cur in declaration.parents.filterIsInstance<IrClass>()) {
|
||||
return when {
|
||||
cur == parent -> AccessType.PrivateWhenNoBox
|
||||
cur.isInner -> continue
|
||||
cur.isCompanion -> continue
|
||||
else -> AccessType.AlwaysPublic
|
||||
}
|
||||
}
|
||||
return AccessType.AlwaysPublic
|
||||
}
|
||||
|
||||
private fun IrProperty.getterIfDeclared(parent: IrDeclarationContainer): IrSimpleFunction? = getter?.takeIf { it in parent.declarations }
|
||||
private fun IrProperty.getterIfDeclared(parent: IrDeclarationContainer): IrSimpleFunction? =
|
||||
getter?.takeIf { it in parent.declarations || this in parent.declarations }
|
||||
|
||||
private val IrProperty.backingFieldIfNotDelegate get() = backingField?.takeUnless { isDelegated }
|
||||
|
||||
@@ -23,8 +23,11 @@ interface MfvcNodeInstance {
|
||||
val typeArguments: TypeArguments
|
||||
val type: IrSimpleType
|
||||
|
||||
fun makeFlattenedGetterExpressions(scope: IrBlockBuilder, registerPossibleExtraBoxCreation: () -> Unit): List<IrExpression>
|
||||
fun makeGetterExpression(scope: IrBuilderWithScope, registerPossibleExtraBoxCreation: () -> Unit): IrExpression
|
||||
fun makeFlattenedGetterExpressions(
|
||||
scope: IrBlockBuilder, currentClass: IrClass, registerPossibleExtraBoxCreation: () -> Unit
|
||||
): List<IrExpression>
|
||||
|
||||
fun makeGetterExpression(scope: IrBuilderWithScope, currentClass: IrClass, registerPossibleExtraBoxCreation: () -> Unit): IrExpression
|
||||
operator fun get(name: Name): MfvcNodeInstance?
|
||||
fun makeStatements(scope: IrBuilderWithScope, values: List<IrExpression>): List<IrStatement>
|
||||
}
|
||||
@@ -57,12 +60,12 @@ class ValueDeclarationMfvcNodeInstance(
|
||||
|
||||
override val type: IrSimpleType = makeTypeFromMfvcNodeAndTypeArguments(node, typeArguments)
|
||||
|
||||
override fun makeFlattenedGetterExpressions(scope: IrBlockBuilder, registerPossibleExtraBoxCreation: () -> Unit): List<IrExpression> =
|
||||
override fun makeFlattenedGetterExpressions(scope: IrBlockBuilder, currentClass: IrClass, registerPossibleExtraBoxCreation: () -> Unit): List<IrExpression> =
|
||||
makeFlattenedGetterExpressions(scope as IrBuilderWithScope)
|
||||
|
||||
private fun makeFlattenedGetterExpressions(scope: IrBuilderWithScope): List<IrExpression> = valueDeclarations.map { scope.irGet(it) }
|
||||
|
||||
override fun makeGetterExpression(scope: IrBuilderWithScope, registerPossibleExtraBoxCreation: () -> Unit): IrExpression = when (node) {
|
||||
override fun makeGetterExpression(scope: IrBuilderWithScope, currentClass: IrClass, registerPossibleExtraBoxCreation: () -> Unit): IrExpression = when (node) {
|
||||
is LeafMfvcNode -> makeFlattenedGetterExpressions(scope).single()
|
||||
is MfvcNodeWithSubnodes -> node.makeBoxedExpression(
|
||||
scope, typeArguments, makeFlattenedGetterExpressions(scope), registerPossibleExtraBoxCreation
|
||||
@@ -138,7 +141,7 @@ fun IrExpression?.isRepeatableSetter(): Boolean = when (this) {
|
||||
|
||||
fun IrExpression?.isRepeatableAccessor(): Boolean = isRepeatableGetter() || isRepeatableSetter()
|
||||
|
||||
enum class AccessType { AlwaysPublic, PrivateWhenNoBox, AlwaysPrivate }
|
||||
enum class AccessType { UseFields, ChooseEffective }
|
||||
|
||||
class ReceiverBasedMfvcNodeInstance(
|
||||
private val scope: IrBlockBuilder,
|
||||
@@ -162,20 +165,23 @@ class ReceiverBasedMfvcNodeInstance(
|
||||
}
|
||||
|
||||
override fun makeFlattenedGetterExpressions(
|
||||
scope: IrBlockBuilder, registerPossibleExtraBoxCreation: () -> Unit
|
||||
): List<IrExpression> = when (node) {
|
||||
is LeafMfvcNode -> listOf(makeGetterExpression(scope, registerPossibleExtraBoxCreation))
|
||||
is MfvcNodeWithSubnodes -> when {
|
||||
node is IntermediateMfvcNode && canUsePrivateAccessFor(node) && fields != null ->
|
||||
fields.map { scope.irGetField(makeReceiverCopy(), it) }
|
||||
scope: IrBlockBuilder, currentClass: IrClass, registerPossibleExtraBoxCreation: () -> Unit
|
||||
): List<IrExpression> = makeFlattenedGetterExpressions(scope, currentClass, isInsideRecursion = false, registerPossibleExtraBoxCreation)
|
||||
|
||||
node !is IntermediateMfvcNode || node.hasPureUnboxMethod && (canUsePrivateAccessFor(node) || node.unboxMethod.parentAsClass.isMultiFieldValueClass) ->
|
||||
// We cannot rely 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, registerPossibleExtraBoxCreation) }
|
||||
private fun makeFlattenedGetterExpressions(
|
||||
scope: IrBlockBuilder, currentClass: IrClass, isInsideRecursion: Boolean, registerPossibleExtraBoxCreation: () -> Unit
|
||||
): List<IrExpression> {
|
||||
fun makeRecursiveResult(node: MfvcNodeWithSubnodes) = node.subnodes.flatMap {
|
||||
get(it.name)!!.makeFlattenedGetterExpressions(scope, currentClass, true, registerPossibleExtraBoxCreation)
|
||||
}
|
||||
|
||||
else -> {
|
||||
val value = makeGetterExpression(scope, registerPossibleExtraBoxCreation = { /* The box is definitely useful */ })
|
||||
return when (node) {
|
||||
is LeafMfvcNode -> listOf(makeGetterExpression(scope, currentClass, registerPossibleExtraBoxCreation))
|
||||
is RootMfvcNode -> makeRecursiveResult(node)
|
||||
is IntermediateMfvcNode -> if (isInsideRecursion || node.hasPureUnboxMethod) {
|
||||
makeRecursiveResult(node) // use real getter for fields
|
||||
} else {
|
||||
val value = makeGetterExpression(scope, currentClass, registerPossibleExtraBoxCreation = { /* The box is definitely useful */ })
|
||||
val asVariable = scope.savableStandaloneVariableWithSetter(
|
||||
value,
|
||||
origin = JvmLoweredDeclarationOrigin.TEMPORARY_MULTI_FIELD_VALUE_CLASS_VARIABLE,
|
||||
@@ -185,18 +191,26 @@ class ReceiverBasedMfvcNodeInstance(
|
||||
val root = node.rootNode
|
||||
val variableInstance =
|
||||
root.createInstanceFromBox(scope, typeArguments, scope.irGet(asVariable), accessType, saveVariable)
|
||||
variableInstance.makeFlattenedGetterExpressions(scope, registerPossibleExtraBoxCreation)
|
||||
variableInstance.makeFlattenedGetterExpressions(scope, currentClass, registerPossibleExtraBoxCreation)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun makeGetterExpression(scope: IrBuilderWithScope, registerPossibleExtraBoxCreation: () -> Unit): IrExpression = with(scope) {
|
||||
override fun makeGetterExpression(scope: IrBuilderWithScope, currentClass: IrClass, registerPossibleExtraBoxCreation: () -> Unit): IrExpression = with(scope) {
|
||||
when {
|
||||
node is LeafMfvcNode && canUsePrivateAccessFor(node) && fields != null -> irGetField(makeReceiverCopy(), fields.single())
|
||||
node is IntermediateMfvcNode && accessType == AccessType.AlwaysPrivate && fields != null -> node.makeBoxedExpression(
|
||||
this, typeArguments, fields.map { irGetField(makeReceiverCopy(), it) }, registerPossibleExtraBoxCreation
|
||||
)
|
||||
|
||||
node is RootMfvcNode -> makeReceiverCopy()!!
|
||||
node is LeafMfvcNode && node.hasPureUnboxMethod && canUsePrivateAccess(node, currentClass) && fields != null ->
|
||||
irGetField(makeReceiverCopy(), fields.single())
|
||||
node is LeafMfvcNode && accessType == AccessType.UseFields -> {
|
||||
require(fields != null) { "Invalid getter to $node" }
|
||||
irGetField(makeReceiverCopy(), fields.single())
|
||||
}
|
||||
node is IntermediateMfvcNode && accessType == AccessType.UseFields -> {
|
||||
require(fields != null) { "Invalid getter to $node" }
|
||||
node.makeBoxedExpression(
|
||||
this, typeArguments, fields.map { irGetField(makeReceiverCopy(), it) }, registerPossibleExtraBoxCreation
|
||||
)
|
||||
}
|
||||
unboxMethod != null -> irCall(unboxMethod).apply {
|
||||
val dispatchReceiverParameter = unboxMethod.dispatchReceiverParameter
|
||||
if (dispatchReceiverParameter != null) {
|
||||
@@ -207,14 +221,14 @@ class ReceiverBasedMfvcNodeInstance(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
node is RootMfvcNode -> makeReceiverCopy()!!
|
||||
else -> error("Unbox method must exist for $node")
|
||||
}
|
||||
}
|
||||
|
||||
private fun canUsePrivateAccessFor(node: NameableMfvcNode) =
|
||||
node.hasPureUnboxMethod && accessType == AccessType.PrivateWhenNoBox || accessType == AccessType.AlwaysPrivate
|
||||
private fun canUsePrivateAccess(node: NameableMfvcNode, currentClass: IrClass): Boolean {
|
||||
val sourceClass = node.unboxMethod.parentAsClass.let { if (it.isCompanion) it.parentAsClass else it }
|
||||
return sourceClass == currentClass
|
||||
}
|
||||
|
||||
override fun get(name: Name): ReceiverBasedMfvcNodeInstance? {
|
||||
val (newNode, _) = node.getSubnodeAndIndices(name) ?: return null
|
||||
|
||||
Reference in New Issue
Block a user