Created a deep copier good for fake overrides.

Adapted it from inliner copier.
It is capable of producing type substituted members.
This commit is contained in:
Alexander Gorshenev
2020-05-12 13:26:47 +03:00
parent 63429c088f
commit 789efc7c3a
5 changed files with 200 additions and 11 deletions
@@ -21,7 +21,6 @@ import org.jetbrains.kotlin.ir.visitors.acceptVoid
import org.jetbrains.kotlin.name.Name
internal class DeepCopyIrTreeWithSymbolsForInliner(
val context: CommonBackendContext,
val typeArguments: Map<IrTypeParameterSymbol, IrType?>?,
val parent: IrDeclarationParent?
) {
@@ -120,7 +120,7 @@ class FunctionInlining(
(0 until callSite.typeArgumentsCount).map {
typeParameters[it].symbol to callSite.getTypeArgument(it)
}.associate { it }
DeepCopyIrTreeWithSymbolsForInliner(context, typeArguments, parent)
DeepCopyIrTreeWithSymbolsForInliner(typeArguments, parent)
}
val substituteMap = mutableMapOf<IrValueParameter, IrExpression>()
@@ -62,22 +62,22 @@ open class DeepCopyIrTreeWithSymbols(
}
}
private fun mapDeclarationOrigin(origin: IrDeclarationOrigin) = origin
private fun mapStatementOrigin(origin: IrStatementOrigin?) = origin
protected fun mapDeclarationOrigin(origin: IrDeclarationOrigin) = origin
protected fun mapStatementOrigin(origin: IrStatementOrigin?) = origin
private inline fun <reified T : IrElement> T.transform() =
protected inline fun <reified T : IrElement> T.transform() =
transform(this@DeepCopyIrTreeWithSymbols, null) as T
private inline fun <reified T : IrElement> List<T>.transform() =
protected inline fun <reified T : IrElement> List<T>.transform() =
map { it.transform() }
private inline fun <reified T : IrElement> List<T>.transformTo(destination: MutableList<T>) =
protected inline fun <reified T : IrElement> List<T>.transformTo(destination: MutableList<T>) =
mapTo(destination) { it.transform() }
private fun <T : IrDeclarationContainer> T.transformDeclarationsTo(destination: T) =
protected fun <T : IrDeclarationContainer> T.transformDeclarationsTo(destination: T) =
declarations.transformTo(destination.declarations)
private fun IrType.remapType() = typeRemapper.remapType(this)
protected fun IrType.remapType() = typeRemapper.remapType(this)
override fun visitElement(element: IrElement): IrElement =
throw IllegalArgumentException("Unsupported element type: $element")
@@ -201,7 +201,7 @@ open class DeepCopyIrTreeWithSymbols(
}
}
private fun IrMutableAnnotationContainer.transformAnnotations(declaration: IrAnnotationContainer) {
protected fun IrMutableAnnotationContainer.transformAnnotations(declaration: IrAnnotationContainer) {
annotations = declaration.annotations.transform()
}
@@ -322,7 +322,7 @@ open class DeepCopyIrTreeWithSymbols(
transformAnnotations(declaration)
}
private fun IrTypeParametersContainer.copyTypeParametersFrom(other: IrTypeParametersContainer) {
protected fun IrTypeParametersContainer.copyTypeParametersFrom(other: IrTypeParametersContainer) {
this.typeParameters = other.typeParameters.map {
copyTypeParameter(it)
}
@@ -0,0 +1,104 @@
package org.jetbrains.kotlin.backend.common.serialization
import org.jetbrains.kotlin.backend.common.DescriptorsToIrRemapper
import org.jetbrains.kotlin.backend.common.WrappedDescriptorPatcher
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrTypeParametersContainer
import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.types.impl.buildSimpleType
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.acceptVoid
// This is basicly modelled after the inliner copier.
class DeepCopyIrTreeWithSymbolsForFakeOverrides(
val typeArguments: Map<IrTypeParameterSymbol, IrType>,
val superType: IrType,
val parent: IrClass
) {
fun copy(irElement: IrElement): IrElement {
// Create new symbols.
irElement.acceptVoid(symbolRemapper)
// Make symbol remapper aware of the callsite's type arguments.
symbolRemapper.typeArguments = typeArguments
// Copy IR.
val result = irElement.transform(copier, data = null)
// Bind newly created IR with wrapped descriptors.
result.acceptVoid(WrappedDescriptorPatcher)
result.patchDeclarationParents(parent)
return result
}
private inner class FakeOverrideTypeRemapper(
val symbolRemapper: SymbolRemapper,
val typeArguments: Map<IrTypeParameterSymbol, IrType>
) : TypeRemapper {
override fun enterScope(irTypeParametersContainer: IrTypeParametersContainer) {}
override fun leaveScope() {}
private fun remapTypeArguments(arguments: List<IrTypeArgument>) =
arguments.map { argument ->
(argument as? IrTypeProjection)?.let { makeTypeProjection(remapType(it.type), it.variance) }
?: argument
}
override fun remapType(type: IrType): IrType {
if (type !is IrSimpleType) return type
val substitutedType = typeArguments[type.classifier]
if (substitutedType is IrDynamicType) return substitutedType
if (substitutedType is IrSimpleType) {
return substitutedType.buildSimpleType {
kotlinType = null
hasQuestionMark = type.hasQuestionMark or substitutedType.isMarkedNullable()
}
}
return type.buildSimpleType {
kotlinType = null
classifier = symbolRemapper.getReferencedClassifier(type.classifier)
arguments = remapTypeArguments(type.arguments)
annotations = type.annotations.map { it.transform(copier, null) as IrConstructorCall }
}
}
}
private class FakeOverrideSymbolRemapperImpl(descriptorsRemapper: DescriptorsRemapper) :
DeepCopySymbolRemapper(descriptorsRemapper) {
var typeArguments = mapOf<IrTypeParameterSymbol, IrType>()
set(value) {
field = value.asSequence().associate {
(getReferencedClassifier(it.key) as IrTypeParameterSymbol) to it.value
}
}
override fun getReferencedClassifier(symbol: IrClassifierSymbol): IrClassifierSymbol {
val result = super.getReferencedClassifier(symbol)
if (result !is IrTypeParameterSymbol)
return result
return typeArguments[result]?.classifierOrNull ?: result
}
}
private val symbolRemapper = FakeOverrideSymbolRemapperImpl(DescriptorsToIrRemapper)
private val copier =
FakeOverrideCopier(
symbolRemapper,
FakeOverrideTypeRemapper(symbolRemapper, typeArguments),
SymbolRenamer.DEFAULT
)
}
@@ -0,0 +1,86 @@
package org.jetbrains.kotlin.backend.common.serialization
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrProperty
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.declarations.impl.IrFakeOverrideFunctionImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrFakeOverridePropertyImpl
import org.jetbrains.kotlin.ir.util.*
class FakeOverrideCopier(
symbolRemapper: SymbolRemapper,
private val typeRemapper: TypeRemapper,
private val symbolRenamer: SymbolRenamer
) : DeepCopyIrTreeWithSymbols(symbolRemapper, typeRemapper, symbolRenamer) {
private fun <T : IrFunction> T.transformFunctionChildren(declaration: T): T =
apply {
transformAnnotations(declaration)
copyTypeParametersFrom(declaration)
typeRemapper.withinScope(this) {
// This is the more correct way to produce dispatch receiver for a fake override,
// but some lowerings still expect the below behavior as produced by the current psi2ir.
/*
val superDispatchReceiver = declaration.dispatchReceiverParameter!!
val dispatchReceiverSymbol = IrValueParameterSymbolImpl(WrappedReceiverParameterDescriptor())
val dispatchReceiverType = destinationClass.defaultType
dispatchReceiverParameter = IrValueParameterImpl(
superDispatchReceiver.startOffset,
superDispatchReceiver.endOffset,
superDispatchReceiver.origin,
dispatchReceiverSymbol,
superDispatchReceiver.name,
superDispatchReceiver.index,
dispatchReceiverType,
null,
superDispatchReceiver.isCrossinline,
superDispatchReceiver.isNoinline
)
*/
// Should fake override's receiver be the current class is an open question.
dispatchReceiverParameter = declaration.dispatchReceiverParameter?.transform()
extensionReceiverParameter = declaration.extensionReceiverParameter?.transform()
returnType = typeRemapper.remapType(declaration.returnType)
this.valueParameters = declaration.valueParameters.transform()
}
}
override fun visitSimpleFunction(declaration: IrSimpleFunction): IrSimpleFunction =
IrFakeOverrideFunctionImpl(
declaration.startOffset, declaration.endOffset,
IrDeclarationOrigin.FAKE_OVERRIDE,
symbolRenamer.getFunctionName(declaration.symbol),
declaration.visibility,
declaration.modality,
declaration.returnType,
isInline = declaration.isInline,
isExternal = false,
isTailrec = declaration.isTailrec,
isSuspend = declaration.isSuspend,
isExpect = declaration.isExpect,
isOperator = declaration.isOperator
).apply {
transformFunctionChildren(declaration)
}
override fun visitProperty(declaration: IrProperty): IrProperty =
IrFakeOverridePropertyImpl(
declaration.startOffset, declaration.endOffset,
IrDeclarationOrigin.FAKE_OVERRIDE,
declaration.name,
declaration.visibility,
declaration.modality,
isVar = declaration.isVar,
isConst = declaration.isConst,
isLateinit = declaration.isLateinit,
isDelegated = declaration.isDelegated,
isExpect = declaration.isExpect,
isExternal = false
).apply {
transformAnnotations(declaration)
this.getter = declaration.getter?.transform()
this.setter = declaration.setter?.transform()
}
}