[IR] Fix MFVC with type arguments/parameters
#KT-1179
This commit is contained in:
committed by
teamcity
parent
cd432b1371
commit
d0590e4e83
+3
@@ -718,6 +718,9 @@ internal class BridgeLowering(val context: JvmBackendContext) : FileLoweringPass
|
|||||||
is MultiFieldValueClassMapping -> {
|
is MultiFieldValueClassMapping -> {
|
||||||
val count = bridgeRemappedParameter.declarations.fields.size
|
val count = bridgeRemappedParameter.declarations.fields.size
|
||||||
val boxCall = irCall(bridgeRemappedParameter.declarations.boxMethod).apply {
|
val boxCall = irCall(bridgeRemappedParameter.declarations.boxMethod).apply {
|
||||||
|
bridgeRemappedParameter.boxedType.arguments.forEachIndexed { index, argument ->
|
||||||
|
putTypeArgument(index, argument.typeOrNull)
|
||||||
|
}
|
||||||
for (i in 0 until count) {
|
for (i in 0 until count) {
|
||||||
putValueArgument(i, irGet(bridgeExplicitParameters[bridgeIndex++]))
|
putValueArgument(i, irGet(bridgeExplicitParameters[bridgeIndex++]))
|
||||||
}
|
}
|
||||||
|
|||||||
+4
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.ir.expressions.IrExpression
|
|||||||
import org.jetbrains.kotlin.ir.expressions.IrTypeOperator
|
import org.jetbrains.kotlin.ir.expressions.IrTypeOperator
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrTypeOperatorCallImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrTypeOperatorCallImpl
|
||||||
import org.jetbrains.kotlin.ir.types.IrType
|
import org.jetbrains.kotlin.ir.types.IrType
|
||||||
|
import org.jetbrains.kotlin.ir.types.typeOrNull
|
||||||
import org.jetbrains.kotlin.ir.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
import org.jetbrains.kotlin.ir.visitors.*
|
import org.jetbrains.kotlin.ir.visitors.*
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||||
@@ -135,6 +136,9 @@ private class InheritedDefaultMethodsOnClassesLowering(val context: JvmBackendCo
|
|||||||
when (val remappedParameter = structure[i]) {
|
when (val remappedParameter = structure[i]) {
|
||||||
is MultiFieldValueClassMapping ->
|
is MultiFieldValueClassMapping ->
|
||||||
putValueArgument(i, irCall(remappedParameter.declarations.boxMethod).apply {
|
putValueArgument(i, irCall(remappedParameter.declarations.boxMethod).apply {
|
||||||
|
remappedParameter.boxedType.arguments.forEachIndexed { index, argument ->
|
||||||
|
putTypeArgument(index, argument.typeOrNull)
|
||||||
|
}
|
||||||
val boxArgumentsCount = remappedParameter.valueParameters.size
|
val boxArgumentsCount = remappedParameter.valueParameters.size
|
||||||
for (boxArgumentIndex in 0 until boxArgumentsCount) {
|
for (boxArgumentIndex in 0 until boxArgumentsCount) {
|
||||||
putValueArgument(boxArgumentIndex, irGet(sourceFullValueParameterList[flattenedIndex++]))
|
putValueArgument(boxArgumentIndex, irGet(sourceFullValueParameterList[flattenedIndex++]))
|
||||||
|
|||||||
+111
-68
@@ -5,10 +5,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.backend.jvm.lower
|
package org.jetbrains.kotlin.backend.jvm.lower
|
||||||
|
|
||||||
import org.jetbrains.kotlin.backend.common.ir.copyParameterDeclarationsFrom
|
import org.jetbrains.kotlin.backend.common.ir.*
|
||||||
import org.jetbrains.kotlin.backend.common.ir.copyTo
|
|
||||||
import org.jetbrains.kotlin.backend.common.ir.createDispatchReceiverParameter
|
|
||||||
import org.jetbrains.kotlin.backend.common.ir.passTypeArgumentsFrom
|
|
||||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||||
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
||||||
import org.jetbrains.kotlin.backend.common.pop
|
import org.jetbrains.kotlin.backend.common.pop
|
||||||
@@ -21,6 +18,7 @@ import org.jetbrains.kotlin.backend.jvm.MemoizedMultiFieldValueClassReplacements
|
|||||||
import org.jetbrains.kotlin.backend.jvm.MultiFieldValueClassSpecificDeclarations.ImplementationAgnostic
|
import org.jetbrains.kotlin.backend.jvm.MultiFieldValueClassSpecificDeclarations.ImplementationAgnostic
|
||||||
import org.jetbrains.kotlin.backend.jvm.MultiFieldValueClassSpecificDeclarations.VirtualProperty
|
import org.jetbrains.kotlin.backend.jvm.MultiFieldValueClassSpecificDeclarations.VirtualProperty
|
||||||
import org.jetbrains.kotlin.backend.jvm.MultiFieldValueClassTree.InternalNode
|
import org.jetbrains.kotlin.backend.jvm.MultiFieldValueClassTree.InternalNode
|
||||||
|
import org.jetbrains.kotlin.backend.jvm.MultiFieldValueClassTree.Leaf
|
||||||
import org.jetbrains.kotlin.backend.jvm.ir.erasedUpperBound
|
import org.jetbrains.kotlin.backend.jvm.ir.erasedUpperBound
|
||||||
import org.jetbrains.kotlin.backend.jvm.ir.isMultiFieldValueClassType
|
import org.jetbrains.kotlin.backend.jvm.ir.isMultiFieldValueClassType
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
@@ -37,9 +35,7 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
|
|||||||
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
|
||||||
import org.jetbrains.kotlin.ir.symbols.impl.IrAnonymousInitializerSymbolImpl
|
import org.jetbrains.kotlin.ir.symbols.impl.IrAnonymousInitializerSymbolImpl
|
||||||
import org.jetbrains.kotlin.ir.transformStatement
|
import org.jetbrains.kotlin.ir.transformStatement
|
||||||
import org.jetbrains.kotlin.ir.types.IrType
|
import org.jetbrains.kotlin.ir.types.*
|
||||||
import org.jetbrains.kotlin.ir.types.isNullable
|
|
||||||
import org.jetbrains.kotlin.ir.types.makeNotNull
|
|
||||||
import org.jetbrains.kotlin.ir.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||||
@@ -58,39 +54,39 @@ val jvmMultiFieldValueClassPhase = makeIrFilePhase(
|
|||||||
private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmValueClassAbstractLowering(context) {
|
private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmValueClassAbstractLowering(context) {
|
||||||
|
|
||||||
private open inner class ValueDeclarationsRemapper {
|
private open inner class ValueDeclarationsRemapper {
|
||||||
private val symbol2getter = mutableMapOf<IrValueSymbol, ExpressionGenerator<Unit>>()
|
private val symbol2getter = mutableMapOf<IrValueSymbol, ExpressionGenerator>()
|
||||||
private val symbol2setters = mutableMapOf<IrValueSymbol, List<ExpressionSupplier<Unit>?>>()
|
private val symbol2setters = mutableMapOf<IrValueSymbol, List<ExpressionSupplier?>>()
|
||||||
private val knownExpressions = mutableMapOf<IrExpression, ImplementationAgnostic<Unit>>()
|
private val knownExpressions = mutableMapOf<IrExpression, ImplementationAgnostic>()
|
||||||
|
|
||||||
fun remapSymbol(original: IrValueSymbol, replacement: IrValueDeclaration) {
|
fun remapSymbol(original: IrValueSymbol, replacement: IrValueDeclaration) {
|
||||||
symbol2getter[original] = { irGet(replacement) }
|
symbol2getter[original] = { irGet(replacement) }
|
||||||
symbol2setters[original] = if (replacement.isAssignable) listOf { _, value -> irSet(replacement, value) } else listOf(null)
|
symbol2setters[original] = if (replacement.isAssignable) listOf { value -> irSet(replacement, value) } else listOf(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun remapSymbol(
|
fun remapSymbol(
|
||||||
original: IrValueSymbol,
|
original: IrValueSymbol,
|
||||||
unboxed: List<VirtualProperty<Unit>>,
|
unboxed: List<VirtualProperty>,
|
||||||
declarations: MultiFieldValueClassSpecificDeclarations
|
declarations: MultiFieldValueClassSpecificDeclarations
|
||||||
): Unit =
|
): Unit =
|
||||||
remapSymbol(original, declarations.ImplementationAgnostic(unboxed))
|
remapSymbol(original, declarations.ImplementationAgnostic(original.owner.type as IrSimpleType, unboxed))
|
||||||
|
|
||||||
fun remapSymbol(original: IrValueSymbol, unboxed: ImplementationAgnostic<Unit>) {
|
fun remapSymbol(original: IrValueSymbol, unboxed: ImplementationAgnostic) {
|
||||||
symbol2getter[original] = {
|
symbol2getter[original] = {
|
||||||
unboxed.boxedExpression(this, Unit).also { irExpression -> knownExpressions[irExpression] = unboxed }
|
unboxed.boxedExpression(this).also { irExpression -> knownExpressions[irExpression] = unboxed }
|
||||||
}
|
}
|
||||||
symbol2setters[original] = unboxed.virtualFields.map { it.assigner }
|
symbol2setters[original] = unboxed.virtualFields.map { it.assigner }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun IrBuilderWithScope.getter(original: IrValueSymbol): IrExpression? =
|
fun IrBuilderWithScope.getter(original: IrValueSymbol): IrExpression? =
|
||||||
symbol2getter[original]?.invoke(this, Unit)
|
symbol2getter[original]?.invoke(this)
|
||||||
|
|
||||||
fun setter(original: IrValueSymbol): List<ExpressionSupplier<Unit>?>? = symbol2setters[original]
|
fun setter(original: IrValueSymbol): List<ExpressionSupplier?>? = symbol2setters[original]
|
||||||
|
|
||||||
fun implementationAgnostic(expression: IrExpression): ImplementationAgnostic<Unit>? = knownExpressions[expression]
|
fun implementationAgnostic(expression: IrExpression): ImplementationAgnostic? = knownExpressions[expression]
|
||||||
|
|
||||||
fun IrBuilderWithScope.subfield(expression: IrExpression, name: Name): IrExpression? =
|
fun IrBuilderWithScope.subfield(expression: IrExpression, name: Name): IrExpression? =
|
||||||
implementationAgnostic(expression)?.get(name)?.let { (expressionGenerator, representation) ->
|
implementationAgnostic(expression)?.get(name)?.let { (expressionGenerator, representation) ->
|
||||||
val res = expressionGenerator(this, Unit)
|
val res = expressionGenerator(this)
|
||||||
representation?.let { knownExpressions[res] = it }
|
representation?.let { knownExpressions[res] = it }
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
@@ -98,7 +94,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
|
|||||||
/**
|
/**
|
||||||
* Register value declaration instead of singular expressions when possible
|
* Register value declaration instead of singular expressions when possible
|
||||||
*/
|
*/
|
||||||
fun registerExpression(getter: IrExpression, representation: ImplementationAgnostic<Unit>) {
|
fun registerExpression(getter: IrExpression, representation: ImplementationAgnostic) {
|
||||||
knownExpressions[getter] = representation
|
knownExpressions[getter] = representation
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -108,7 +104,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
|
|||||||
private val regularClassMFVCPropertyMainGetters: MutableMap<IrClass, MutableMap<Name, IrSimpleFunction>> = mutableMapOf()
|
private val regularClassMFVCPropertyMainGetters: MutableMap<IrClass, MutableMap<Name, IrSimpleFunction>> = mutableMapOf()
|
||||||
private val regularClassMFVCPropertyNextGetters: MutableMap<IrSimpleFunction, Map<Name, IrSimpleFunction>> = mutableMapOf()
|
private val regularClassMFVCPropertyNextGetters: MutableMap<IrSimpleFunction, Map<Name, IrSimpleFunction>> = mutableMapOf()
|
||||||
private val regularClassMFVCPropertyFieldsMapping: MutableMap<IrField, List<IrField>> = mutableMapOf()
|
private val regularClassMFVCPropertyFieldsMapping: MutableMap<IrField, List<IrField>> = mutableMapOf()
|
||||||
private val regularClassMFVCPropertyNodes: MutableMap<IrSimpleFunction, MultiFieldValueClassTree<Unit, Unit>> = mutableMapOf()
|
private val regularClassMFVCPropertyNodes: MutableMap<IrSimpleFunction, MultiFieldValueClassTree> = mutableMapOf()
|
||||||
private val regularClassMFVCPropertyAllPrimitiveGetters: MutableSet<IrSimpleFunction> = mutableSetOf()
|
private val regularClassMFVCPropertyAllPrimitiveGetters: MutableSet<IrSimpleFunction> = mutableSetOf()
|
||||||
|
|
||||||
override val replacements
|
override val replacements
|
||||||
@@ -148,7 +144,6 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
|
|||||||
|
|
||||||
val oldFieldToInitializers: MutableMap<IrField, IrAnonymousInitializer> = mutableMapOf()
|
val oldFieldToInitializers: MutableMap<IrField, IrAnonymousInitializer> = mutableMapOf()
|
||||||
// we need to preserve order of initializations
|
// we need to preserve order of initializations
|
||||||
// todo test it
|
|
||||||
val newFields: List<List<IrField>> = fieldsToReplace.map { oldField ->
|
val newFields: List<List<IrField>> = fieldsToReplace.map { oldField ->
|
||||||
val declarations = replacements.getDeclarations(oldField.type.erasedUpperBound)!!
|
val declarations = replacements.getDeclarations(oldField.type.erasedUpperBound)!!
|
||||||
val newFields = declarations.fields.map { sourceField ->
|
val newFields = declarations.fields.map { sourceField ->
|
||||||
@@ -163,15 +158,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
regularClassMFVCPropertyFieldsMapping[oldField] = newFields
|
regularClassMFVCPropertyFieldsMapping[oldField] = newFields
|
||||||
val virtualFields: List<VirtualProperty<IrValueDeclaration>> = newFields.map { newField ->
|
val nodes2getters = declarations.makeNodes2FieldExpressions(newFields)
|
||||||
VirtualProperty(
|
|
||||||
type = newField.type,
|
|
||||||
makeGetter = { receiver: IrValueDeclaration -> irGetField(irGet(receiver), newField) },
|
|
||||||
assigner = { receiver: IrValueDeclaration, value: IrExpression -> irSetField(irGet(receiver), newField, value) },
|
|
||||||
symbol = null,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
val implementationAgnostic = declarations.ImplementationAgnostic(virtualFields)
|
|
||||||
|
|
||||||
val property = oldField.correspondingPropertySymbol?.owner
|
val property = oldField.correspondingPropertySymbol?.owner
|
||||||
val mainGetter = property?.getter
|
val mainGetter = property?.getter
|
||||||
@@ -181,7 +168,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
|
|||||||
if (!property.isDelegated && mainGetter.isDefaultGetter(oldField)) {
|
if (!property.isDelegated && mainGetter.isDefaultGetter(oldField)) {
|
||||||
mainGetter.origin = IrDeclarationOrigin.GENERATED_MULTI_FIELD_VALUE_CLASS_MEMBER
|
mainGetter.origin = IrDeclarationOrigin.GENERATED_MULTI_FIELD_VALUE_CLASS_MEMBER
|
||||||
regularClassMFVCPropertyMainGetters.getOrPut(declaration) { mutableMapOf() }[oldField.name] = mainGetter
|
regularClassMFVCPropertyMainGetters.getOrPut(declaration) { mutableMapOf() }[oldField.name] = mainGetter
|
||||||
val nodesToGetters = implementationAgnostic.nodeToExpressionGetters.mapValues { (node, exprGen) ->
|
val nodesToGetters = nodes2getters.mapValues { (node, exprGen) ->
|
||||||
if (node == declarations.loweringRepresentation) mainGetter else {
|
if (node == declarations.loweringRepresentation) mainGetter else {
|
||||||
context.irFactory.buildProperty {
|
context.irFactory.buildProperty {
|
||||||
val nameAsString = "${oldField.name.asString()}$${declarations.nodeFullNames[node]!!.asString()}"
|
val nameAsString = "${oldField.name.asString()}$${declarations.nodeFullNames[node]!!.asString()}"
|
||||||
@@ -195,8 +182,9 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
|
|||||||
origin = IrDeclarationOrigin.GENERATED_MULTI_FIELD_VALUE_CLASS_MEMBER
|
origin = IrDeclarationOrigin.GENERATED_MULTI_FIELD_VALUE_CLASS_MEMBER
|
||||||
}.apply {
|
}.apply {
|
||||||
createDispatchReceiverParameter()
|
createDispatchReceiverParameter()
|
||||||
|
val function = this
|
||||||
body = with(context.createIrBuilder(this.symbol)) {
|
body = with(context.createIrBuilder(this.symbol)) {
|
||||||
irExprBody(exprGen(this, dispatchReceiverParameter!!))
|
irExprBody(exprGen(this, function))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.getter!!.also {
|
}.getter!!.also {
|
||||||
@@ -206,7 +194,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
|
|||||||
}
|
}
|
||||||
regularClassMFVCPropertyNodes.putAll(nodesToGetters.map { (node, getter) -> getter to node })
|
regularClassMFVCPropertyNodes.putAll(nodesToGetters.map { (node, getter) -> getter to node })
|
||||||
for ((node, getter) in nodesToGetters) {
|
for ((node, getter) in nodesToGetters) {
|
||||||
if (node is InternalNode<Unit, Unit>) {
|
if (node is InternalNode) {
|
||||||
regularClassMFVCPropertyNextGetters[getter] = node.fields.associate { it.name to nodesToGetters[it.node]!! }
|
regularClassMFVCPropertyNextGetters[getter] = node.fields.associate { it.name to nodesToGetters[it.node]!! }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -225,9 +213,9 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
|
|||||||
val representation = newFields.zip(gettersAndSetters) { newField, (getter, setter) ->
|
val representation = newFields.zip(gettersAndSetters) { newField, (getter, setter) ->
|
||||||
VirtualProperty(newField.type, getter, setter, null)
|
VirtualProperty(newField.type, getter, setter, null)
|
||||||
}
|
}
|
||||||
val fieldRepresentation = declarations.ImplementationAgnostic(representation)
|
val fieldRepresentation = declarations.ImplementationAgnostic(oldField.type as IrSimpleType, representation)
|
||||||
val boxed = fieldRepresentation.boxedExpression(
|
val boxed = fieldRepresentation.boxedExpression(
|
||||||
context.createIrBuilder((currentScope!!.irElement as IrSymbolOwner).symbol), Unit
|
context.createIrBuilder((currentScope!!.irElement as IrSymbolOwner).symbol)
|
||||||
)
|
)
|
||||||
valueDeclarationsRemapper.registerExpression(boxed, fieldRepresentation)
|
valueDeclarationsRemapper.registerExpression(boxed, fieldRepresentation)
|
||||||
return boxed
|
return boxed
|
||||||
@@ -330,18 +318,35 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
|
|||||||
name = mangledName
|
name = mangledName
|
||||||
returnType = source.returnType
|
returnType = source.returnType
|
||||||
}.apply {
|
}.apply {
|
||||||
val overriddenReplaced = replacement.overriddenSymbols.firstOrNull {
|
val anyOverriddenReplaced = replacement.overriddenSymbols.any {
|
||||||
replacements.bindingNewFunctionToParameterTemplateStructure[it.owner] != null
|
it.owner in replacements.bindingNewFunctionToParameterTemplateStructure
|
||||||
}?.owner
|
}
|
||||||
if (source.parentAsClass.isMultiFieldValueClass && overriddenReplaced != null) {
|
if (source.parentAsClass.isMultiFieldValueClass && anyOverriddenReplaced) {
|
||||||
copyParameterDeclarationsFrom(overriddenReplaced)
|
copyTypeParametersFrom(source) // without static type parameters
|
||||||
dispatchReceiverParameter = source.dispatchReceiverParameter!!.copyTo(this)
|
val substitutionMap = makeTypeParameterSubstitutionMap(source, this)
|
||||||
val replacementStructure = replacement.overriddenSymbols.firstNotNullOf {
|
dispatchReceiverParameter = source.dispatchReceiverParameter!!.let { // source!!!
|
||||||
replacements.bindingNewFunctionToParameterTemplateStructure[it.owner]
|
it.copyTo(this, type = it.type.substitute(substitutionMap))
|
||||||
}.toMutableList().apply {
|
}
|
||||||
|
require(replacement.dispatchReceiverParameter == null) {
|
||||||
|
"""
|
||||||
|
Ambiguous receivers:
|
||||||
|
${source.dispatchReceiverParameter!!.render()}
|
||||||
|
${replacement.dispatchReceiverParameter!!.render()}
|
||||||
|
""".trimIndent()
|
||||||
|
}
|
||||||
|
require(replacement.extensionReceiverParameter == null) {
|
||||||
|
"Static replacement must have no extension receiver but ${replacement.extensionReceiverParameter!!.render()} found"
|
||||||
|
}
|
||||||
|
val replacementStructure = replacements.bindingNewFunctionToParameterTemplateStructure[replacement]!!
|
||||||
|
val offset = replacementStructure[0].valueParameters.size
|
||||||
|
valueParameters = replacement.valueParameters.drop(offset).map {
|
||||||
|
it.copyTo(this, type = it.type.substitute(substitutionMap), index = it.index - offset)
|
||||||
|
}
|
||||||
|
val bridgeStructure =
|
||||||
|
replacementStructure.toMutableList().apply {
|
||||||
set(0, RegularMapping(ValueParameterTemplate(dispatchReceiverParameter!!, dispatchReceiverParameter!!.origin)))
|
set(0, RegularMapping(ValueParameterTemplate(dispatchReceiverParameter!!, dispatchReceiverParameter!!.origin)))
|
||||||
}
|
}
|
||||||
replacements.bindingNewFunctionToParameterTemplateStructure[this] = replacementStructure
|
replacements.bindingNewFunctionToParameterTemplateStructure[this] = bridgeStructure
|
||||||
} else {
|
} else {
|
||||||
copyParameterDeclarationsFrom(source)
|
copyParameterDeclarationsFrom(source)
|
||||||
}
|
}
|
||||||
@@ -358,9 +363,9 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
|
|||||||
allScopes.push(createScope(source))
|
allScopes.push(createScope(source))
|
||||||
source.body = context.createIrBuilder(source.symbol, source.startOffset, source.endOffset).run {
|
source.body = context.createIrBuilder(source.symbol, source.startOffset, source.endOffset).run {
|
||||||
val sourceExplicitParameters = source.explicitParameters
|
val sourceExplicitParameters = source.explicitParameters
|
||||||
irExprBody(irCall(target).apply {
|
|
||||||
passTypeArgumentsFrom(source)
|
|
||||||
val targetExplicitParameters = target.explicitParameters
|
val targetExplicitParameters = target.explicitParameters
|
||||||
|
irExprBody(irCall(target).apply {
|
||||||
|
passTypeArgumentsWithOffsets(target, source) { source.typeParameters[it].defaultType }
|
||||||
val sourceStructure: List<RemappedParameter>? = replacements.bindingNewFunctionToParameterTemplateStructure[source]
|
val sourceStructure: List<RemappedParameter>? = replacements.bindingNewFunctionToParameterTemplateStructure[source]
|
||||||
val targetStructure: List<RemappedParameter>? = replacements.bindingNewFunctionToParameterTemplateStructure[target]
|
val targetStructure: List<RemappedParameter>? = replacements.bindingNewFunctionToParameterTemplateStructure[target]
|
||||||
val errorMessage = {
|
val errorMessage = {
|
||||||
@@ -415,10 +420,12 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is RegularMapping, null ->
|
is RegularMapping, null -> putArgument(
|
||||||
putArgument(
|
|
||||||
targetExplicitParameters[flattenedTargetIndex++],
|
targetExplicitParameters[flattenedTargetIndex++],
|
||||||
irCall(remappedSourceParameter.declarations.boxMethod).apply {
|
irCall(remappedSourceParameter.declarations.boxMethod).apply {
|
||||||
|
remappedSourceParameter.boxedType.arguments.forEachIndexed { index, argument ->
|
||||||
|
putTypeArgument(index, argument.typeOrNull)
|
||||||
|
}
|
||||||
sourceExplicitParameters
|
sourceExplicitParameters
|
||||||
.slice(flattenedSourceIndex until flattenedSourceIndex + remappedSourceParameter.valueParameters.size)
|
.slice(flattenedSourceIndex until flattenedSourceIndex + remappedSourceParameter.valueParameters.size)
|
||||||
.forEachIndexed { index, boxParameter -> putValueArgument(index, irGet(boxParameter)) }
|
.forEachIndexed { index, boxParameter -> putValueArgument(index, irGet(boxParameter)) }
|
||||||
@@ -451,6 +458,34 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
|
|||||||
allScopes.pop()
|
allScopes.pop()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun IrFunctionAccessExpression.passTypeArgumentsWithOffsets(
|
||||||
|
target: IrFunction, source: IrFunction, forCommonTypeParameters: (targetIndex: Int) -> IrType
|
||||||
|
) {
|
||||||
|
val passedTypeParametersSize = minOf(target.typeParameters.size, source.typeParameters.size)
|
||||||
|
val targetOffset = target.typeParameters.size - passedTypeParametersSize
|
||||||
|
val sourceOffset = source.typeParameters.size - passedTypeParametersSize
|
||||||
|
if (sourceOffset > 0) {
|
||||||
|
// static fun calls method
|
||||||
|
val dispatchReceiverType = source.parentAsClass.defaultType
|
||||||
|
require(dispatchReceiverType.let {
|
||||||
|
it.isMultiFieldValueClassType() && !it.isNullable() && it.erasedUpperBound.typeParameters.size == sourceOffset
|
||||||
|
}) { "Unexpected dispatcher receiver type: ${dispatchReceiverType.render()}" }
|
||||||
|
}
|
||||||
|
if (targetOffset > 0) {
|
||||||
|
// method calls static fun
|
||||||
|
val dispatchReceiverType = source.parentAsClass.defaultType
|
||||||
|
require(dispatchReceiverType.let {
|
||||||
|
it.isMultiFieldValueClassType() && !it.isNullable() && it.erasedUpperBound.typeParameters.size == targetOffset
|
||||||
|
}) { "Unexpected dispatcher receiver type: ${dispatchReceiverType.render()}" }
|
||||||
|
dispatchReceiverType.erasedUpperBound.typeParameters.forEachIndexed { index, typeParameter ->
|
||||||
|
putTypeArgument(index, typeParameter.defaultType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (i in 0 until passedTypeParametersSize) {
|
||||||
|
putTypeArgument(i + targetOffset, forCommonTypeParameters(i + sourceOffset))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun addBindingsFor(original: IrFunction, replacement: IrFunction) {
|
override fun addBindingsFor(original: IrFunction, replacement: IrFunction) {
|
||||||
val parametersStructure = replacements.bindingOldFunctionToParameterTemplateStructure[original]!!
|
val parametersStructure = replacements.bindingOldFunctionToParameterTemplateStructure[original]!!
|
||||||
require(parametersStructure.size == original.explicitParameters.size) {
|
require(parametersStructure.size == original.explicitParameters.size) {
|
||||||
@@ -495,7 +530,6 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
|
|||||||
fun MultiFieldValueClassSpecificDeclarations.buildBoxFunction() {
|
fun MultiFieldValueClassSpecificDeclarations.buildBoxFunction() {
|
||||||
boxMethod.body = with(context.createIrBuilder(boxMethod.symbol)) {
|
boxMethod.body = with(context.createIrBuilder(boxMethod.symbol)) {
|
||||||
irExprBody(irCall(primaryConstructor.symbol).apply {
|
irExprBody(irCall(primaryConstructor.symbol).apply {
|
||||||
passTypeArgumentsFrom(boxMethod)
|
|
||||||
for (i in leaves.indices) {
|
for (i in leaves.indices) {
|
||||||
putValueArgument(i, irGet(boxMethod.valueParameters[i]))
|
putValueArgument(i, irGet(boxMethod.valueParameters[i]))
|
||||||
}
|
}
|
||||||
@@ -568,6 +602,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
|
|||||||
if (newReceiver is IrCall) {
|
if (newReceiver is IrCall) {
|
||||||
val nextFunction = regularClassMFVCPropertyNextGetters[newReceiver.symbol.owner]?.get(name)
|
val nextFunction = regularClassMFVCPropertyNextGetters[newReceiver.symbol.owner]?.get(name)
|
||||||
if (nextFunction != null) {
|
if (nextFunction != null) {
|
||||||
|
require(nextFunction.typeParameters.isEmpty()) { "Subgetter with type parameters: ${nextFunction.render()}" }
|
||||||
return irCall(nextFunction).apply {
|
return irCall(nextFunction).apply {
|
||||||
this.dispatchReceiver = newReceiver.dispatchReceiver
|
this.dispatchReceiver = newReceiver.dispatchReceiver
|
||||||
}
|
}
|
||||||
@@ -596,8 +631,11 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
|
|||||||
require(leftClass == rightClass) { "Equals for different classes: $leftClass and $rightClass called" }
|
require(leftClass == rightClass) { "Equals for different classes: $leftClass and $rightClass called" }
|
||||||
return context.createIrBuilder(expression.symbol).run {
|
return context.createIrBuilder(expression.symbol).run {
|
||||||
irCall(leftImplementation.regularDeclarations.specializedEqualsMethod).apply {
|
irCall(leftImplementation.regularDeclarations.specializedEqualsMethod).apply {
|
||||||
|
(leftImplementation.type.arguments + rightImplementation.type.arguments).forEachIndexed { index, argument ->
|
||||||
|
putTypeArgument(index, argument.typeOrNull)
|
||||||
|
}
|
||||||
val arguments =
|
val arguments =
|
||||||
(leftImplementation.virtualFields + rightImplementation.virtualFields).map { it.makeGetter(this@run, Unit) }
|
(leftImplementation.virtualFields + rightImplementation.virtualFields).map { it.makeGetter(this@run) }
|
||||||
arguments.forEachIndexed { index, argument -> putValueArgument(index, argument) }
|
arguments.forEachIndexed { index, argument -> putValueArgument(index, argument) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -625,6 +663,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
|
|||||||
val nonNullLeftArgumentVariable =
|
val nonNullLeftArgumentVariable =
|
||||||
irTemporary(irImplicitCast(irGet(leftValue), leftArgument.type.makeNotNull()))
|
irTemporary(irImplicitCast(irGet(leftValue), leftArgument.type.makeNotNull()))
|
||||||
+irCall(context.irBuiltIns.eqeqSymbol).apply {
|
+irCall(context.irBuiltIns.eqeqSymbol).apply {
|
||||||
|
copyTypeArgumentsFrom(expression)
|
||||||
putValueArgument(0, irGet(nonNullLeftArgumentVariable))
|
putValueArgument(0, irGet(nonNullLeftArgumentVariable))
|
||||||
putValueArgument(1, rightArgument)
|
putValueArgument(1, rightArgument)
|
||||||
}
|
}
|
||||||
@@ -639,7 +678,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
|
|||||||
private fun makeLeavesGetters(currentGetter: IrSimpleFunction): List<IrSimpleFunction>? =
|
private fun makeLeavesGetters(currentGetter: IrSimpleFunction): List<IrSimpleFunction>? =
|
||||||
when (val node = regularClassMFVCPropertyNodes[currentGetter]) {
|
when (val node = regularClassMFVCPropertyNodes[currentGetter]) {
|
||||||
null -> null
|
null -> null
|
||||||
is MultiFieldValueClassTree.Leaf<Unit> -> listOf(currentGetter)
|
is Leaf -> listOf(currentGetter)
|
||||||
is InternalNode -> node.fields.flatMap { makeLeavesGetters(regularClassMFVCPropertyNextGetters[currentGetter]!![it.name]!!)!! }
|
is InternalNode -> node.fields.flatMap { makeLeavesGetters(regularClassMFVCPropertyNextGetters[currentGetter]!![it.name]!!)!! }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -655,7 +694,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
|
|||||||
val newArguments: List<IrExpression?> =
|
val newArguments: List<IrExpression?> =
|
||||||
makeNewArguments(parameter2expression.map { (_, argument) -> argument }, structure.map { it.valueParameters })
|
makeNewArguments(parameter2expression.map { (_, argument) -> argument }, structure.map { it.valueParameters })
|
||||||
+irCall(replacement.symbol).apply {
|
+irCall(replacement.symbol).apply {
|
||||||
copyTypeArgumentsFrom(original)
|
passTypeArgumentsWithOffsets(replacement, originalFunction) { original.getTypeArgument(it)!! }
|
||||||
for ((parameter, argument) in replacement.explicitParameters zip newArguments) {
|
for ((parameter, argument) in replacement.explicitParameters zip newArguments) {
|
||||||
if (argument == null) continue
|
if (argument == null) continue
|
||||||
putArgument(replacement, parameter, argument.transform(this@JvmMultiFieldValueClassLowering, null))
|
putArgument(replacement, parameter, argument.transform(this@JvmMultiFieldValueClassLowering, null))
|
||||||
@@ -671,6 +710,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
|
|||||||
val toString = argument.type.erasedUpperBound.functions.single {
|
val toString = argument.type.erasedUpperBound.functions.single {
|
||||||
it.name.asString() == "toString" && it.valueParameters.isEmpty()
|
it.name.asString() == "toString" && it.valueParameters.isEmpty()
|
||||||
}
|
}
|
||||||
|
require(toString.typeParameters.isEmpty()) { "Bad toString: ${toString.render()}" }
|
||||||
irCall(toString).apply {
|
irCall(toString).apply {
|
||||||
dispatchReceiver = argument
|
dispatchReceiver = argument
|
||||||
}
|
}
|
||||||
@@ -760,6 +800,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
|
|||||||
?: return super.visitGetField(expression)
|
?: return super.visitGetField(expression)
|
||||||
with(context.createIrBuilder(expression.symbol)) {
|
with(context.createIrBuilder(expression.symbol)) {
|
||||||
irCall(getter).apply {
|
irCall(getter).apply {
|
||||||
|
require(getter.typeParameters.isEmpty()) { "Getter with type parameters: ${getter.render()}" }
|
||||||
dispatchReceiver = expression.receiver!!.transform(this@JvmMultiFieldValueClassLowering, null)
|
dispatchReceiver = expression.receiver!!.transform(this@JvmMultiFieldValueClassLowering, null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -807,7 +848,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
for ((setter, subValue) in setters zip subValues) {
|
for ((setter, subValue) in setters zip subValues) {
|
||||||
setter?.invoke(this, Unit, subValue)?.let { +it }
|
setter?.invoke(this, subValue)?.let { +it }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -835,14 +876,14 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun List<IrVariable>.toGettersAndSetters() = map { variable ->
|
private fun List<IrVariable>.toGettersAndSetters() = map { variable ->
|
||||||
Pair<ExpressionGenerator<Unit>, ExpressionSupplier<Unit>>(
|
Pair<ExpressionGenerator, ExpressionSupplier>(
|
||||||
{ irGet(variable) },
|
{ irGet(variable) },
|
||||||
{ _, value: IrExpression -> irSet(variable, value) }
|
{ value: IrExpression -> irSet(variable, value) }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun List<IrField>.toGettersAndSetters(receiver: IrValueParameter, transformReceiver: Boolean = false) = map { field ->
|
private fun List<IrField>.toGettersAndSetters(receiver: IrValueParameter, transformReceiver: Boolean = false) = map { field ->
|
||||||
Pair<ExpressionGenerator<Unit>, ExpressionSupplier<Unit>>(
|
Pair<ExpressionGenerator, ExpressionSupplier>(
|
||||||
{
|
{
|
||||||
val initialGetReceiver = irGet(receiver)
|
val initialGetReceiver = irGet(receiver)
|
||||||
val resultReceiver =
|
val resultReceiver =
|
||||||
@@ -850,7 +891,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
|
|||||||
else initialGetReceiver
|
else initialGetReceiver
|
||||||
irGetField(resultReceiver, field)
|
irGetField(resultReceiver, field)
|
||||||
},
|
},
|
||||||
{ _, value: IrExpression ->
|
{ value: IrExpression ->
|
||||||
val initialGetReceiver = irGet(receiver)
|
val initialGetReceiver = irGet(receiver)
|
||||||
val resultReceiver =
|
val resultReceiver =
|
||||||
if (transformReceiver) initialGetReceiver.transform(this@JvmMultiFieldValueClassLowering, null)
|
if (transformReceiver) initialGetReceiver.transform(this@JvmMultiFieldValueClassLowering, null)
|
||||||
@@ -882,7 +923,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun IrBlockBuilder.flattenExpressionTo(
|
fun IrBlockBuilder.flattenExpressionTo(
|
||||||
expression: IrExpression, variables: List<Pair<ExpressionGenerator<Unit>, ExpressionSupplier<Unit>>>
|
expression: IrExpression, variables: List<Pair<ExpressionGenerator, ExpressionSupplier>>
|
||||||
) {
|
) {
|
||||||
val declarations = replacements.getDeclarations(expression.type.erasedUpperBound) ?: run {
|
val declarations = replacements.getDeclarations(expression.type.erasedUpperBound) ?: run {
|
||||||
val constructor = (expression as? IrConstructorCall)?.symbol?.owner ?: return@run null
|
val constructor = (expression as? IrConstructorCall)?.symbol?.owner ?: return@run null
|
||||||
@@ -891,7 +932,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
|
|||||||
|
|
||||||
if (expression.type.isNullable() || declarations == null) {
|
if (expression.type.isNullable() || declarations == null) {
|
||||||
require(variables.size == 1)
|
require(variables.size == 1)
|
||||||
+variables.single().second(this, Unit, expression.transform(this@JvmMultiFieldValueClassLowering, null))
|
+variables.single().second(this, expression.transform(this@JvmMultiFieldValueClassLowering, null))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
require(variables.size == declarations.leaves.size)
|
require(variables.size == declarations.leaves.size)
|
||||||
@@ -907,22 +948,23 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
|
|||||||
for ((treeField, argument) in root.fields zip oldArguments) {
|
for ((treeField, argument) in root.fields zip oldArguments) {
|
||||||
val size = when (treeField.node) {
|
val size = when (treeField.node) {
|
||||||
is InternalNode -> replacements.getDeclarations(treeField.node.irClass)!!.leaves.size
|
is InternalNode -> replacements.getDeclarations(treeField.node.irClass)!!.leaves.size
|
||||||
is MultiFieldValueClassTree.Leaf -> 1
|
is Leaf -> 1
|
||||||
}
|
}
|
||||||
val subVariables = variables.slice(curOffset until (curOffset + size)).also { curOffset += size }
|
val subVariables = variables.slice(curOffset until (curOffset + size)).also { curOffset += size }
|
||||||
argument?.let { flattenExpressionTo(it, subVariables) }
|
argument?.let { flattenExpressionTo(it, subVariables) }
|
||||||
}
|
}
|
||||||
+irCall(declarations.primaryConstructorImpl).apply {
|
+irCall(declarations.primaryConstructorImpl).apply {
|
||||||
variables.forEachIndexed { index, variable -> putValueArgument(index, variable.first(this@flattenExpressionTo, Unit)) }
|
copyTypeArgumentsFrom(expression)
|
||||||
|
variables.forEachIndexed { index, variable -> putValueArgument(index, variable.first(this@flattenExpressionTo)) }
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val transformedExpression = expression.transform(this@JvmMultiFieldValueClassLowering, null)
|
val transformedExpression = expression.transform(this@JvmMultiFieldValueClassLowering, null)
|
||||||
valueDeclarationsRemapper.implementationAgnostic(transformedExpression)?.virtualFields?.map { it.makeGetter(this, Unit) }?.let {
|
valueDeclarationsRemapper.implementationAgnostic(transformedExpression)?.virtualFields?.map { it.makeGetter(this) }?.let {
|
||||||
require(variables.size == it.size)
|
require(variables.size == it.size)
|
||||||
for ((variable, subExpression) in variables zip it) {
|
for ((variable, subExpression) in variables zip it) {
|
||||||
+variable.second(this, Unit, subExpression)
|
+variable.second(this, subExpression)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -936,7 +978,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
|
|||||||
transformedExpression.getValueArgument(it)
|
transformedExpression.getValueArgument(it)
|
||||||
}) {
|
}) {
|
||||||
if (argument != null) {
|
if (argument != null) {
|
||||||
+variable.second(this, Unit, argument)
|
+variable.second(this, argument)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
@@ -946,7 +988,8 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
|
|||||||
val receiver = irTemporary(transformedExpression.dispatchReceiver)
|
val receiver = irTemporary(transformedExpression.dispatchReceiver)
|
||||||
require(getters.size == variables.size) { "Number of getters must be equal to number of variables" }
|
require(getters.size == variables.size) { "Number of getters must be equal to number of variables" }
|
||||||
for ((variable, getter) in variables zip getters) {
|
for ((variable, getter) in variables zip getters) {
|
||||||
+variable.second(this, Unit, irCall(getter).apply { dispatchReceiver = irGet(receiver) })
|
require(getter.typeParameters.isEmpty()) { "Getter with type parameters: ${getter.render()}" }
|
||||||
|
+variable.second(this, irCall(getter).apply { dispatchReceiver = irGet(receiver) })
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -960,7 +1003,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
|
|||||||
}
|
}
|
||||||
val boxed = irTemporary(transformedExpression)
|
val boxed = irTemporary(transformedExpression)
|
||||||
for ((variable, unboxMethod) in variables zip declarations.unboxMethods) {
|
for ((variable, unboxMethod) in variables zip declarations.unboxMethods) {
|
||||||
+variable.second(this, Unit, irCall(unboxMethod).apply { dispatchReceiver = irGet(boxed) })
|
+variable.second(this, irCall(unboxMethod).apply { dispatchReceiver = irGet(boxed) })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+34
-18
@@ -7,15 +7,15 @@ package org.jetbrains.kotlin.backend.jvm
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.backend.common.ir.copyTo
|
import org.jetbrains.kotlin.backend.common.ir.copyTo
|
||||||
import org.jetbrains.kotlin.backend.common.ir.copyTypeParametersFrom
|
import org.jetbrains.kotlin.backend.common.ir.copyTypeParametersFrom
|
||||||
|
import org.jetbrains.kotlin.backend.jvm.MemoizedMultiFieldValueClassReplacements.RemappedParameter.MultiFieldValueClassMapping
|
||||||
import org.jetbrains.kotlin.backend.jvm.ir.*
|
import org.jetbrains.kotlin.backend.jvm.ir.*
|
||||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||||
import org.jetbrains.kotlin.ir.builders.declarations.buildConstructor
|
import org.jetbrains.kotlin.ir.builders.declarations.buildConstructor
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrExpressionBody
|
import org.jetbrains.kotlin.ir.expressions.IrExpressionBody
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||||
import org.jetbrains.kotlin.ir.types.IrType
|
import org.jetbrains.kotlin.ir.types.*
|
||||||
import org.jetbrains.kotlin.ir.types.IrTypeSystemContext
|
|
||||||
import org.jetbrains.kotlin.ir.types.isNullable
|
|
||||||
import org.jetbrains.kotlin.ir.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.storage.LockBasedStorageManager
|
import org.jetbrains.kotlin.storage.LockBasedStorageManager
|
||||||
@@ -89,15 +89,18 @@ class MemoizedMultiFieldValueClassReplacements(
|
|||||||
.flatMap { it.valueParameters }.mapIndexed { index: Int, template -> template.toParameter(this, index) }
|
.flatMap { it.valueParameters }.mapIndexed { index: Int, template -> template.toParameter(this, index) }
|
||||||
|
|
||||||
private fun List<ValueParameterTemplate>.grouped(
|
private fun List<ValueParameterTemplate>.grouped(
|
||||||
|
substitutionMap: Map<IrTypeParameterSymbol, IrType>,
|
||||||
originWhenFlattenedAndNotSpecified: IrDeclarationOrigin? = IrDeclarationOrigin.GENERATED_MULTI_FIELD_VALUE_CLASS_PARAMETER
|
originWhenFlattenedAndNotSpecified: IrDeclarationOrigin? = IrDeclarationOrigin.GENERATED_MULTI_FIELD_VALUE_CLASS_PARAMETER
|
||||||
): List<RemappedParameter> = map { parameter ->
|
): List<RemappedParameter> = map { parameter ->
|
||||||
val declarations = parameter.type.takeIf { !it.isNullable() }?.erasedUpperBound?.let { getDeclarations(it) }
|
val declarations = parameter.type.takeIf { !it.isNullable() }?.erasedUpperBound?.let { getDeclarations(it) }
|
||||||
?: return@map RemappedParameter.RegularMapping(parameter)
|
?: return@map RemappedParameter.RegularMapping(parameter)
|
||||||
require(!parameter.original.hasDefaultValue()) { "Default parameters values are not supported for multi-field value classes" }
|
require(!parameter.original.hasDefaultValue()) { "Default parameters values are not supported for multi-field value classes" }
|
||||||
RemappedParameter.MultiFieldValueClassMapping(declarations, declarations.leaves.map { leaf ->
|
val localSubstitutionMap = declarations.valueClass.typeParameters.zip((parameter.type as IrSimpleType).arguments)
|
||||||
|
.mapNotNull { (parameter, argument) -> if (argument is IrSimpleType) parameter.symbol to argument.type else null}.toMap()
|
||||||
|
MultiFieldValueClassMapping(declarations, parameter.type.substitute(substitutionMap) as IrSimpleType, declarations.leaves.map { leaf ->
|
||||||
ValueParameterTemplate(
|
ValueParameterTemplate(
|
||||||
name = "${parameter.name}$${declarations.nodeFullNames[leaf]!!}",
|
name = "${parameter.name}$${declarations.nodeFullNames[leaf]!!}",
|
||||||
type = leaf.type,
|
type = leaf.type.substitute(localSubstitutionMap),
|
||||||
origin = parameter.origin ?: originWhenFlattenedAndNotSpecified,
|
origin = parameter.origin ?: originWhenFlattenedAndNotSpecified,
|
||||||
defaultValue = null,
|
defaultValue = null,
|
||||||
original = parameter.original,
|
original = parameter.original,
|
||||||
@@ -122,7 +125,7 @@ class MemoizedMultiFieldValueClassReplacements(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun makeGroupedValueParametersFrom(
|
private fun makeGroupedValueParametersFrom(
|
||||||
function: IrFunction, includeDispatcherReceiver: Boolean
|
function: IrFunction, includeDispatcherReceiver: Boolean, substitutionMap: Map<IrTypeParameterSymbol, IrType>
|
||||||
): List<RemappedParameter> {
|
): List<RemappedParameter> {
|
||||||
val newFlattenedParameters = mutableListOf<RemappedParameter>()
|
val newFlattenedParameters = mutableListOf<RemappedParameter>()
|
||||||
if (function.dispatchReceiverParameter != null && includeDispatcherReceiver) {
|
if (function.dispatchReceiverParameter != null && includeDispatcherReceiver) {
|
||||||
@@ -133,7 +136,7 @@ class MemoizedMultiFieldValueClassReplacements(
|
|||||||
defaultValue = null,
|
defaultValue = null,
|
||||||
original = function.parentAsClass.thisReceiver!!,
|
original = function.parentAsClass.thisReceiver!!,
|
||||||
)
|
)
|
||||||
newFlattenedParameters.addAll(listOf(template).grouped())
|
newFlattenedParameters.addAll(listOf(template).grouped(substitutionMap))
|
||||||
}
|
}
|
||||||
val contextReceivers = function.valueParameters.take(function.contextReceiverParametersCount)
|
val contextReceivers = function.valueParameters.take(function.contextReceiverParametersCount)
|
||||||
.mapIndexed { index: Int, valueParameter: IrValueParameter ->
|
.mapIndexed { index: Int, valueParameter: IrValueParameter ->
|
||||||
@@ -145,7 +148,7 @@ class MemoizedMultiFieldValueClassReplacements(
|
|||||||
original = valueParameter,
|
original = valueParameter,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
.grouped()
|
.grouped(substitutionMap)
|
||||||
newFlattenedParameters.addAll(contextReceivers)
|
newFlattenedParameters.addAll(contextReceivers)
|
||||||
function.extensionReceiverParameter?.let {
|
function.extensionReceiverParameter?.let {
|
||||||
val template = ValueParameterTemplate(
|
val template = ValueParameterTemplate(
|
||||||
@@ -155,11 +158,11 @@ class MemoizedMultiFieldValueClassReplacements(
|
|||||||
defaultValue = it.defaultValue,
|
defaultValue = it.defaultValue,
|
||||||
original = it,
|
original = it,
|
||||||
)
|
)
|
||||||
newFlattenedParameters.addAll(listOf(template).grouped())
|
newFlattenedParameters.addAll(listOf(template).grouped(substitutionMap))
|
||||||
}
|
}
|
||||||
newFlattenedParameters += function.valueParameters.drop(function.contextReceiverParametersCount).map {
|
newFlattenedParameters += function.valueParameters.drop(function.contextReceiverParametersCount).map {
|
||||||
ValueParameterTemplate(it, origin = null)
|
ValueParameterTemplate(it, origin = null)
|
||||||
}.grouped()
|
}.grouped(substitutionMap)
|
||||||
return newFlattenedParameters
|
return newFlattenedParameters
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,6 +173,7 @@ class MemoizedMultiFieldValueClassReplacements(
|
|||||||
|
|
||||||
data class MultiFieldValueClassMapping(
|
data class MultiFieldValueClassMapping(
|
||||||
val declarations: MultiFieldValueClassSpecificDeclarations,
|
val declarations: MultiFieldValueClassSpecificDeclarations,
|
||||||
|
val boxedType: IrSimpleType,
|
||||||
override val valueParameters: List<ValueParameterTemplate>,
|
override val valueParameters: List<ValueParameterTemplate>,
|
||||||
) : RemappedParameter() {
|
) : RemappedParameter() {
|
||||||
init {
|
init {
|
||||||
@@ -181,41 +185,53 @@ class MemoizedMultiFieldValueClassReplacements(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val bindingOldFunctionToParameterTemplateStructure: MutableMap<IrFunction, List<RemappedParameter>> = ConcurrentHashMap()
|
val bindingOldFunctionToParameterTemplateStructure: MutableMap<IrFunction, List<RemappedParameter>> = ConcurrentHashMap()
|
||||||
val bindingNewFunctionToParameterTemplateStructure: MutableMap<IrFunction, List<RemappedParameter>> = ConcurrentHashMap()
|
val bindingNewFunctionToParameterTemplateStructure: MutableMap<IrFunction, List<RemappedParameter>> =
|
||||||
|
object : ConcurrentHashMap<IrFunction, List<RemappedParameter>>() {
|
||||||
|
override fun put(key: IrFunction, value: List<RemappedParameter>): List<RemappedParameter>? {
|
||||||
|
require(key.explicitParametersCount == value.sumOf { it.valueParameters.size }) {
|
||||||
|
"Illegal structure $value for function ${key.dump()}"
|
||||||
|
}
|
||||||
|
return super.put(key, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// todo inline classes pass type arguments correctly
|
||||||
override fun createStaticReplacement(function: IrFunction): IrSimpleFunction =
|
override fun createStaticReplacement(function: IrFunction): IrSimpleFunction =
|
||||||
buildReplacement(function, JvmLoweredDeclarationOrigin.STATIC_MULTI_FIELD_VALUE_CLASS_REPLACEMENT, noFakeOverride = true) {
|
buildReplacement(function, JvmLoweredDeclarationOrigin.STATIC_MULTI_FIELD_VALUE_CLASS_REPLACEMENT, noFakeOverride = true) {
|
||||||
originalFunctionForStaticReplacement[this] = function
|
originalFunctionForStaticReplacement[this] = function
|
||||||
val newFlattenedParameters = makeGroupedValueParametersFrom(function, includeDispatcherReceiver = true)
|
typeParameters = listOf()
|
||||||
|
copyTypeParametersFrom(function.parentAsClass)
|
||||||
|
val substitutionMap = function.parentAsClass.typeParameters.map { it.symbol }.zip(typeParameters.map { it.defaultType }).toMap()
|
||||||
|
copyTypeParametersFrom(function, parameterMap = (function.parentAsClass.typeParameters zip typeParameters).toMap())
|
||||||
|
val newFlattenedParameters = makeGroupedValueParametersFrom(function, includeDispatcherReceiver = true, substitutionMap)
|
||||||
|
valueParameters = makeValueParametersFromTemplate(newFlattenedParameters)
|
||||||
bindingOldFunctionToParameterTemplateStructure[function] = newFlattenedParameters
|
bindingOldFunctionToParameterTemplateStructure[function] = newFlattenedParameters
|
||||||
bindingNewFunctionToParameterTemplateStructure[this] = newFlattenedParameters
|
bindingNewFunctionToParameterTemplateStructure[this] = newFlattenedParameters
|
||||||
valueParameters = makeValueParametersFromTemplate(newFlattenedParameters)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun createMethodReplacement(function: IrFunction): IrSimpleFunction = buildReplacement(function, function.origin) {
|
override fun createMethodReplacement(function: IrFunction): IrSimpleFunction = buildReplacement(function, function.origin) {
|
||||||
originalFunctionForMethodReplacement[this] = function
|
originalFunctionForMethodReplacement[this] = function
|
||||||
dispatchReceiverParameter = function.dispatchReceiverParameter?.copyTo(this, index = -1)
|
dispatchReceiverParameter = function.dispatchReceiverParameter?.copyTo(this, index = -1)
|
||||||
val newFlattenedParameters = makeGroupedValueParametersFrom(function, includeDispatcherReceiver = false)
|
val newFlattenedParameters = makeGroupedValueParametersFrom(function, includeDispatcherReceiver = false, mapOf())
|
||||||
val receiver = dispatchReceiverParameter
|
val receiver = dispatchReceiverParameter
|
||||||
val receiverTemplate = if (receiver != null) ValueParameterTemplate(receiver, origin = receiver.origin) else null
|
val receiverTemplate = if (receiver != null) ValueParameterTemplate(receiver, origin = receiver.origin) else null
|
||||||
val remappedParameters =
|
val remappedParameters =
|
||||||
if (receiverTemplate != null) listOf(RemappedParameter.RegularMapping(receiverTemplate)) + newFlattenedParameters else newFlattenedParameters
|
if (receiverTemplate != null) listOf(RemappedParameter.RegularMapping(receiverTemplate)) + newFlattenedParameters else newFlattenedParameters
|
||||||
|
valueParameters = makeValueParametersFromTemplate(newFlattenedParameters)
|
||||||
bindingOldFunctionToParameterTemplateStructure[function] = remappedParameters
|
bindingOldFunctionToParameterTemplateStructure[function] = remappedParameters
|
||||||
bindingNewFunctionToParameterTemplateStructure[this] = remappedParameters
|
bindingNewFunctionToParameterTemplateStructure[this] = remappedParameters
|
||||||
valueParameters = makeValueParametersFromTemplate(newFlattenedParameters)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createConstructorReplacement(@Suppress("UNUSED_PARAMETER") constructor: IrConstructor): IrConstructor {
|
private fun createConstructorReplacement(@Suppress("UNUSED_PARAMETER") constructor: IrConstructor): IrConstructor {
|
||||||
val newFlattenedParameters = makeGroupedValueParametersFrom(constructor, includeDispatcherReceiver = false)
|
val newFlattenedParameters = makeGroupedValueParametersFrom(constructor, includeDispatcherReceiver = false, mapOf())
|
||||||
bindingOldFunctionToParameterTemplateStructure[constructor] = newFlattenedParameters
|
bindingOldFunctionToParameterTemplateStructure[constructor] = newFlattenedParameters
|
||||||
val newConstructor = irFactory.buildConstructor {
|
val newConstructor = irFactory.buildConstructor {
|
||||||
updateFrom(constructor)
|
updateFrom(constructor)
|
||||||
returnType = constructor.returnType
|
returnType = constructor.returnType
|
||||||
}.apply {
|
}.apply {
|
||||||
|
parent = constructor.parent
|
||||||
copyTypeParametersFrom(constructor)
|
copyTypeParametersFrom(constructor)
|
||||||
valueParameters = makeValueParametersFromTemplate(newFlattenedParameters)
|
valueParameters = makeValueParametersFromTemplate(newFlattenedParameters)
|
||||||
annotations = constructor.annotations
|
annotations = constructor.annotations
|
||||||
parent = constructor.parent
|
|
||||||
originalConstructorForConstructorReplacement[this] = constructor
|
originalConstructorForConstructorReplacement[this] = constructor
|
||||||
}
|
}
|
||||||
bindingNewFunctionToParameterTemplateStructure[newConstructor] = newFlattenedParameters
|
bindingNewFunctionToParameterTemplateStructure[newConstructor] = newFlattenedParameters
|
||||||
|
|||||||
+192
-187
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.backend.jvm.MultiFieldValueClassTree.InternalNode
|
|||||||
import org.jetbrains.kotlin.backend.jvm.MultiFieldValueClassTree.Leaf
|
import org.jetbrains.kotlin.backend.jvm.MultiFieldValueClassTree.Leaf
|
||||||
import org.jetbrains.kotlin.backend.jvm.ir.erasedUpperBound
|
import org.jetbrains.kotlin.backend.jvm.ir.erasedUpperBound
|
||||||
import org.jetbrains.kotlin.backend.jvm.ir.isMultiFieldValueClassType
|
import org.jetbrains.kotlin.backend.jvm.ir.isMultiFieldValueClassType
|
||||||
|
import org.jetbrains.kotlin.backend.jvm.ir.upperBound
|
||||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
||||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibility
|
import org.jetbrains.kotlin.descriptors.DescriptorVisibility
|
||||||
@@ -25,87 +26,75 @@ import org.jetbrains.kotlin.ir.builders.declarations.*
|
|||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
|
import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrGetField
|
import org.jetbrains.kotlin.ir.expressions.IrGetField
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
|
||||||
import org.jetbrains.kotlin.ir.types.IrType
|
import org.jetbrains.kotlin.ir.types.*
|
||||||
import org.jetbrains.kotlin.ir.types.IrTypeSystemContext
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
import org.jetbrains.kotlin.ir.types.isNullable
|
|
||||||
import org.jetbrains.kotlin.ir.types.isSubtypeOf
|
|
||||||
import org.jetbrains.kotlin.ir.util.constructedClass
|
|
||||||
import org.jetbrains.kotlin.ir.util.constructors
|
|
||||||
import org.jetbrains.kotlin.ir.util.defaultType
|
|
||||||
import org.jetbrains.kotlin.ir.util.primaryConstructor
|
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.renderer.render
|
||||||
import org.jetbrains.kotlin.resolve.InlineClassDescriptorResolver
|
import org.jetbrains.kotlin.resolve.InlineClassDescriptorResolver
|
||||||
|
|
||||||
sealed class MultiFieldValueClassTree<out TI, out TL> {
|
sealed class MultiFieldValueClassTree {
|
||||||
abstract val type: IrType
|
abstract val type: IrType
|
||||||
val irClass: IrClass
|
val irClass: IrClass
|
||||||
get() = type.erasedUpperBound
|
get() = type.erasedUpperBound
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun <TI, TL> create(
|
fun create(type: IrSimpleType, replacements: MemoizedMultiFieldValueClassReplacements) =
|
||||||
type: IrType,
|
if (!type.isNullable() && type.isMultiFieldValueClassType()) InternalNode(type, DescriptorVisibilities.PUBLIC, replacements)
|
||||||
defaultInternalNodeValue: TI,
|
else Leaf(type)
|
||||||
defaultLeafValue: TL,
|
|
||||||
replacements: MemoizedMultiFieldValueClassReplacements
|
|
||||||
) =
|
|
||||||
if (!type.isNullable() && type.isMultiFieldValueClassType())
|
|
||||||
InternalNode(type, defaultInternalNodeValue, DescriptorVisibilities.PUBLIC, defaultLeafValue, replacements)
|
|
||||||
else
|
|
||||||
Leaf(type, defaultLeafValue)
|
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
fun create(type: IrType, replacements: MemoizedMultiFieldValueClassReplacements) = create(type, Unit, Unit, replacements)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class Leaf<out TL>(override val type: IrType, val leafValue: TL) : MultiFieldValueClassTree<Nothing, TL>() {
|
class Leaf(override val type: IrType) : MultiFieldValueClassTree() {
|
||||||
init {
|
init {
|
||||||
require(type.isNullable() || !type.isMultiFieldValueClassType())
|
require(type.isNullable() || !type.isMultiFieldValueClassType())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <RL> map(transformLeaf: Leaf<TL>.(TL) -> RL) = Leaf(type, transformLeaf(leafValue))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class InternalNode<out TI, out TL> internal constructor(
|
class InternalNode internal constructor(
|
||||||
override val type: IrType, val internalNodeValue: TI, val fields: List<TreeField<TI, TL>>
|
override val type: IrSimpleType, val fields: List<TreeField>
|
||||||
) : MultiFieldValueClassTree<TI, TL>() {
|
) : MultiFieldValueClassTree() {
|
||||||
constructor(
|
constructor(
|
||||||
type: IrType, defaultInternalNodeValue: TI, visibility: DescriptorVisibility, defaultLeafValue: TL,
|
type: IrSimpleType, visibility: DescriptorVisibility,
|
||||||
replacements: MemoizedMultiFieldValueClassReplacements
|
replacements: MemoizedMultiFieldValueClassReplacements
|
||||||
) : this(type, defaultInternalNodeValue, 0.let {
|
) : this(type, 0.let {
|
||||||
val valueClassRepresentation = type.erasedUpperBound.valueClassRepresentation as MultiFieldValueClassRepresentation
|
val valueClassRepresentation = type.erasedUpperBound.valueClassRepresentation as MultiFieldValueClassRepresentation
|
||||||
val primaryConstructor = type.erasedUpperBound.primaryConstructor!!
|
val primaryConstructor = type.erasedUpperBound.primaryConstructor!!
|
||||||
val propertiesByName = replacements.getOldMFVCProperties(primaryConstructor.constructedClass).associateBy { it.name }
|
val propertiesByName = replacements.getOldMFVCProperties(primaryConstructor.constructedClass).associateBy { it.name }
|
||||||
valueClassRepresentation.underlyingPropertyNamesToTypes.map { (name, type) ->
|
val typeArguments: List<IrTypeArgument> = type.arguments
|
||||||
|
val typeParameters = type.erasedUpperBound.typeParameters
|
||||||
|
val substitutionMap = typeParameters.map { it.symbol }.zip(typeArguments)
|
||||||
|
.mapNotNull { (param, arg) -> if (arg is IrSimpleType) param to arg else null }.toMap()
|
||||||
|
valueClassRepresentation.underlyingPropertyNamesToTypes.map { (name, representationType) ->
|
||||||
val property = propertiesByName[name]!!
|
val property = propertiesByName[name]!!
|
||||||
val innerVisibility = property.visibility
|
val innerVisibility = property.visibility
|
||||||
val comparison = visibility.compareTo(innerVisibility)
|
val comparison = visibility.compareTo(innerVisibility)
|
||||||
?: error("Expected comparable visibilities but got $visibility and $innerVisibility")
|
?: error("Expected comparable visibilities but got $visibility and $innerVisibility")
|
||||||
val newVisibility = if (comparison < 0) visibility else innerVisibility
|
val newVisibility = if (comparison < 0) visibility else innerVisibility
|
||||||
TreeField(name, type, defaultInternalNodeValue, newVisibility, property.annotations, defaultLeafValue, replacements)
|
TreeField(
|
||||||
|
name,
|
||||||
|
representationType.substitute(substitutionMap) as IrSimpleType,
|
||||||
|
newVisibility,
|
||||||
|
property.annotations,
|
||||||
|
replacements
|
||||||
|
)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
class TreeField<out TI, out TL>(
|
class TreeField(
|
||||||
val name: Name, val type: IrType, val visibility: DescriptorVisibility, val annotations: List<IrConstructorCall>,
|
val name: Name, val type: IrType, val visibility: DescriptorVisibility, val annotations: List<IrConstructorCall>,
|
||||||
val node: MultiFieldValueClassTree<TI, TL>
|
val node: MultiFieldValueClassTree
|
||||||
) {
|
) {
|
||||||
constructor(
|
constructor(
|
||||||
name: Name,
|
name: Name,
|
||||||
type: IrType,
|
type: IrSimpleType,
|
||||||
internalNodeValue: TI,
|
|
||||||
visibility: DescriptorVisibility,
|
visibility: DescriptorVisibility,
|
||||||
annotations: List<IrConstructorCall>,
|
annotations: List<IrConstructorCall>,
|
||||||
defaultLeafValue: TL,
|
|
||||||
replacements: MemoizedMultiFieldValueClassReplacements
|
replacements: MemoizedMultiFieldValueClassReplacements
|
||||||
) : this(name, type, visibility, annotations, create(type, internalNodeValue, defaultLeafValue, replacements))
|
) : this(name, type, visibility, annotations, create(type, replacements))
|
||||||
|
|
||||||
fun <RI, RL> map(
|
|
||||||
transformInternalNode: InternalNode<TI, TL>.(TI) -> RI,
|
|
||||||
transformLeaf: Leaf<TL>.(TL) -> RL
|
|
||||||
): TreeField<RI, RL> = TreeField(name, type, visibility, annotations, node.map(transformInternalNode, transformLeaf))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo store real fields, cannot restore them
|
// todo store real fields, cannot restore them
|
||||||
@@ -118,35 +107,12 @@ sealed class MultiFieldValueClassTree<out TI, out TL> {
|
|||||||
private val fieldByName = fields.associateBy { it.name }
|
private val fieldByName = fields.associateBy { it.name }
|
||||||
|
|
||||||
operator fun get(name: Name) = fieldByName[name]
|
operator fun get(name: Name) = fieldByName[name]
|
||||||
|
|
||||||
override fun <RI, RL> map(
|
|
||||||
transformInternalNode: InternalNode<TI, TL>.(TI) -> RI,
|
|
||||||
transformLeaf: Leaf<TL>.(TL) -> RL
|
|
||||||
): InternalNode<RI, RL> = InternalNode(
|
|
||||||
type = type,
|
|
||||||
internalNodeValue = transformInternalNode(internalNodeValue),
|
|
||||||
fields = fields.map { it.map(transformInternalNode, transformLeaf) },
|
|
||||||
)
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
interface Visitor<out T, in TL, in TI> {
|
fun MultiFieldValueClassTree.render(): String = type.render() + when (this) {
|
||||||
fun visitLeaf(treeNode: Leaf<TL>): T
|
is InternalNode -> "\n" + fields.joinToString("\n") { "${it.name.render()}: ${it.node.render().prependIndent(" ")}" }
|
||||||
fun visitInternalNode(treeNode: InternalNode<TI, TL>): T
|
is Leaf -> ""
|
||||||
}
|
|
||||||
|
|
||||||
fun <T> visit(visitor: Visitor<T, TL, TI>) = when (this) {
|
|
||||||
is InternalNode -> visitor.visitInternalNode(this)
|
|
||||||
is Leaf -> visitor.visitLeaf(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
open fun <RI, RL> map(
|
|
||||||
transformInternalNode: InternalNode<TI, TL>.(TI) -> RI,
|
|
||||||
transformLeaf: Leaf<TL>.(TL) -> RL
|
|
||||||
): MultiFieldValueClassTree<RI, RL> = when (this) {
|
|
||||||
is InternalNode -> map(transformInternalNode, transformLeaf)
|
|
||||||
is Leaf -> map(transformLeaf)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class MultiFieldValueClassSpecificDeclarations(
|
class MultiFieldValueClassSpecificDeclarations(
|
||||||
@@ -162,39 +128,39 @@ class MultiFieldValueClassSpecificDeclarations(
|
|||||||
|
|
||||||
val loweringRepresentation = MultiFieldValueClassTree.create(valueClass.defaultType, replacements) as InternalNode
|
val loweringRepresentation = MultiFieldValueClassTree.create(valueClass.defaultType, replacements) as InternalNode
|
||||||
|
|
||||||
val leaves: List<Leaf<Unit>> = ArrayList<Leaf<Unit>>().apply {
|
val leaves: List<Leaf> = ArrayList<Leaf>().apply {
|
||||||
loweringRepresentation.visit(object : MultiFieldValueClassTree.Visitor<Unit, Unit, Unit> {
|
fun proceed(node: MultiFieldValueClassTree) {
|
||||||
override fun visitLeaf(treeNode: Leaf<Unit>) {
|
when (node) {
|
||||||
add(treeNode)
|
is InternalNode -> node.fields.forEach { proceed(it.node) }
|
||||||
|
is Leaf -> add(node)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
proceed(loweringRepresentation)
|
||||||
|
if (size <= 1) {
|
||||||
|
error("${this@MultiFieldValueClassSpecificDeclarations::class.qualifiedName} for $valueClass must have multiple leaves")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitInternalNode(treeNode: InternalNode<Unit, Unit>) {
|
val nodeFullNames: Map<MultiFieldValueClassTree, Name> =
|
||||||
treeNode.fields.forEach { it.node.visit(this) }
|
mutableMapOf<MultiFieldValueClassTree, Name>().apply {
|
||||||
}
|
|
||||||
})
|
|
||||||
}.also { if (it.size <= 1) error("${this::class.qualifiedName} for $valueClass must have multiple leaves") }
|
|
||||||
|
|
||||||
val nodeFullNames: Map<MultiFieldValueClassTree<Unit, Unit>, Name> =
|
|
||||||
mutableMapOf<MultiFieldValueClassTree<Unit, Unit>, Name>().apply {
|
|
||||||
loweringRepresentation.visit(object : MultiFieldValueClassTree.Visitor<Unit, Unit, Unit> {
|
|
||||||
val parts = mutableListOf<String>()
|
val parts = mutableListOf<String>()
|
||||||
override fun visitLeaf(treeNode: Leaf<Unit>) {
|
fun makeName() = Name.guessByFirstCharacter(parts.joinToString("$"))
|
||||||
put(treeNode, makeName())
|
fun proceed(node: MultiFieldValueClassTree) {
|
||||||
}
|
when (node) {
|
||||||
|
is InternalNode -> {
|
||||||
override fun visitInternalNode(treeNode: InternalNode<Unit, Unit>) {
|
|
||||||
if (parts.isNotEmpty()) {
|
if (parts.isNotEmpty()) {
|
||||||
put(treeNode, makeName())
|
put(node, makeName())
|
||||||
}
|
}
|
||||||
for (field in treeNode.fields) {
|
for (field in node.fields) {
|
||||||
parts.add(field.name.asString())
|
parts.add(field.name.asString())
|
||||||
field.node.visit(this)
|
proceed(field.node)
|
||||||
parts.removeLast()
|
parts.removeLast()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
is Leaf -> put(node, makeName())
|
||||||
private fun makeName() = Name.guessByFirstCharacter(parts.joinToString("$"))
|
}
|
||||||
})
|
}
|
||||||
|
proceed(loweringRepresentation)
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
@@ -202,24 +168,24 @@ class MultiFieldValueClassSpecificDeclarations(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private val indexByLeaf = leaves.withIndex().associate { it.value to it.index }
|
private val indexByLeaf = leaves.withIndex().associate { it.value to it.index }
|
||||||
private val indexesByInternalNode = mutableMapOf<InternalNode<Unit, Unit>, IntRange>().apply {
|
private val indexesByInternalNode = mutableMapOf<InternalNode, IntRange>().apply {
|
||||||
var index = 0
|
var index = 0
|
||||||
loweringRepresentation.visit(object : MultiFieldValueClassTree.Visitor<Unit, Unit, Unit> {
|
fun proceed(node: MultiFieldValueClassTree) {
|
||||||
override fun visitLeaf(treeNode: Leaf<Unit>) {
|
when (node) {
|
||||||
index++
|
is InternalNode -> {
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitInternalNode(treeNode: InternalNode<Unit, Unit>) {
|
|
||||||
val start = index
|
val start = index
|
||||||
treeNode.fields.forEach { it.node.visit(this) }
|
node.fields.forEach { proceed(it.node) }
|
||||||
val finish = index
|
val finish = index
|
||||||
val range = start until finish
|
val range = start until finish
|
||||||
if (finish - start <= 1) {
|
if (finish - start <= 1) {
|
||||||
error("Invalid multi-field value class indexes range for class $valueClass: ${range}")
|
error("Invalid multi-field value class indexes range for class $valueClass: ${range}")
|
||||||
}
|
}
|
||||||
put(treeNode, range)
|
put(node, range)
|
||||||
}
|
}
|
||||||
})
|
is Leaf -> index++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
proceed(loweringRepresentation)
|
||||||
}
|
}
|
||||||
|
|
||||||
val oldPrimaryConstructor = valueClass.primaryConstructor ?: error("Value classes have primary constructors")
|
val oldPrimaryConstructor = valueClass.primaryConstructor ?: error("Value classes have primary constructors")
|
||||||
@@ -236,61 +202,52 @@ class MultiFieldValueClassSpecificDeclarations(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val gettersVisibilities = mutableMapOf<MultiFieldValueClassTree<Unit, Unit>, DescriptorVisibility>().apply {
|
private val gettersVisibilities = mutableMapOf<MultiFieldValueClassTree, DescriptorVisibility>().apply {
|
||||||
loweringRepresentation.visit(object : MultiFieldValueClassTree.Visitor<Unit, Unit, Unit> {
|
|
||||||
val stack = mutableListOf<DescriptorVisibility>()
|
val stack = mutableListOf<DescriptorVisibility>()
|
||||||
override fun visitLeaf(treeNode: Leaf<Unit>) {
|
fun proceed(node: MultiFieldValueClassTree) {
|
||||||
put(treeNode, stack.last())
|
when (node) {
|
||||||
}
|
is InternalNode -> {
|
||||||
|
|
||||||
override fun visitInternalNode(treeNode: InternalNode<Unit, Unit>) {
|
|
||||||
if (stack.isNotEmpty()) {
|
if (stack.isNotEmpty()) {
|
||||||
put(treeNode, stack.last())
|
put(node, stack.last())
|
||||||
}
|
}
|
||||||
for (field in treeNode.fields) {
|
for (field in node.fields) {
|
||||||
stack.add(field.visibility)
|
stack.add(field.visibility)
|
||||||
field.node.visit(this)
|
proceed(field.node)
|
||||||
stack.pop()
|
stack.pop()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
is Leaf -> put(node, stack.last())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
proceed(loweringRepresentation)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val gettersAnnotations = mutableMapOf<MultiFieldValueClassTree<Unit, Unit>, List<IrConstructorCall>>().apply {
|
private val gettersAnnotations = mutableMapOf<MultiFieldValueClassTree, List<IrConstructorCall>>().apply {
|
||||||
loweringRepresentation.visit(object : MultiFieldValueClassTree.Visitor<Unit, Unit, Unit> {
|
|
||||||
val stack = mutableListOf<List<IrConstructorCall>>()
|
val stack = mutableListOf<List<IrConstructorCall>>()
|
||||||
override fun visitLeaf(treeNode: Leaf<Unit>) {
|
|
||||||
put(treeNode, stack.last())
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitInternalNode(treeNode: InternalNode<Unit, Unit>) {
|
fun proceed(node: MultiFieldValueClassTree) {
|
||||||
|
when (node) {
|
||||||
|
is InternalNode -> {
|
||||||
if (stack.isNotEmpty()) {
|
if (stack.isNotEmpty()) {
|
||||||
put(treeNode, stack.last())
|
put(node, stack.last())
|
||||||
}
|
}
|
||||||
for (field in treeNode.fields) {
|
for (field in node.fields) {
|
||||||
stack.add(field.annotations)
|
stack.add(field.annotations)
|
||||||
field.node.visit(this)
|
proceed(field.node)
|
||||||
stack.pop()
|
stack.pop()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
is Leaf -> put(node, stack.last())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
proceed(loweringRepresentation)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun IrBuilderWithScope.fieldGetter(receiver: IrValueParameter, field: IrField): IrGetField =
|
private fun IrBuilderWithScope.fieldGetter(receiver: IrValueParameter, field: IrField): IrGetField =
|
||||||
irGetField(irGet(receiver), field)
|
irGetField(irGet(receiver), field)
|
||||||
|
|
||||||
private fun IrFunction.fieldGetter(field: IrField): IrBuilderWithScope.() -> IrGetField = { fieldGetter(dispatchReceiverParameter!!, field) }
|
private fun IrFunction.fieldGetter(field: IrField): IrBuilderWithScope.() -> IrGetField =
|
||||||
|
{ fieldGetter(dispatchReceiverParameter!!, field) }
|
||||||
private val selfImplementationAgnosticDeclarations = ImplementationAgnostic(
|
|
||||||
fields.map {
|
|
||||||
VirtualProperty(
|
|
||||||
type = it.type,
|
|
||||||
makeGetter = { receiver: IrValueParameter -> irGetField(irGet(receiver), it) },
|
|
||||||
assigner = { receiver: IrValueParameter, value: IrExpression -> irSetField(irGet(receiver), it, value) },
|
|
||||||
symbol = null,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
val primaryConstructor: IrConstructor = irFactory.buildConstructor {
|
val primaryConstructor: IrConstructor = irFactory.buildConstructor {
|
||||||
updateFrom(oldPrimaryConstructor)
|
updateFrom(oldPrimaryConstructor)
|
||||||
@@ -298,8 +255,10 @@ class MultiFieldValueClassSpecificDeclarations(
|
|||||||
origin = JvmLoweredDeclarationOrigin.SYNTHETIC_MULTI_FIELD_VALUE_CLASS_MEMBER
|
origin = JvmLoweredDeclarationOrigin.SYNTHETIC_MULTI_FIELD_VALUE_CLASS_MEMBER
|
||||||
returnType = oldPrimaryConstructor.returnType
|
returnType = oldPrimaryConstructor.returnType
|
||||||
}.apply {
|
}.apply {
|
||||||
copyTypeParametersFrom(oldPrimaryConstructor)
|
require(oldPrimaryConstructor.typeParameters.isEmpty()) {
|
||||||
addFlattenedClassRepresentationToParameters()
|
"Constructors do not support type parameters yet"
|
||||||
|
}
|
||||||
|
addFlattenedClassRepresentationToParameters(mapOf())
|
||||||
val irConstructor = this@apply
|
val irConstructor = this@apply
|
||||||
parent = valueClass
|
parent = valueClass
|
||||||
body = context.createIrBuilder(irConstructor.symbol).irBlockBody(irConstructor) {
|
body = context.createIrBuilder(irConstructor.symbol).irBlockBody(irConstructor) {
|
||||||
@@ -322,11 +281,14 @@ class MultiFieldValueClassSpecificDeclarations(
|
|||||||
modality = Modality.FINAL
|
modality = Modality.FINAL
|
||||||
}.apply {
|
}.apply {
|
||||||
parent = valueClass
|
parent = valueClass
|
||||||
copyTypeParametersFrom(oldPrimaryConstructor)
|
copyTypeParametersFrom(valueClass)
|
||||||
addFlattenedClassRepresentationToParameters()
|
addFlattenedClassRepresentationToParameters(classToFunctionTypeParametersMapping())
|
||||||
// body is added in Lowering file
|
// body is added in Lowering file
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun IrSimpleFunction.classToFunctionTypeParametersMapping() =
|
||||||
|
valueClass.typeParameters.map { it.symbol }.zip(typeParameters.map { it.defaultType }).toMap()
|
||||||
|
|
||||||
val boxMethod = irFactory.buildFun {
|
val boxMethod = irFactory.buildFun {
|
||||||
name = Name.identifier(KotlinTypeMapper.BOX_JVM_METHOD_NAME)
|
name = Name.identifier(KotlinTypeMapper.BOX_JVM_METHOD_NAME)
|
||||||
origin = JvmLoweredDeclarationOrigin.SYNTHETIC_MULTI_FIELD_VALUE_CLASS_MEMBER
|
origin = JvmLoweredDeclarationOrigin.SYNTHETIC_MULTI_FIELD_VALUE_CLASS_MEMBER
|
||||||
@@ -334,33 +296,46 @@ class MultiFieldValueClassSpecificDeclarations(
|
|||||||
}.apply {
|
}.apply {
|
||||||
parent = valueClass
|
parent = valueClass
|
||||||
copyTypeParametersFrom(valueClass)
|
copyTypeParametersFrom(valueClass)
|
||||||
addFlattenedClassRepresentationToParameters()
|
addFlattenedClassRepresentationToParameters(classToFunctionTypeParametersMapping())
|
||||||
// body is added in Lowering file
|
// body is added in Lowering file
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun IrFunction.addFlattenedClassRepresentationToParameters() {
|
private fun IrFunction.addFlattenedClassRepresentationToParameters(substitutionMap: Map<IrTypeParameterSymbol, IrType>) {
|
||||||
for (leaf in leaves) {
|
for (leaf in leaves) {
|
||||||
addValueParameter {
|
addValueParameter {
|
||||||
this.name = nodeFullNames[leaf]!!
|
this.name = nodeFullNames[leaf]!!
|
||||||
this.type = leaf.type
|
this.type = leaf.type.substitute(substitutionMap)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val specializedEqualsMethod = irFactory.buildFun {
|
val specializedEqualsMethod = irFactory.buildFun {
|
||||||
name = InlineClassDescriptorResolver.SPECIALIZED_EQUALS_NAME
|
name = InlineClassDescriptorResolver.SPECIALIZED_EQUALS_NAME
|
||||||
// TODO: Revisit this once we allow user defined equals methods in inline classes.
|
// TODO: Revisit this once we allow user defined equals methods in value classes.
|
||||||
origin = JvmLoweredDeclarationOrigin.MULTI_FIELD_VALUE_CLASS_GENERATED_IMPL_METHOD
|
origin = JvmLoweredDeclarationOrigin.MULTI_FIELD_VALUE_CLASS_GENERATED_IMPL_METHOD
|
||||||
returnType = context.irBuiltIns.booleanType
|
returnType = context.irBuiltIns.booleanType
|
||||||
}.apply {
|
}.apply {
|
||||||
parent = valueClass
|
parent = valueClass
|
||||||
copyTypeParametersFrom(oldPrimaryConstructor)
|
copyTypeParametersFrom(valueClass)
|
||||||
|
val typeParametersHalf1 = typeParameters.apply {
|
||||||
|
for (it in this) {
|
||||||
|
it.name = Name.guessByFirstCharacter("${it.name.asString()}1")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val substitutionMapHalf1 = (valueClass.typeParameters.map { it.symbol } zip typeParametersHalf1.map { it.defaultType }).toMap()
|
||||||
|
copyTypeParametersFrom(valueClass)
|
||||||
|
val typeParametersHalf2 = typeParameters.drop(typeParametersHalf1.size).apply {
|
||||||
|
for (it in this) {
|
||||||
|
it.name = Name.guessByFirstCharacter("${it.name.asString()}2")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val substitutionMapHalf2 = (valueClass.typeParameters.map { it.symbol } zip typeParametersHalf2.map { it.defaultType }).toMap()
|
||||||
for (leaf in leaves) {
|
for (leaf in leaves) {
|
||||||
addValueParameter {
|
addValueParameter {
|
||||||
this.name = Name.guessByFirstCharacter(
|
this.name = Name.guessByFirstCharacter(
|
||||||
"${InlineClassDescriptorResolver.SPECIALIZED_EQUALS_FIRST_PARAMETER_NAME}$${nodeFullNames[leaf]!!.asString()}"
|
"${InlineClassDescriptorResolver.SPECIALIZED_EQUALS_FIRST_PARAMETER_NAME}$${nodeFullNames[leaf]!!.asString()}"
|
||||||
)
|
)
|
||||||
this.type = leaf.type
|
this.type = leaf.type.substitute(substitutionMapHalf1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (leaf in leaves) {
|
for (leaf in leaves) {
|
||||||
@@ -368,7 +343,7 @@ class MultiFieldValueClassSpecificDeclarations(
|
|||||||
this.name = Name.guessByFirstCharacter(
|
this.name = Name.guessByFirstCharacter(
|
||||||
"${InlineClassDescriptorResolver.SPECIALIZED_EQUALS_SECOND_PARAMETER_NAME}$${nodeFullNames[leaf]!!.asString()}"
|
"${InlineClassDescriptorResolver.SPECIALIZED_EQUALS_SECOND_PARAMETER_NAME}$${nodeFullNames[leaf]!!.asString()}"
|
||||||
)
|
)
|
||||||
this.type = leaf.type
|
this.type = leaf.type.substitute(substitutionMapHalf2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// body is added in Lowering file
|
// body is added in Lowering file
|
||||||
@@ -388,9 +363,10 @@ class MultiFieldValueClassSpecificDeclarations(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val properties: Map<MultiFieldValueClassTree<Unit, Unit>, IrProperty> =
|
val properties: Map<MultiFieldValueClassTree, IrProperty> = run {
|
||||||
selfImplementationAgnosticDeclarations.nodeToExpressionGetters.filterKeys { it in nodeFullNames }.mapValues { (node, getter) ->
|
val nodes2expressions: Map<MultiFieldValueClassTree, IrBuilderWithScope.(function: IrFunction) -> IrExpression> =
|
||||||
val propertyName = nodeFullNames[node]!!
|
makeNodes2FieldExpressions(fields)
|
||||||
|
nodeFullNames.mapValues { (node, propertyName) ->
|
||||||
val overrideable = oldProperties[propertyName]
|
val overrideable = oldProperties[propertyName]
|
||||||
irFactory.buildProperty {
|
irFactory.buildProperty {
|
||||||
name = propertyName
|
name = propertyName
|
||||||
@@ -404,42 +380,75 @@ class MultiFieldValueClassSpecificDeclarations(
|
|||||||
returnType = node.type
|
returnType = node.type
|
||||||
origin = IrDeclarationOrigin.GENERATED_MULTI_FIELD_VALUE_CLASS_MEMBER
|
origin = IrDeclarationOrigin.GENERATED_MULTI_FIELD_VALUE_CLASS_MEMBER
|
||||||
}.apply {
|
}.apply {
|
||||||
|
val function = this
|
||||||
overrideable?.getter?.overriddenSymbols?.let { overriddenSymbols = it }
|
overrideable?.getter?.overriddenSymbols?.let { overriddenSymbols = it }
|
||||||
createDispatchReceiverParameter()
|
createDispatchReceiverParameter()
|
||||||
body = with(context.createIrBuilder(this.symbol)) {
|
body = with(context.createIrBuilder(this.symbol)) {
|
||||||
irExprBody(getter(this, dispatchReceiverParameter!!))
|
irExprBody(nodes2expressions[node]!!.invoke(this, function))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data class VirtualProperty<in T>(
|
companion object {
|
||||||
|
private fun IrFunctionAccessExpression.copyTypeArgumentsFromType(
|
||||||
|
type: IrSimpleType, valueClass: IrClass, substitutionMap: Map<IrTypeParameterSymbol, IrType>
|
||||||
|
) {
|
||||||
|
require(type.erasedUpperBound == valueClass) {
|
||||||
|
"Illegal bound ${type.erasedUpperBound.render()} instead of ${valueClass.render()}"
|
||||||
|
}
|
||||||
|
require(type.arguments.size == valueClass.typeParameters.size) {
|
||||||
|
"Unexpected number of type arguments: ${type.arguments.size} for ${valueClass.typeParameters.size} parameters"
|
||||||
|
}
|
||||||
|
require(type.arguments.size == symbol.owner.typeParameters.size) {
|
||||||
|
"Unexpected number of type arguments: ${type.arguments.size} for ${symbol.owner.typeParameters.size} parameters"
|
||||||
|
}
|
||||||
|
for (i in valueClass.typeParameters.indices) {
|
||||||
|
putTypeArgument(i, type.arguments[i].typeOrNull?.substitute(substitutionMap))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun makeNodes2FieldExpressions(fields: List<IrField>): Map<MultiFieldValueClassTree, IrBuilderWithScope.(IrFunction) -> IrExpression> {
|
||||||
|
fun proceed(node: MultiFieldValueClassTree): Map<MultiFieldValueClassTree, IrBuilderWithScope.(function: IrFunction) -> IrExpression> =
|
||||||
|
when (node) {
|
||||||
|
is InternalNode -> buildMap {
|
||||||
|
val innerDeclarations =
|
||||||
|
if (node.irClass == valueClass) this@MultiFieldValueClassSpecificDeclarations
|
||||||
|
else replacements.getDeclarations(node.irClass)!!
|
||||||
|
put(node) { function ->
|
||||||
|
irCall(innerDeclarations.boxMethod).apply {
|
||||||
|
copyTypeArgumentsFromType(node.type, node.irClass, mapOf())
|
||||||
|
indexesByInternalNode[node]!!.forEachIndexed { index, nodeIndex ->
|
||||||
|
putValueArgument(index, fieldGetter(function.dispatchReceiverParameter!!, fields[nodeIndex]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node.fields.forEach { putAll(proceed(it.node)) }
|
||||||
|
}
|
||||||
|
is Leaf -> mapOf(node to { fieldGetter(it.dispatchReceiverParameter!!, fields[indexByLeaf[node]!!]) })
|
||||||
|
}
|
||||||
|
return proceed(loweringRepresentation)
|
||||||
|
}
|
||||||
|
|
||||||
|
data class VirtualProperty(
|
||||||
val type: IrType,
|
val type: IrType,
|
||||||
val makeGetter: ExpressionGenerator<T>,
|
val makeGetter: ExpressionGenerator,
|
||||||
val assigner: ExpressionSupplier<T>?,
|
val assigner: ExpressionSupplier?,
|
||||||
val symbol: IrValueSymbol?
|
val symbol: IrValueSymbol?
|
||||||
) {
|
) {
|
||||||
constructor(declaration: IrValueDeclaration) : this(
|
constructor(declaration: IrValueDeclaration) : this(
|
||||||
declaration.type,
|
declaration.type,
|
||||||
{ irGet(declaration) },
|
{ irGet(declaration) },
|
||||||
if (declaration.isAssignable) { _, value -> irSet(declaration, value) } else null,
|
if (declaration.isAssignable) { value -> irSet(declaration, value) } else null,
|
||||||
declaration.symbol,
|
declaration.symbol,
|
||||||
)
|
)
|
||||||
|
|
||||||
val isAssignable: Boolean
|
val isAssignable: Boolean
|
||||||
get() = assigner != null
|
get() = assigner != null
|
||||||
|
|
||||||
fun <R> map(f: (R) -> T) = VirtualProperty<R>(
|
|
||||||
type = type,
|
|
||||||
makeGetter = { makeGetter(f(it)) },
|
|
||||||
assigner = assigner?.let { assigner -> { additionalParam, value -> assigner(f(additionalParam), value) } },
|
|
||||||
symbol = symbol,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun implementationAgnosticFromDeclarations(declarations: List<IrValueDeclaration>) =
|
|
||||||
ImplementationAgnostic<Any?>(declarations.map { VirtualProperty(it) })
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Multi-field value class instance can be not only a standalone instance but also:
|
* Multi-field value class instance can be not only a standalone instance but also:
|
||||||
* 1. A slice of fields in another multi-field class instance;
|
* 1. A slice of fields in another multi-field class instance;
|
||||||
@@ -449,28 +458,31 @@ class MultiFieldValueClassSpecificDeclarations(
|
|||||||
* 5. Virtual instance constructed with local fields;
|
* 5. Virtual instance constructed with local fields;
|
||||||
* 6. Some mix of the above ones.
|
* 6. Some mix of the above ones.
|
||||||
*/
|
*/
|
||||||
inner class ImplementationAgnostic<T>(val virtualFields: List<VirtualProperty<T>>) {
|
inner class ImplementationAgnostic constructor(val type: IrSimpleType, val virtualFields: List<VirtualProperty>) {
|
||||||
val regularDeclarations = this@MultiFieldValueClassSpecificDeclarations
|
val regularDeclarations = this@MultiFieldValueClassSpecificDeclarations
|
||||||
val symbols = virtualFields.map { it.symbol }
|
val symbols = virtualFields.map { it.symbol }
|
||||||
|
private val substitutionMap = valueClass.typeParameters.map { it.symbol }.zip(type.arguments.map { it.typeOrNull })
|
||||||
fun <R> map(f: (R) -> T) = ImplementationAgnostic(virtualFields.map { it.map(f) })
|
.mapNotNull { (parameter, type) -> if (type != null) parameter to type else null }.toMap()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
require(virtualFields.size == leaves.size) { "Wrong symbols number given for $leaves, got $virtualFields" }
|
require(virtualFields.size == leaves.size) { "Wrong symbols number given for $leaves, got $virtualFields" }
|
||||||
for ((actual, expected) in virtualFields.map { it.type } zip leaves.map { it.type }) {
|
for ((actual, expected) in virtualFields.map { it.type } zip leaves.map { it.type }) {
|
||||||
require(actual.isSubtypeOf(expected, typeSystemContext)) { "$actual is not a subtype of $expected for MFVC $valueClass" }
|
require(actual.upperBound.isSubtypeOf(expected.upperBound, typeSystemContext)) {
|
||||||
|
"${actual.render()} is not a subtype of ${expected.render()} for MFVC ${valueClass.render()}"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val nodeToSymbols = indexesByInternalNode.mapValues { (_, indexes) -> virtualFields.slice(indexes) } +
|
private val nodeToSymbols = indexesByInternalNode.mapValues { (_, indexes) -> virtualFields.slice(indexes) } +
|
||||||
indexByLeaf.mapValues { (_, index) -> listOf(virtualFields[index]) }
|
indexByLeaf.mapValues { (_, index) -> listOf(virtualFields[index]) }
|
||||||
|
|
||||||
private val internalNodeToExpressionGetters: Map<InternalNode<Unit, Unit>, ExpressionGenerator<T>> =
|
private val internalNodeToExpressionGetters: Map<InternalNode, ExpressionGenerator> =
|
||||||
indexesByInternalNode.mapValues { (node, indexes) ->
|
indexesByInternalNode.mapValues { (node, indexes) ->
|
||||||
{ additionalParameter ->
|
{
|
||||||
val arguments = virtualFields.slice(indexes).map { it.makeGetter(this, additionalParameter) }
|
val arguments = virtualFields.slice(indexes).map { it.makeGetter(this) }
|
||||||
val innerDeclarations = replacements.getDeclarations(node.irClass)!!
|
val innerDeclarations = replacements.getDeclarations(node.irClass)!!
|
||||||
irCall(innerDeclarations.boxMethod).apply {
|
irCall(innerDeclarations.boxMethod).apply {
|
||||||
|
copyTypeArgumentsFromType(node.type, node.irClass, substitutionMap)
|
||||||
for (i in arguments.indices) {
|
for (i in arguments.indices) {
|
||||||
putValueArgument(i, arguments[i])
|
putValueArgument(i, arguments[i])
|
||||||
}
|
}
|
||||||
@@ -478,13 +490,13 @@ class MultiFieldValueClassSpecificDeclarations(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val leavesToExpressionGetters: Map<Leaf<Unit>, ExpressionGenerator<T>> =
|
private val leavesToExpressionGetters: Map<Leaf, ExpressionGenerator> =
|
||||||
indexByLeaf.mapValues { (_, index) -> { virtualFields[index].makeGetter(this, it) } }
|
indexByLeaf.mapValues { (_, index) -> { virtualFields[index].makeGetter(this) } }
|
||||||
|
|
||||||
val nodeToExpressionGetters: Map<MultiFieldValueClassTree<Unit, Unit>, ExpressionGenerator<T>> =
|
val nodeToExpressionGetters: Map<MultiFieldValueClassTree, ExpressionGenerator> =
|
||||||
internalNodeToExpressionGetters + leavesToExpressionGetters
|
internalNodeToExpressionGetters + leavesToExpressionGetters
|
||||||
|
|
||||||
operator fun get(name: Name): Pair<ExpressionGenerator<T>, ImplementationAgnostic<T>?>? =
|
operator fun get(name: Name): Pair<ExpressionGenerator, ImplementationAgnostic?>? =
|
||||||
when (val field = loweringRepresentation[name]) {
|
when (val field = loweringRepresentation[name]) {
|
||||||
null -> null
|
null -> null
|
||||||
else -> nodeToExpressionGetters[field.node]!! to when (field.node) {
|
else -> nodeToExpressionGetters[field.node]!! to when (field.node) {
|
||||||
@@ -492,24 +504,17 @@ class MultiFieldValueClassSpecificDeclarations(
|
|||||||
is InternalNode -> {
|
is InternalNode -> {
|
||||||
val irClass = field.node.irClass
|
val irClass = field.node.irClass
|
||||||
val declarations = replacements.getDeclarations(irClass)!!
|
val declarations = replacements.getDeclarations(irClass)!!
|
||||||
declarations.ImplementationAgnostic(nodeToSymbols[field.node]!!)
|
declarations.ImplementationAgnostic(field.type as IrSimpleType, nodeToSymbols[field.node]!!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val boxedExpression = nodeToExpressionGetters[loweringRepresentation]!!
|
val boxedExpression = nodeToExpressionGetters[loweringRepresentation]!!
|
||||||
|
|
||||||
// todo type parameters
|
|
||||||
// todo recursive
|
|
||||||
// todo cheeeck!!!
|
|
||||||
// todo equals
|
|
||||||
// todo toString
|
|
||||||
// todo hashCode
|
|
||||||
// todo default parameters
|
// todo default parameters
|
||||||
// todo annotations etc.
|
// todo annotations etc.
|
||||||
// todo inline in not value class
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
typealias ExpressionGenerator<T> = IrBuilderWithScope.(T) -> IrExpression
|
typealias ExpressionGenerator = IrBuilderWithScope.() -> IrExpression
|
||||||
typealias ExpressionSupplier<T> = IrBuilderWithScope.(T, IrExpression) -> IrStatement
|
typealias ExpressionSupplier = IrBuilderWithScope.(IrExpression) -> IrStatement
|
||||||
@@ -12,8 +12,23 @@ interface AbstractPoint<T> {
|
|||||||
val y: T
|
val y: T
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface SomeInterface<X> {
|
||||||
|
fun <T, R: X> someFunction1(x: X, t: T, r: R) = Unit
|
||||||
|
fun <T, R: X> someFunction2(x: XPoint<X>, t: XPoint<T>, r: XPoint<R>) = Unit
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@JvmInline
|
@JvmInline
|
||||||
value class XPoint<X>(override val x: X, override val y: X): AbstractPoint<X>
|
value class XPoint<X>(override val x: X, override val y: X): AbstractPoint<X>, SomeInterface<X> {
|
||||||
|
override fun <T, R: X> someFunction1(x: X, t: T, r: R) = Unit
|
||||||
|
override fun <T, R: X> someFunction2(x: XPoint<X>, t: XPoint<T>, r: XPoint<R>) = Unit
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmInline
|
||||||
|
value class YPoint<X>(val x: X)
|
||||||
|
|
||||||
|
fun <S: List<Int>> genericFunctionMFVC(v: XPoint<S>) {}
|
||||||
|
fun <S: List<Int>> genericFunctionIC(v: YPoint<S>) {}
|
||||||
|
|
||||||
interface GenericMFVCHolder<T> {
|
interface GenericMFVCHolder<T> {
|
||||||
var p: T
|
var p: T
|
||||||
|
|||||||
@@ -2354,6 +2354,8 @@ public final class Overrides_typeParametersKt {
|
|||||||
inner (anonymous) class Overrides_typeParametersKt$box$xPointLam$1
|
inner (anonymous) class Overrides_typeParametersKt$box$xPointLam$1
|
||||||
public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String
|
public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String
|
||||||
public final static method equal(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function0, @org.jetbrains.annotations.NotNull p1: kotlin.jvm.functions.Function0): void
|
public final static method equal(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function0, @org.jetbrains.annotations.NotNull p1: kotlin.jvm.functions.Function0): void
|
||||||
|
public final static method genericFunctionIC-lld4ICU(@org.jetbrains.annotations.NotNull p0: java.lang.Object): void
|
||||||
|
public final static method genericFunctionMFVC-sUp7gFk(@org.jetbrains.annotations.NotNull p0: java.util.List, @org.jetbrains.annotations.NotNull p1: java.util.List): void
|
||||||
}
|
}
|
||||||
|
|
||||||
@kotlin.Metadata
|
@kotlin.Metadata
|
||||||
@@ -2443,6 +2445,22 @@ public interface ReifiedMFVCHolderWithImpls {
|
|||||||
public final inner class ReifiedMFVCHolderWithImpls$DefaultImpls
|
public final inner class ReifiedMFVCHolderWithImpls$DefaultImpls
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@kotlin.Metadata
|
||||||
|
public final class SomeInterface$DefaultImpls {
|
||||||
|
// source: 'overrides_typeParameters.kt'
|
||||||
|
public static method someFunction1(@org.jetbrains.annotations.NotNull p0: SomeInterface, p1: java.lang.Object, p2: java.lang.Object, p3: java.lang.Object): void
|
||||||
|
public static method someFunction2-lIoT8es(@org.jetbrains.annotations.NotNull p0: SomeInterface, p1: java.lang.Object, p2: java.lang.Object, p3: java.lang.Object, p4: java.lang.Object, p5: java.lang.Object, p6: java.lang.Object): void
|
||||||
|
public final inner class SomeInterface$DefaultImpls
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.Metadata
|
||||||
|
public interface SomeInterface {
|
||||||
|
// source: 'overrides_typeParameters.kt'
|
||||||
|
public abstract method someFunction1(p0: java.lang.Object, p1: java.lang.Object, p2: java.lang.Object): void
|
||||||
|
public abstract method someFunction2-lIoT8es(p0: java.lang.Object, p1: java.lang.Object, p2: java.lang.Object, p3: java.lang.Object, p4: java.lang.Object, p5: java.lang.Object): void
|
||||||
|
public final inner class SomeInterface$DefaultImpls
|
||||||
|
}
|
||||||
|
|
||||||
@kotlin.Metadata
|
@kotlin.Metadata
|
||||||
public interface SomePointInterface {
|
public interface SomePointInterface {
|
||||||
// source: 'overrides_typeParameters.kt'
|
// source: 'overrides_typeParameters.kt'
|
||||||
@@ -2481,6 +2499,10 @@ public final class XPoint {
|
|||||||
public final method getY(): java.lang.Object
|
public final method getY(): java.lang.Object
|
||||||
public method hashCode(): int
|
public method hashCode(): int
|
||||||
public static method hashCode-impl(p0: java.lang.Object, p1: java.lang.Object): int
|
public static method hashCode-impl(p0: java.lang.Object, p1: java.lang.Object): int
|
||||||
|
public method someFunction1(p0: java.lang.Object, p1: java.lang.Object, p2: java.lang.Object): void
|
||||||
|
public static method someFunction1-impl(p0: java.lang.Object, p1: java.lang.Object, p2: java.lang.Object, p3: java.lang.Object, p4: java.lang.Object): void
|
||||||
|
public method someFunction2-lIoT8es(p0: java.lang.Object, p1: java.lang.Object, p2: java.lang.Object, p3: java.lang.Object, p4: java.lang.Object, p5: java.lang.Object): void
|
||||||
|
public static method someFunction2-lIoT8es(p0: java.lang.Object, p1: java.lang.Object, p2: java.lang.Object, p3: java.lang.Object, p4: java.lang.Object, p5: java.lang.Object, p6: java.lang.Object, p7: java.lang.Object): void
|
||||||
public @org.jetbrains.annotations.NotNull method toString(): java.lang.String
|
public @org.jetbrains.annotations.NotNull method toString(): java.lang.String
|
||||||
public static method toString-impl(p0: java.lang.Object, p1: java.lang.Object): java.lang.String
|
public static method toString-impl(p0: java.lang.Object, p1: java.lang.Object): java.lang.String
|
||||||
public synthetic final method unbox-impl0(): java.lang.Object
|
public synthetic final method unbox-impl0(): java.lang.Object
|
||||||
@@ -2554,3 +2576,22 @@ public final class XSegment {
|
|||||||
public synthetic final method unbox-impl2(): java.lang.Object
|
public synthetic final method unbox-impl2(): java.lang.Object
|
||||||
public synthetic final method unbox-impl3(): java.lang.Object
|
public synthetic final method unbox-impl3(): java.lang.Object
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@kotlin.jvm.JvmInline
|
||||||
|
@kotlin.Metadata
|
||||||
|
public final class YPoint {
|
||||||
|
// source: 'overrides_typeParameters.kt'
|
||||||
|
private final field x: java.lang.Object
|
||||||
|
private synthetic method <init>(p0: java.lang.Object): void
|
||||||
|
public synthetic final static method box-impl(p0: java.lang.Object): YPoint
|
||||||
|
public static @org.jetbrains.annotations.NotNull method constructor-impl(p0: java.lang.Object): java.lang.Object
|
||||||
|
public method equals(p0: java.lang.Object): boolean
|
||||||
|
public static method equals-impl(p0: java.lang.Object, p1: java.lang.Object): boolean
|
||||||
|
public final static method equals-impl0(p0: java.lang.Object, p1: java.lang.Object): boolean
|
||||||
|
public final method getX(): java.lang.Object
|
||||||
|
public method hashCode(): int
|
||||||
|
public static method hashCode-impl(p0: java.lang.Object): int
|
||||||
|
public method toString(): java.lang.String
|
||||||
|
public static method toString-impl(p0: java.lang.Object): java.lang.String
|
||||||
|
public synthetic final method unbox-impl(): java.lang.Object
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user