[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 -> {
|
||||
val count = bridgeRemappedParameter.declarations.fields.size
|
||||
val boxCall = irCall(bridgeRemappedParameter.declarations.boxMethod).apply {
|
||||
bridgeRemappedParameter.boxedType.arguments.forEachIndexed { index, argument ->
|
||||
putTypeArgument(index, argument.typeOrNull)
|
||||
}
|
||||
for (i in 0 until count) {
|
||||
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.impl.IrTypeOperatorCallImpl
|
||||
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.visitors.*
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
@@ -135,6 +136,9 @@ private class InheritedDefaultMethodsOnClassesLowering(val context: JvmBackendCo
|
||||
when (val remappedParameter = structure[i]) {
|
||||
is MultiFieldValueClassMapping ->
|
||||
putValueArgument(i, irCall(remappedParameter.declarations.boxMethod).apply {
|
||||
remappedParameter.boxedType.arguments.forEachIndexed { index, argument ->
|
||||
putTypeArgument(index, argument.typeOrNull)
|
||||
}
|
||||
val boxArgumentsCount = remappedParameter.valueParameters.size
|
||||
for (boxArgumentIndex in 0 until boxArgumentsCount) {
|
||||
putValueArgument(boxArgumentIndex, irGet(sourceFullValueParameterList[flattenedIndex++]))
|
||||
|
||||
+119
-76
@@ -5,10 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.backend.jvm.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.ir.copyParameterDeclarationsFrom
|
||||
import org.jetbrains.kotlin.backend.common.ir.copyTo
|
||||
import org.jetbrains.kotlin.backend.common.ir.createDispatchReceiverParameter
|
||||
import org.jetbrains.kotlin.backend.common.ir.passTypeArgumentsFrom
|
||||
import org.jetbrains.kotlin.backend.common.ir.*
|
||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
||||
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.VirtualProperty
|
||||
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.isMultiFieldValueClassType
|
||||
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.impl.IrAnonymousInitializerSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.transformStatement
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.isNullable
|
||||
import org.jetbrains.kotlin.ir.types.makeNotNull
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||
@@ -58,39 +54,39 @@ val jvmMultiFieldValueClassPhase = makeIrFilePhase(
|
||||
private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmValueClassAbstractLowering(context) {
|
||||
|
||||
private open inner class ValueDeclarationsRemapper {
|
||||
private val symbol2getter = mutableMapOf<IrValueSymbol, ExpressionGenerator<Unit>>()
|
||||
private val symbol2setters = mutableMapOf<IrValueSymbol, List<ExpressionSupplier<Unit>?>>()
|
||||
private val knownExpressions = mutableMapOf<IrExpression, ImplementationAgnostic<Unit>>()
|
||||
private val symbol2getter = mutableMapOf<IrValueSymbol, ExpressionGenerator>()
|
||||
private val symbol2setters = mutableMapOf<IrValueSymbol, List<ExpressionSupplier?>>()
|
||||
private val knownExpressions = mutableMapOf<IrExpression, ImplementationAgnostic>()
|
||||
|
||||
fun remapSymbol(original: IrValueSymbol, replacement: IrValueDeclaration) {
|
||||
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(
|
||||
original: IrValueSymbol,
|
||||
unboxed: List<VirtualProperty<Unit>>,
|
||||
unboxed: List<VirtualProperty>,
|
||||
declarations: MultiFieldValueClassSpecificDeclarations
|
||||
): 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] = {
|
||||
unboxed.boxedExpression(this, Unit).also { irExpression -> knownExpressions[irExpression] = unboxed }
|
||||
unboxed.boxedExpression(this).also { irExpression -> knownExpressions[irExpression] = unboxed }
|
||||
}
|
||||
symbol2setters[original] = unboxed.virtualFields.map { it.assigner }
|
||||
}
|
||||
|
||||
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? =
|
||||
implementationAgnostic(expression)?.get(name)?.let { (expressionGenerator, representation) ->
|
||||
val res = expressionGenerator(this, Unit)
|
||||
val res = expressionGenerator(this)
|
||||
representation?.let { knownExpressions[res] = it }
|
||||
res
|
||||
}
|
||||
@@ -98,7 +94,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
|
||||
/**
|
||||
* 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
|
||||
}
|
||||
}
|
||||
@@ -108,7 +104,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
|
||||
private val regularClassMFVCPropertyMainGetters: MutableMap<IrClass, MutableMap<Name, IrSimpleFunction>> = mutableMapOf()
|
||||
private val regularClassMFVCPropertyNextGetters: MutableMap<IrSimpleFunction, Map<Name, IrSimpleFunction>> = mutableMapOf()
|
||||
private val regularClassMFVCPropertyFieldsMapping: MutableMap<IrField, List<IrField>> = mutableMapOf()
|
||||
private val regularClassMFVCPropertyNodes: MutableMap<IrSimpleFunction, MultiFieldValueClassTree<Unit, Unit>> = mutableMapOf()
|
||||
private val regularClassMFVCPropertyNodes: MutableMap<IrSimpleFunction, MultiFieldValueClassTree> = mutableMapOf()
|
||||
private val regularClassMFVCPropertyAllPrimitiveGetters: MutableSet<IrSimpleFunction> = mutableSetOf()
|
||||
|
||||
override val replacements
|
||||
@@ -148,7 +144,6 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
|
||||
|
||||
val oldFieldToInitializers: MutableMap<IrField, IrAnonymousInitializer> = mutableMapOf()
|
||||
// we need to preserve order of initializations
|
||||
// todo test it
|
||||
val newFields: List<List<IrField>> = fieldsToReplace.map { oldField ->
|
||||
val declarations = replacements.getDeclarations(oldField.type.erasedUpperBound)!!
|
||||
val newFields = declarations.fields.map { sourceField ->
|
||||
@@ -163,15 +158,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
|
||||
}
|
||||
}
|
||||
regularClassMFVCPropertyFieldsMapping[oldField] = newFields
|
||||
val virtualFields: List<VirtualProperty<IrValueDeclaration>> = newFields.map { newField ->
|
||||
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 nodes2getters = declarations.makeNodes2FieldExpressions(newFields)
|
||||
|
||||
val property = oldField.correspondingPropertySymbol?.owner
|
||||
val mainGetter = property?.getter
|
||||
@@ -181,7 +168,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
|
||||
if (!property.isDelegated && mainGetter.isDefaultGetter(oldField)) {
|
||||
mainGetter.origin = IrDeclarationOrigin.GENERATED_MULTI_FIELD_VALUE_CLASS_MEMBER
|
||||
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 {
|
||||
context.irFactory.buildProperty {
|
||||
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
|
||||
}.apply {
|
||||
createDispatchReceiverParameter()
|
||||
val function = this
|
||||
body = with(context.createIrBuilder(this.symbol)) {
|
||||
irExprBody(exprGen(this, dispatchReceiverParameter!!))
|
||||
irExprBody(exprGen(this, function))
|
||||
}
|
||||
}
|
||||
}.getter!!.also {
|
||||
@@ -206,7 +194,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
|
||||
}
|
||||
regularClassMFVCPropertyNodes.putAll(nodesToGetters.map { (node, getter) -> getter to node })
|
||||
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]!! }
|
||||
}
|
||||
}
|
||||
@@ -225,9 +213,9 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
|
||||
val representation = newFields.zip(gettersAndSetters) { newField, (getter, setter) ->
|
||||
VirtualProperty(newField.type, getter, setter, null)
|
||||
}
|
||||
val fieldRepresentation = declarations.ImplementationAgnostic(representation)
|
||||
val fieldRepresentation = declarations.ImplementationAgnostic(oldField.type as IrSimpleType, representation)
|
||||
val boxed = fieldRepresentation.boxedExpression(
|
||||
context.createIrBuilder((currentScope!!.irElement as IrSymbolOwner).symbol), Unit
|
||||
context.createIrBuilder((currentScope!!.irElement as IrSymbolOwner).symbol)
|
||||
)
|
||||
valueDeclarationsRemapper.registerExpression(boxed, fieldRepresentation)
|
||||
return boxed
|
||||
@@ -330,18 +318,35 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
|
||||
name = mangledName
|
||||
returnType = source.returnType
|
||||
}.apply {
|
||||
val overriddenReplaced = replacement.overriddenSymbols.firstOrNull {
|
||||
replacements.bindingNewFunctionToParameterTemplateStructure[it.owner] != null
|
||||
}?.owner
|
||||
if (source.parentAsClass.isMultiFieldValueClass && overriddenReplaced != null) {
|
||||
copyParameterDeclarationsFrom(overriddenReplaced)
|
||||
dispatchReceiverParameter = source.dispatchReceiverParameter!!.copyTo(this)
|
||||
val replacementStructure = replacement.overriddenSymbols.firstNotNullOf {
|
||||
replacements.bindingNewFunctionToParameterTemplateStructure[it.owner]
|
||||
}.toMutableList().apply {
|
||||
set(0, RegularMapping(ValueParameterTemplate(dispatchReceiverParameter!!, dispatchReceiverParameter!!.origin)))
|
||||
val anyOverriddenReplaced = replacement.overriddenSymbols.any {
|
||||
it.owner in replacements.bindingNewFunctionToParameterTemplateStructure
|
||||
}
|
||||
if (source.parentAsClass.isMultiFieldValueClass && anyOverriddenReplaced) {
|
||||
copyTypeParametersFrom(source) // without static type parameters
|
||||
val substitutionMap = makeTypeParameterSubstitutionMap(source, this)
|
||||
dispatchReceiverParameter = source.dispatchReceiverParameter!!.let { // source!!!
|
||||
it.copyTo(this, type = it.type.substitute(substitutionMap))
|
||||
}
|
||||
replacements.bindingNewFunctionToParameterTemplateStructure[this] = replacementStructure
|
||||
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)))
|
||||
}
|
||||
replacements.bindingNewFunctionToParameterTemplateStructure[this] = bridgeStructure
|
||||
} else {
|
||||
copyParameterDeclarationsFrom(source)
|
||||
}
|
||||
@@ -358,9 +363,9 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
|
||||
allScopes.push(createScope(source))
|
||||
source.body = context.createIrBuilder(source.symbol, source.startOffset, source.endOffset).run {
|
||||
val sourceExplicitParameters = source.explicitParameters
|
||||
val targetExplicitParameters = target.explicitParameters
|
||||
irExprBody(irCall(target).apply {
|
||||
passTypeArgumentsFrom(source)
|
||||
val targetExplicitParameters = target.explicitParameters
|
||||
passTypeArgumentsWithOffsets(target, source) { source.typeParameters[it].defaultType }
|
||||
val sourceStructure: List<RemappedParameter>? = replacements.bindingNewFunctionToParameterTemplateStructure[source]
|
||||
val targetStructure: List<RemappedParameter>? = replacements.bindingNewFunctionToParameterTemplateStructure[target]
|
||||
val errorMessage = {
|
||||
@@ -415,15 +420,17 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
|
||||
)
|
||||
}
|
||||
}
|
||||
is RegularMapping, null ->
|
||||
putArgument(
|
||||
targetExplicitParameters[flattenedTargetIndex++],
|
||||
irCall(remappedSourceParameter.declarations.boxMethod).apply {
|
||||
sourceExplicitParameters
|
||||
.slice(flattenedSourceIndex until flattenedSourceIndex + remappedSourceParameter.valueParameters.size)
|
||||
.forEachIndexed { index, boxParameter -> putValueArgument(index, irGet(boxParameter)) }
|
||||
.also { flattenedSourceIndex += remappedSourceParameter.valueParameters.size }
|
||||
})
|
||||
is RegularMapping, null -> putArgument(
|
||||
targetExplicitParameters[flattenedTargetIndex++],
|
||||
irCall(remappedSourceParameter.declarations.boxMethod).apply {
|
||||
remappedSourceParameter.boxedType.arguments.forEachIndexed { index, argument ->
|
||||
putTypeArgument(index, argument.typeOrNull)
|
||||
}
|
||||
sourceExplicitParameters
|
||||
.slice(flattenedSourceIndex until flattenedSourceIndex + remappedSourceParameter.valueParameters.size)
|
||||
.forEachIndexed { index, boxParameter -> putValueArgument(index, irGet(boxParameter)) }
|
||||
.also { flattenedSourceIndex += remappedSourceParameter.valueParameters.size }
|
||||
})
|
||||
}
|
||||
}
|
||||
is RegularMapping, null -> when (remappedTargetParameter) {
|
||||
@@ -451,6 +458,34 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
|
||||
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) {
|
||||
val parametersStructure = replacements.bindingOldFunctionToParameterTemplateStructure[original]!!
|
||||
require(parametersStructure.size == original.explicitParameters.size) {
|
||||
@@ -495,7 +530,6 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
|
||||
fun MultiFieldValueClassSpecificDeclarations.buildBoxFunction() {
|
||||
boxMethod.body = with(context.createIrBuilder(boxMethod.symbol)) {
|
||||
irExprBody(irCall(primaryConstructor.symbol).apply {
|
||||
passTypeArgumentsFrom(boxMethod)
|
||||
for (i in leaves.indices) {
|
||||
putValueArgument(i, irGet(boxMethod.valueParameters[i]))
|
||||
}
|
||||
@@ -568,6 +602,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
|
||||
if (newReceiver is IrCall) {
|
||||
val nextFunction = regularClassMFVCPropertyNextGetters[newReceiver.symbol.owner]?.get(name)
|
||||
if (nextFunction != null) {
|
||||
require(nextFunction.typeParameters.isEmpty()) { "Subgetter with type parameters: ${nextFunction.render()}" }
|
||||
return irCall(nextFunction).apply {
|
||||
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" }
|
||||
return context.createIrBuilder(expression.symbol).run {
|
||||
irCall(leftImplementation.regularDeclarations.specializedEqualsMethod).apply {
|
||||
(leftImplementation.type.arguments + rightImplementation.type.arguments).forEachIndexed { index, argument ->
|
||||
putTypeArgument(index, argument.typeOrNull)
|
||||
}
|
||||
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) }
|
||||
}
|
||||
}
|
||||
@@ -625,6 +663,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
|
||||
val nonNullLeftArgumentVariable =
|
||||
irTemporary(irImplicitCast(irGet(leftValue), leftArgument.type.makeNotNull()))
|
||||
+irCall(context.irBuiltIns.eqeqSymbol).apply {
|
||||
copyTypeArgumentsFrom(expression)
|
||||
putValueArgument(0, irGet(nonNullLeftArgumentVariable))
|
||||
putValueArgument(1, rightArgument)
|
||||
}
|
||||
@@ -639,7 +678,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
|
||||
private fun makeLeavesGetters(currentGetter: IrSimpleFunction): List<IrSimpleFunction>? =
|
||||
when (val node = regularClassMFVCPropertyNodes[currentGetter]) {
|
||||
null -> null
|
||||
is MultiFieldValueClassTree.Leaf<Unit> -> listOf(currentGetter)
|
||||
is Leaf -> listOf(currentGetter)
|
||||
is InternalNode -> node.fields.flatMap { makeLeavesGetters(regularClassMFVCPropertyNextGetters[currentGetter]!![it.name]!!)!! }
|
||||
}
|
||||
|
||||
@@ -655,7 +694,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
|
||||
val newArguments: List<IrExpression?> =
|
||||
makeNewArguments(parameter2expression.map { (_, argument) -> argument }, structure.map { it.valueParameters })
|
||||
+irCall(replacement.symbol).apply {
|
||||
copyTypeArgumentsFrom(original)
|
||||
passTypeArgumentsWithOffsets(replacement, originalFunction) { original.getTypeArgument(it)!! }
|
||||
for ((parameter, argument) in replacement.explicitParameters zip newArguments) {
|
||||
if (argument == null) continue
|
||||
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 {
|
||||
it.name.asString() == "toString" && it.valueParameters.isEmpty()
|
||||
}
|
||||
require(toString.typeParameters.isEmpty()) { "Bad toString: ${toString.render()}" }
|
||||
irCall(toString).apply {
|
||||
dispatchReceiver = argument
|
||||
}
|
||||
@@ -760,6 +800,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
|
||||
?: return super.visitGetField(expression)
|
||||
with(context.createIrBuilder(expression.symbol)) {
|
||||
irCall(getter).apply {
|
||||
require(getter.typeParameters.isEmpty()) { "Getter with type parameters: ${getter.render()}" }
|
||||
dispatchReceiver = expression.receiver!!.transform(this@JvmMultiFieldValueClassLowering, null)
|
||||
}
|
||||
}
|
||||
@@ -807,7 +848,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
|
||||
}
|
||||
)
|
||||
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 ->
|
||||
Pair<ExpressionGenerator<Unit>, ExpressionSupplier<Unit>>(
|
||||
Pair<ExpressionGenerator, ExpressionSupplier>(
|
||||
{ irGet(variable) },
|
||||
{ _, value: IrExpression -> irSet(variable, value) }
|
||||
{ value: IrExpression -> irSet(variable, value) }
|
||||
)
|
||||
}
|
||||
|
||||
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 resultReceiver =
|
||||
@@ -850,7 +891,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
|
||||
else initialGetReceiver
|
||||
irGetField(resultReceiver, field)
|
||||
},
|
||||
{ _, value: IrExpression ->
|
||||
{ value: IrExpression ->
|
||||
val initialGetReceiver = irGet(receiver)
|
||||
val resultReceiver =
|
||||
if (transformReceiver) initialGetReceiver.transform(this@JvmMultiFieldValueClassLowering, null)
|
||||
@@ -882,7 +923,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
|
||||
}
|
||||
|
||||
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 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) {
|
||||
require(variables.size == 1)
|
||||
+variables.single().second(this, Unit, expression.transform(this@JvmMultiFieldValueClassLowering, null))
|
||||
+variables.single().second(this, expression.transform(this@JvmMultiFieldValueClassLowering, null))
|
||||
return
|
||||
}
|
||||
require(variables.size == declarations.leaves.size)
|
||||
@@ -907,22 +948,23 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
|
||||
for ((treeField, argument) in root.fields zip oldArguments) {
|
||||
val size = when (treeField.node) {
|
||||
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 }
|
||||
argument?.let { flattenExpressionTo(it, subVariables) }
|
||||
}
|
||||
+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
|
||||
}
|
||||
}
|
||||
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)
|
||||
for ((variable, subExpression) in variables zip it) {
|
||||
+variable.second(this, Unit, subExpression)
|
||||
+variable.second(this, subExpression)
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -936,7 +978,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
|
||||
transformedExpression.getValueArgument(it)
|
||||
}) {
|
||||
if (argument != null) {
|
||||
+variable.second(this, Unit, argument)
|
||||
+variable.second(this, argument)
|
||||
}
|
||||
}
|
||||
return
|
||||
@@ -946,7 +988,8 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
|
||||
val receiver = irTemporary(transformedExpression.dispatchReceiver)
|
||||
require(getters.size == variables.size) { "Number of getters must be equal to number of variables" }
|
||||
for ((variable, getter) in variables zip getters) {
|
||||
+variable.second(this, Unit, irCall(getter).apply { dispatchReceiver = irGet(receiver) })
|
||||
require(getter.typeParameters.isEmpty()) { "Getter with type parameters: ${getter.render()}" }
|
||||
+variable.second(this, irCall(getter).apply { dispatchReceiver = irGet(receiver) })
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -960,7 +1003,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
|
||||
}
|
||||
val boxed = irTemporary(transformedExpression)
|
||||
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) })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -43,7 +43,7 @@ internal abstract class JvmValueClassAbstractLowering(val context: JvmBackendCon
|
||||
}
|
||||
|
||||
val replacement = replacements.getReplacementFunction(function)
|
||||
|
||||
|
||||
if (replacement == null) {
|
||||
if (function is IrConstructor) {
|
||||
val constructorReplacement = replacements.getReplacementRegularClassConstructor(function)
|
||||
|
||||
+41
-25
@@ -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.copyTypeParametersFrom
|
||||
import org.jetbrains.kotlin.backend.jvm.MemoizedMultiFieldValueClassReplacements.RemappedParameter.MultiFieldValueClassMapping
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.*
|
||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.buildConstructor
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
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.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.IrTypeSystemContext
|
||||
import org.jetbrains.kotlin.ir.types.isNullable
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.storage.LockBasedStorageManager
|
||||
@@ -89,20 +89,23 @@ class MemoizedMultiFieldValueClassReplacements(
|
||||
.flatMap { it.valueParameters }.mapIndexed { index: Int, template -> template.toParameter(this, index) }
|
||||
|
||||
private fun List<ValueParameterTemplate>.grouped(
|
||||
substitutionMap: Map<IrTypeParameterSymbol, IrType>,
|
||||
originWhenFlattenedAndNotSpecified: IrDeclarationOrigin? = IrDeclarationOrigin.GENERATED_MULTI_FIELD_VALUE_CLASS_PARAMETER
|
||||
): List<RemappedParameter> = map { parameter ->
|
||||
val declarations = parameter.type.takeIf { !it.isNullable() }?.erasedUpperBound?.let { getDeclarations(it) }
|
||||
?: return@map RemappedParameter.RegularMapping(parameter)
|
||||
require(!parameter.original.hasDefaultValue()) { "Default parameters values are not supported for multi-field value classes" }
|
||||
RemappedParameter.MultiFieldValueClassMapping(declarations, declarations.leaves.map { leaf ->
|
||||
ValueParameterTemplate(
|
||||
name = "${parameter.name}$${declarations.nodeFullNames[leaf]!!}",
|
||||
type = leaf.type,
|
||||
origin = parameter.origin ?: originWhenFlattenedAndNotSpecified,
|
||||
defaultValue = null,
|
||||
original = parameter.original,
|
||||
)
|
||||
})
|
||||
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(
|
||||
name = "${parameter.name}$${declarations.nodeFullNames[leaf]!!}",
|
||||
type = leaf.type.substitute(localSubstitutionMap),
|
||||
origin = parameter.origin ?: originWhenFlattenedAndNotSpecified,
|
||||
defaultValue = null,
|
||||
original = parameter.original,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
private fun buildReplacement(
|
||||
@@ -122,7 +125,7 @@ class MemoizedMultiFieldValueClassReplacements(
|
||||
}
|
||||
|
||||
private fun makeGroupedValueParametersFrom(
|
||||
function: IrFunction, includeDispatcherReceiver: Boolean
|
||||
function: IrFunction, includeDispatcherReceiver: Boolean, substitutionMap: Map<IrTypeParameterSymbol, IrType>
|
||||
): List<RemappedParameter> {
|
||||
val newFlattenedParameters = mutableListOf<RemappedParameter>()
|
||||
if (function.dispatchReceiverParameter != null && includeDispatcherReceiver) {
|
||||
@@ -133,7 +136,7 @@ class MemoizedMultiFieldValueClassReplacements(
|
||||
defaultValue = null,
|
||||
original = function.parentAsClass.thisReceiver!!,
|
||||
)
|
||||
newFlattenedParameters.addAll(listOf(template).grouped())
|
||||
newFlattenedParameters.addAll(listOf(template).grouped(substitutionMap))
|
||||
}
|
||||
val contextReceivers = function.valueParameters.take(function.contextReceiverParametersCount)
|
||||
.mapIndexed { index: Int, valueParameter: IrValueParameter ->
|
||||
@@ -145,7 +148,7 @@ class MemoizedMultiFieldValueClassReplacements(
|
||||
original = valueParameter,
|
||||
)
|
||||
}
|
||||
.grouped()
|
||||
.grouped(substitutionMap)
|
||||
newFlattenedParameters.addAll(contextReceivers)
|
||||
function.extensionReceiverParameter?.let {
|
||||
val template = ValueParameterTemplate(
|
||||
@@ -155,11 +158,11 @@ class MemoizedMultiFieldValueClassReplacements(
|
||||
defaultValue = it.defaultValue,
|
||||
original = it,
|
||||
)
|
||||
newFlattenedParameters.addAll(listOf(template).grouped())
|
||||
newFlattenedParameters.addAll(listOf(template).grouped(substitutionMap))
|
||||
}
|
||||
newFlattenedParameters += function.valueParameters.drop(function.contextReceiverParametersCount).map {
|
||||
ValueParameterTemplate(it, origin = null)
|
||||
}.grouped()
|
||||
}.grouped(substitutionMap)
|
||||
return newFlattenedParameters
|
||||
}
|
||||
|
||||
@@ -170,6 +173,7 @@ class MemoizedMultiFieldValueClassReplacements(
|
||||
|
||||
data class MultiFieldValueClassMapping(
|
||||
val declarations: MultiFieldValueClassSpecificDeclarations,
|
||||
val boxedType: IrSimpleType,
|
||||
override val valueParameters: List<ValueParameterTemplate>,
|
||||
) : RemappedParameter() {
|
||||
init {
|
||||
@@ -181,41 +185,53 @@ class MemoizedMultiFieldValueClassReplacements(
|
||||
}
|
||||
|
||||
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 =
|
||||
buildReplacement(function, JvmLoweredDeclarationOrigin.STATIC_MULTI_FIELD_VALUE_CLASS_REPLACEMENT, noFakeOverride = true) {
|
||||
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
|
||||
bindingNewFunctionToParameterTemplateStructure[this] = newFlattenedParameters
|
||||
valueParameters = makeValueParametersFromTemplate(newFlattenedParameters)
|
||||
}
|
||||
|
||||
override fun createMethodReplacement(function: IrFunction): IrSimpleFunction = buildReplacement(function, function.origin) {
|
||||
originalFunctionForMethodReplacement[this] = function
|
||||
dispatchReceiverParameter = function.dispatchReceiverParameter?.copyTo(this, index = -1)
|
||||
val newFlattenedParameters = makeGroupedValueParametersFrom(function, includeDispatcherReceiver = false)
|
||||
val newFlattenedParameters = makeGroupedValueParametersFrom(function, includeDispatcherReceiver = false, mapOf())
|
||||
val receiver = dispatchReceiverParameter
|
||||
val receiverTemplate = if (receiver != null) ValueParameterTemplate(receiver, origin = receiver.origin) else null
|
||||
val remappedParameters =
|
||||
if (receiverTemplate != null) listOf(RemappedParameter.RegularMapping(receiverTemplate)) + newFlattenedParameters else newFlattenedParameters
|
||||
valueParameters = makeValueParametersFromTemplate(newFlattenedParameters)
|
||||
bindingOldFunctionToParameterTemplateStructure[function] = remappedParameters
|
||||
bindingNewFunctionToParameterTemplateStructure[this] = remappedParameters
|
||||
valueParameters = makeValueParametersFromTemplate(newFlattenedParameters)
|
||||
}
|
||||
|
||||
private fun createConstructorReplacement(@Suppress("UNUSED_PARAMETER") constructor: IrConstructor): IrConstructor {
|
||||
val newFlattenedParameters = makeGroupedValueParametersFrom(constructor, includeDispatcherReceiver = false)
|
||||
val newFlattenedParameters = makeGroupedValueParametersFrom(constructor, includeDispatcherReceiver = false, mapOf())
|
||||
bindingOldFunctionToParameterTemplateStructure[constructor] = newFlattenedParameters
|
||||
val newConstructor = irFactory.buildConstructor {
|
||||
updateFrom(constructor)
|
||||
returnType = constructor.returnType
|
||||
}.apply {
|
||||
parent = constructor.parent
|
||||
copyTypeParametersFrom(constructor)
|
||||
valueParameters = makeValueParametersFromTemplate(newFlattenedParameters)
|
||||
annotations = constructor.annotations
|
||||
parent = constructor.parent
|
||||
originalConstructorForConstructorReplacement[this] = constructor
|
||||
}
|
||||
bindingNewFunctionToParameterTemplateStructure[newConstructor] = newFlattenedParameters
|
||||
|
||||
+213
-208
@@ -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.ir.erasedUpperBound
|
||||
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.descriptors.DescriptorVisibilities
|
||||
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.expressions.IrConstructorCall
|
||||
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.symbols.IrTypeParameterSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.IrTypeSystemContext
|
||||
import org.jetbrains.kotlin.ir.types.isNullable
|
||||
import org.jetbrains.kotlin.ir.types.isSubtypeOf
|
||||
import org.jetbrains.kotlin.ir.util.constructedClass
|
||||
import org.jetbrains.kotlin.ir.util.constructors
|
||||
import org.jetbrains.kotlin.ir.util.defaultType
|
||||
import org.jetbrains.kotlin.ir.util.primaryConstructor
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.renderer.render
|
||||
import org.jetbrains.kotlin.resolve.InlineClassDescriptorResolver
|
||||
|
||||
sealed class MultiFieldValueClassTree<out TI, out TL> {
|
||||
sealed class MultiFieldValueClassTree {
|
||||
abstract val type: IrType
|
||||
val irClass: IrClass
|
||||
get() = type.erasedUpperBound
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun <TI, TL> create(
|
||||
type: IrType,
|
||||
defaultInternalNodeValue: TI,
|
||||
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)
|
||||
fun create(type: IrSimpleType, replacements: MemoizedMultiFieldValueClassReplacements) =
|
||||
if (!type.isNullable() && type.isMultiFieldValueClassType()) InternalNode(type, DescriptorVisibilities.PUBLIC, replacements)
|
||||
else Leaf(type)
|
||||
}
|
||||
|
||||
class Leaf<out TL>(override val type: IrType, val leafValue: TL) : MultiFieldValueClassTree<Nothing, TL>() {
|
||||
class Leaf(override val type: IrType) : MultiFieldValueClassTree() {
|
||||
init {
|
||||
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(
|
||||
override val type: IrType, val internalNodeValue: TI, val fields: List<TreeField<TI, TL>>
|
||||
) : MultiFieldValueClassTree<TI, TL>() {
|
||||
class InternalNode internal constructor(
|
||||
override val type: IrSimpleType, val fields: List<TreeField>
|
||||
) : MultiFieldValueClassTree() {
|
||||
constructor(
|
||||
type: IrType, defaultInternalNodeValue: TI, visibility: DescriptorVisibility, defaultLeafValue: TL,
|
||||
type: IrSimpleType, visibility: DescriptorVisibility,
|
||||
replacements: MemoizedMultiFieldValueClassReplacements
|
||||
) : this(type, defaultInternalNodeValue, 0.let {
|
||||
) : this(type, 0.let {
|
||||
val valueClassRepresentation = type.erasedUpperBound.valueClassRepresentation as MultiFieldValueClassRepresentation
|
||||
val primaryConstructor = type.erasedUpperBound.primaryConstructor!!
|
||||
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 innerVisibility = property.visibility
|
||||
val comparison = visibility.compareTo(innerVisibility)
|
||||
?: error("Expected comparable visibilities but got $visibility and $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 node: MultiFieldValueClassTree<TI, TL>
|
||||
val node: MultiFieldValueClassTree
|
||||
) {
|
||||
constructor(
|
||||
name: Name,
|
||||
type: IrType,
|
||||
internalNodeValue: TI,
|
||||
type: IrSimpleType,
|
||||
visibility: DescriptorVisibility,
|
||||
annotations: List<IrConstructorCall>,
|
||||
defaultLeafValue: TL,
|
||||
replacements: MemoizedMultiFieldValueClassReplacements
|
||||
) : this(name, type, visibility, annotations, create(type, internalNodeValue, defaultLeafValue, 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))
|
||||
) : this(name, type, visibility, annotations, create(type, replacements))
|
||||
}
|
||||
|
||||
// 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 }
|
||||
|
||||
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 visitLeaf(treeNode: Leaf<TL>): T
|
||||
fun visitInternalNode(treeNode: InternalNode<TI, TL>): T
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
fun MultiFieldValueClassTree.render(): String = type.render() + when (this) {
|
||||
is InternalNode -> "\n" + fields.joinToString("\n") { "${it.name.render()}: ${it.node.render().prependIndent(" ")}" }
|
||||
is Leaf -> ""
|
||||
}
|
||||
|
||||
class MultiFieldValueClassSpecificDeclarations(
|
||||
@@ -162,39 +128,39 @@ class MultiFieldValueClassSpecificDeclarations(
|
||||
|
||||
val loweringRepresentation = MultiFieldValueClassTree.create(valueClass.defaultType, replacements) as InternalNode
|
||||
|
||||
val leaves: List<Leaf<Unit>> = ArrayList<Leaf<Unit>>().apply {
|
||||
loweringRepresentation.visit(object : MultiFieldValueClassTree.Visitor<Unit, Unit, Unit> {
|
||||
override fun visitLeaf(treeNode: Leaf<Unit>) {
|
||||
add(treeNode)
|
||||
val leaves: List<Leaf> = ArrayList<Leaf>().apply {
|
||||
fun proceed(node: MultiFieldValueClassTree) {
|
||||
when (node) {
|
||||
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>) {
|
||||
treeNode.fields.forEach { it.node.visit(this) }
|
||||
val nodeFullNames: Map<MultiFieldValueClassTree, Name> =
|
||||
mutableMapOf<MultiFieldValueClassTree, Name>().apply {
|
||||
val parts = mutableListOf<String>()
|
||||
fun makeName() = Name.guessByFirstCharacter(parts.joinToString("$"))
|
||||
fun proceed(node: MultiFieldValueClassTree) {
|
||||
when (node) {
|
||||
is InternalNode -> {
|
||||
if (parts.isNotEmpty()) {
|
||||
put(node, makeName())
|
||||
}
|
||||
for (field in node.fields) {
|
||||
parts.add(field.name.asString())
|
||||
proceed(field.node)
|
||||
parts.removeLast()
|
||||
}
|
||||
}
|
||||
is Leaf -> put(node, makeName())
|
||||
}
|
||||
}
|
||||
})
|
||||
}.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>()
|
||||
override fun visitLeaf(treeNode: Leaf<Unit>) {
|
||||
put(treeNode, makeName())
|
||||
}
|
||||
|
||||
override fun visitInternalNode(treeNode: InternalNode<Unit, Unit>) {
|
||||
if (parts.isNotEmpty()) {
|
||||
put(treeNode, makeName())
|
||||
}
|
||||
for (field in treeNode.fields) {
|
||||
parts.add(field.name.asString())
|
||||
field.node.visit(this)
|
||||
parts.removeLast()
|
||||
}
|
||||
}
|
||||
|
||||
private fun makeName() = Name.guessByFirstCharacter(parts.joinToString("$"))
|
||||
})
|
||||
proceed(loweringRepresentation)
|
||||
}
|
||||
|
||||
init {
|
||||
@@ -202,24 +168,24 @@ class MultiFieldValueClassSpecificDeclarations(
|
||||
}
|
||||
|
||||
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
|
||||
loweringRepresentation.visit(object : MultiFieldValueClassTree.Visitor<Unit, Unit, Unit> {
|
||||
override fun visitLeaf(treeNode: Leaf<Unit>) {
|
||||
index++
|
||||
}
|
||||
|
||||
override fun visitInternalNode(treeNode: InternalNode<Unit, Unit>) {
|
||||
val start = index
|
||||
treeNode.fields.forEach { it.node.visit(this) }
|
||||
val finish = index
|
||||
val range = start until finish
|
||||
if (finish - start <= 1) {
|
||||
error("Invalid multi-field value class indexes range for class $valueClass: ${range}")
|
||||
fun proceed(node: MultiFieldValueClassTree) {
|
||||
when (node) {
|
||||
is InternalNode -> {
|
||||
val start = index
|
||||
node.fields.forEach { proceed(it.node) }
|
||||
val finish = index
|
||||
val range = start until finish
|
||||
if (finish - start <= 1) {
|
||||
error("Invalid multi-field value class indexes range for class $valueClass: ${range}")
|
||||
}
|
||||
put(node, range)
|
||||
}
|
||||
put(treeNode, range)
|
||||
is Leaf -> index++
|
||||
}
|
||||
})
|
||||
}
|
||||
proceed(loweringRepresentation)
|
||||
}
|
||||
|
||||
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 {
|
||||
loweringRepresentation.visit(object : MultiFieldValueClassTree.Visitor<Unit, Unit, Unit> {
|
||||
val stack = mutableListOf<DescriptorVisibility>()
|
||||
override fun visitLeaf(treeNode: Leaf<Unit>) {
|
||||
put(treeNode, stack.last())
|
||||
}
|
||||
|
||||
override fun visitInternalNode(treeNode: InternalNode<Unit, Unit>) {
|
||||
if (stack.isNotEmpty()) {
|
||||
put(treeNode, stack.last())
|
||||
}
|
||||
for (field in treeNode.fields) {
|
||||
stack.add(field.visibility)
|
||||
field.node.visit(this)
|
||||
stack.pop()
|
||||
private val gettersVisibilities = mutableMapOf<MultiFieldValueClassTree, DescriptorVisibility>().apply {
|
||||
val stack = mutableListOf<DescriptorVisibility>()
|
||||
fun proceed(node: MultiFieldValueClassTree) {
|
||||
when (node) {
|
||||
is InternalNode -> {
|
||||
if (stack.isNotEmpty()) {
|
||||
put(node, stack.last())
|
||||
}
|
||||
for (field in node.fields) {
|
||||
stack.add(field.visibility)
|
||||
proceed(field.node)
|
||||
stack.pop()
|
||||
}
|
||||
}
|
||||
is Leaf -> put(node, stack.last())
|
||||
}
|
||||
})
|
||||
}
|
||||
proceed(loweringRepresentation)
|
||||
}
|
||||
|
||||
private val gettersAnnotations = mutableMapOf<MultiFieldValueClassTree<Unit, Unit>, List<IrConstructorCall>>().apply {
|
||||
loweringRepresentation.visit(object : MultiFieldValueClassTree.Visitor<Unit, Unit, Unit> {
|
||||
val stack = mutableListOf<List<IrConstructorCall>>()
|
||||
override fun visitLeaf(treeNode: Leaf<Unit>) {
|
||||
put(treeNode, stack.last())
|
||||
}
|
||||
private val gettersAnnotations = mutableMapOf<MultiFieldValueClassTree, List<IrConstructorCall>>().apply {
|
||||
val stack = mutableListOf<List<IrConstructorCall>>()
|
||||
|
||||
override fun visitInternalNode(treeNode: InternalNode<Unit, Unit>) {
|
||||
if (stack.isNotEmpty()) {
|
||||
put(treeNode, stack.last())
|
||||
}
|
||||
for (field in treeNode.fields) {
|
||||
stack.add(field.annotations)
|
||||
field.node.visit(this)
|
||||
stack.pop()
|
||||
fun proceed(node: MultiFieldValueClassTree) {
|
||||
when (node) {
|
||||
is InternalNode -> {
|
||||
if (stack.isNotEmpty()) {
|
||||
put(node, stack.last())
|
||||
}
|
||||
for (field in node.fields) {
|
||||
stack.add(field.annotations)
|
||||
proceed(field.node)
|
||||
stack.pop()
|
||||
}
|
||||
}
|
||||
is Leaf -> put(node, stack.last())
|
||||
}
|
||||
})
|
||||
}
|
||||
proceed(loweringRepresentation)
|
||||
}
|
||||
|
||||
private fun IrBuilderWithScope.fieldGetter(receiver: IrValueParameter, field: IrField): IrGetField =
|
||||
irGetField(irGet(receiver), 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,
|
||||
)
|
||||
}
|
||||
)
|
||||
private fun IrFunction.fieldGetter(field: IrField): IrBuilderWithScope.() -> IrGetField =
|
||||
{ fieldGetter(dispatchReceiverParameter!!, field) }
|
||||
|
||||
val primaryConstructor: IrConstructor = irFactory.buildConstructor {
|
||||
updateFrom(oldPrimaryConstructor)
|
||||
@@ -298,8 +255,10 @@ class MultiFieldValueClassSpecificDeclarations(
|
||||
origin = JvmLoweredDeclarationOrigin.SYNTHETIC_MULTI_FIELD_VALUE_CLASS_MEMBER
|
||||
returnType = oldPrimaryConstructor.returnType
|
||||
}.apply {
|
||||
copyTypeParametersFrom(oldPrimaryConstructor)
|
||||
addFlattenedClassRepresentationToParameters()
|
||||
require(oldPrimaryConstructor.typeParameters.isEmpty()) {
|
||||
"Constructors do not support type parameters yet"
|
||||
}
|
||||
addFlattenedClassRepresentationToParameters(mapOf())
|
||||
val irConstructor = this@apply
|
||||
parent = valueClass
|
||||
body = context.createIrBuilder(irConstructor.symbol).irBlockBody(irConstructor) {
|
||||
@@ -322,11 +281,14 @@ class MultiFieldValueClassSpecificDeclarations(
|
||||
modality = Modality.FINAL
|
||||
}.apply {
|
||||
parent = valueClass
|
||||
copyTypeParametersFrom(oldPrimaryConstructor)
|
||||
addFlattenedClassRepresentationToParameters()
|
||||
copyTypeParametersFrom(valueClass)
|
||||
addFlattenedClassRepresentationToParameters(classToFunctionTypeParametersMapping())
|
||||
// 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 {
|
||||
name = Name.identifier(KotlinTypeMapper.BOX_JVM_METHOD_NAME)
|
||||
origin = JvmLoweredDeclarationOrigin.SYNTHETIC_MULTI_FIELD_VALUE_CLASS_MEMBER
|
||||
@@ -334,33 +296,46 @@ class MultiFieldValueClassSpecificDeclarations(
|
||||
}.apply {
|
||||
parent = valueClass
|
||||
copyTypeParametersFrom(valueClass)
|
||||
addFlattenedClassRepresentationToParameters()
|
||||
addFlattenedClassRepresentationToParameters(classToFunctionTypeParametersMapping())
|
||||
// body is added in Lowering file
|
||||
}
|
||||
|
||||
private fun IrFunction.addFlattenedClassRepresentationToParameters() {
|
||||
private fun IrFunction.addFlattenedClassRepresentationToParameters(substitutionMap: Map<IrTypeParameterSymbol, IrType>) {
|
||||
for (leaf in leaves) {
|
||||
addValueParameter {
|
||||
this.name = nodeFullNames[leaf]!!
|
||||
this.type = leaf.type
|
||||
this.type = leaf.type.substitute(substitutionMap)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val specializedEqualsMethod = irFactory.buildFun {
|
||||
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
|
||||
returnType = context.irBuiltIns.booleanType
|
||||
}.apply {
|
||||
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) {
|
||||
addValueParameter {
|
||||
this.name = Name.guessByFirstCharacter(
|
||||
"${InlineClassDescriptorResolver.SPECIALIZED_EQUALS_FIRST_PARAMETER_NAME}$${nodeFullNames[leaf]!!.asString()}"
|
||||
)
|
||||
this.type = leaf.type
|
||||
this.type = leaf.type.substitute(substitutionMapHalf1)
|
||||
}
|
||||
}
|
||||
for (leaf in leaves) {
|
||||
@@ -368,7 +343,7 @@ class MultiFieldValueClassSpecificDeclarations(
|
||||
this.name = Name.guessByFirstCharacter(
|
||||
"${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
|
||||
@@ -388,9 +363,10 @@ class MultiFieldValueClassSpecificDeclarations(
|
||||
}
|
||||
}
|
||||
|
||||
val properties: Map<MultiFieldValueClassTree<Unit, Unit>, IrProperty> =
|
||||
selfImplementationAgnosticDeclarations.nodeToExpressionGetters.filterKeys { it in nodeFullNames }.mapValues { (node, getter) ->
|
||||
val propertyName = nodeFullNames[node]!!
|
||||
val properties: Map<MultiFieldValueClassTree, IrProperty> = run {
|
||||
val nodes2expressions: Map<MultiFieldValueClassTree, IrBuilderWithScope.(function: IrFunction) -> IrExpression> =
|
||||
makeNodes2FieldExpressions(fields)
|
||||
nodeFullNames.mapValues { (node, propertyName) ->
|
||||
val overrideable = oldProperties[propertyName]
|
||||
irFactory.buildProperty {
|
||||
name = propertyName
|
||||
@@ -404,42 +380,75 @@ class MultiFieldValueClassSpecificDeclarations(
|
||||
returnType = node.type
|
||||
origin = IrDeclarationOrigin.GENERATED_MULTI_FIELD_VALUE_CLASS_MEMBER
|
||||
}.apply {
|
||||
val function = this
|
||||
overrideable?.getter?.overriddenSymbols?.let { overriddenSymbols = it }
|
||||
createDispatchReceiverParameter()
|
||||
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 makeGetter: ExpressionGenerator<T>,
|
||||
val assigner: ExpressionSupplier<T>?,
|
||||
val makeGetter: ExpressionGenerator,
|
||||
val assigner: ExpressionSupplier?,
|
||||
val symbol: IrValueSymbol?
|
||||
) {
|
||||
constructor(declaration: IrValueDeclaration) : this(
|
||||
declaration.type,
|
||||
{ irGet(declaration) },
|
||||
if (declaration.isAssignable) { _, value -> irSet(declaration, value) } else null,
|
||||
if (declaration.isAssignable) { value -> irSet(declaration, value) } else null,
|
||||
declaration.symbol,
|
||||
)
|
||||
|
||||
val isAssignable: Boolean
|
||||
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:
|
||||
* 1. A slice of fields in another multi-field class instance;
|
||||
@@ -449,28 +458,31 @@ class MultiFieldValueClassSpecificDeclarations(
|
||||
* 5. Virtual instance constructed with local fields;
|
||||
* 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 symbols = virtualFields.map { it.symbol }
|
||||
|
||||
fun <R> map(f: (R) -> T) = ImplementationAgnostic(virtualFields.map { it.map(f) })
|
||||
private val substitutionMap = valueClass.typeParameters.map { it.symbol }.zip(type.arguments.map { it.typeOrNull })
|
||||
.mapNotNull { (parameter, type) -> if (type != null) parameter to type else null }.toMap()
|
||||
|
||||
init {
|
||||
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 }) {
|
||||
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) } +
|
||||
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) ->
|
||||
{ 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)!!
|
||||
irCall(innerDeclarations.boxMethod).apply {
|
||||
copyTypeArgumentsFromType(node.type, node.irClass, substitutionMap)
|
||||
for (i in arguments.indices) {
|
||||
putValueArgument(i, arguments[i])
|
||||
}
|
||||
@@ -478,13 +490,13 @@ class MultiFieldValueClassSpecificDeclarations(
|
||||
}
|
||||
}
|
||||
|
||||
private val leavesToExpressionGetters: Map<Leaf<Unit>, ExpressionGenerator<T>> =
|
||||
indexByLeaf.mapValues { (_, index) -> { virtualFields[index].makeGetter(this, it) } }
|
||||
private val leavesToExpressionGetters: Map<Leaf, ExpressionGenerator> =
|
||||
indexByLeaf.mapValues { (_, index) -> { virtualFields[index].makeGetter(this) } }
|
||||
|
||||
val nodeToExpressionGetters: Map<MultiFieldValueClassTree<Unit, Unit>, ExpressionGenerator<T>> =
|
||||
val nodeToExpressionGetters: Map<MultiFieldValueClassTree, ExpressionGenerator> =
|
||||
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]) {
|
||||
null -> null
|
||||
else -> nodeToExpressionGetters[field.node]!! to when (field.node) {
|
||||
@@ -492,24 +504,17 @@ class MultiFieldValueClassSpecificDeclarations(
|
||||
is InternalNode -> {
|
||||
val irClass = field.node.irClass
|
||||
val declarations = replacements.getDeclarations(irClass)!!
|
||||
declarations.ImplementationAgnostic(nodeToSymbols[field.node]!!)
|
||||
declarations.ImplementationAgnostic(field.type as IrSimpleType, nodeToSymbols[field.node]!!)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val boxedExpression = nodeToExpressionGetters[loweringRepresentation]!!
|
||||
|
||||
// todo type parameters
|
||||
// todo recursive
|
||||
// todo cheeeck!!!
|
||||
// todo equals
|
||||
// todo toString
|
||||
// todo hashCode
|
||||
// todo default parameters
|
||||
// todo annotations etc.
|
||||
// todo inline in not value class
|
||||
}
|
||||
}
|
||||
|
||||
typealias ExpressionGenerator<T> = IrBuilderWithScope.(T) -> IrExpression
|
||||
typealias ExpressionSupplier<T> = IrBuilderWithScope.(T, IrExpression) -> IrStatement
|
||||
typealias ExpressionGenerator = IrBuilderWithScope.() -> IrExpression
|
||||
typealias ExpressionSupplier = IrBuilderWithScope.(IrExpression) -> IrStatement
|
||||
@@ -12,8 +12,23 @@ interface AbstractPoint<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
|
||||
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> {
|
||||
var p: T
|
||||
|
||||
@@ -2354,6 +2354,8 @@ public final class Overrides_typeParametersKt {
|
||||
inner (anonymous) class Overrides_typeParametersKt$box$xPointLam$1
|
||||
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 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
|
||||
@@ -2443,6 +2445,22 @@ public interface ReifiedMFVCHolderWithImpls {
|
||||
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
|
||||
public interface SomePointInterface {
|
||||
// source: 'overrides_typeParameters.kt'
|
||||
@@ -2481,6 +2499,10 @@ public final class XPoint {
|
||||
public final method getY(): java.lang.Object
|
||||
public method hashCode(): int
|
||||
public static method hashCode-impl(p0: java.lang.Object, p1: java.lang.Object): int
|
||||
public 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 static method toString-impl(p0: java.lang.Object, p1: java.lang.Object): java.lang.String
|
||||
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-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