Fixed bug with duplicate IR nodes
This commit is contained in:
+133
-120
@@ -17,6 +17,9 @@
|
|||||||
package org.jetbrains.kotlin.backend.konan.lower
|
package org.jetbrains.kotlin.backend.konan.lower
|
||||||
|
|
||||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||||
|
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
|
||||||
|
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||||
|
import org.jetbrains.kotlin.backend.common.lower.irBlock
|
||||||
import org.jetbrains.kotlin.backend.jvm.descriptors.initialize
|
import org.jetbrains.kotlin.backend.jvm.descriptors.initialize
|
||||||
import org.jetbrains.kotlin.backend.konan.Context
|
import org.jetbrains.kotlin.backend.konan.Context
|
||||||
import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName
|
import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName
|
||||||
@@ -29,31 +32,30 @@ import org.jetbrains.kotlin.ir.IrStatement
|
|||||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOriginImpl
|
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOriginImpl
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrLocalDelegatedProperty
|
import org.jetbrains.kotlin.ir.declarations.IrLocalDelegatedProperty
|
||||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl
|
import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl
|
||||||
import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
|
import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
|
||||||
import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl
|
|
||||||
import org.jetbrains.kotlin.ir.util.constructors
|
import org.jetbrains.kotlin.ir.util.constructors
|
||||||
import org.jetbrains.kotlin.ir.util.functions
|
import org.jetbrains.kotlin.ir.util.functions
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
|
||||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.ir.builders.*
|
||||||
import org.jetbrains.kotlin.types.*
|
import org.jetbrains.kotlin.types.*
|
||||||
|
|
||||||
internal class PropertyDelegationLowering(val context: Context) : FileLoweringPass {
|
internal class PropertyDelegationLowering(val context: Context) : FileLoweringPass {
|
||||||
val reflectionTypes = context.reflectionTypes
|
private val reflectionTypes = context.reflectionTypes
|
||||||
private val kotlinPackage = context.irModule!!.descriptor.getPackage(FqName("kotlin"))
|
private val kotlinPackage = context.irModule!!.descriptor.getPackage(FqName("kotlin"))
|
||||||
private val genericArrayType = kotlinPackage.memberScope.getContributedClassifier(Name.identifier("Array"), NoLookupLocation.FROM_BACKEND) as ClassDescriptor
|
private val genericArrayType = kotlinPackage.memberScope.getContributedClassifier(Name.identifier("Array"), NoLookupLocation.FROM_BACKEND) as ClassDescriptor
|
||||||
|
private var tempIndex = 0
|
||||||
|
|
||||||
private fun getKPropertyImplConstructor(receiverTypes: List<KotlinType>,
|
private fun getKPropertyImplConstructor(receiverTypes: List<KotlinType>,
|
||||||
returnType: KotlinType,
|
returnType: KotlinType,
|
||||||
isLocal: Boolean,
|
isLocal: Boolean,
|
||||||
isMutable: Boolean) : Pair<IrConstructorSymbol, ClassConstructorDescriptor> {
|
isMutable: Boolean) : Pair<IrConstructorSymbol, Map<TypeParameterDescriptor, KotlinType>> {
|
||||||
|
|
||||||
val symbols = context.ir.symbols
|
val symbols = context.ir.symbols
|
||||||
|
|
||||||
@@ -82,16 +84,12 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val classDescriptor = classSymbol.descriptor
|
val typeParameters = classSymbol.descriptor.declaredTypeParameters
|
||||||
|
|
||||||
val typeParameters = classDescriptor.declaredTypeParameters
|
|
||||||
val arguments = (receiverTypes + listOf(returnType))
|
val arguments = (receiverTypes + listOf(returnType))
|
||||||
.mapIndexed { index, type -> typeParameters[index].typeConstructor to TypeProjectionImpl(type) }
|
.mapIndexed { index, type -> typeParameters[index] to type }
|
||||||
.toMap()
|
.toMap()
|
||||||
|
|
||||||
val constructorSymbol = classSymbol.constructors.single()
|
return classSymbol.constructors.single() to arguments
|
||||||
|
|
||||||
return constructorSymbol to constructorSymbol.descriptor.substitute(TypeSubstitutor.create(arguments))!!
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ClassDescriptor.replace(vararg type: KotlinType): SimpleType {
|
private fun ClassDescriptor.replace(vararg type: KotlinType): SimpleType {
|
||||||
@@ -105,10 +103,7 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa
|
|||||||
|
|
||||||
val arrayItemGetter = arrayClass.functions.single { it.descriptor.name == Name.identifier("get") }
|
val arrayItemGetter = arrayClass.functions.single { it.descriptor.name == Name.identifier("get") }
|
||||||
|
|
||||||
val typeParameterT = genericArrayType.declaredTypeParameters[0]
|
|
||||||
val kPropertyImplType = reflectionTypes.kProperty1Impl.replace(context.builtIns.anyType, context.builtIns.anyType)
|
val kPropertyImplType = reflectionTypes.kProperty1Impl.replace(context.builtIns.anyType, context.builtIns.anyType)
|
||||||
val typeSubstitutor = TypeSubstitutor.create(mapOf(typeParameterT.typeConstructor to TypeProjectionImpl(kPropertyImplType)))
|
|
||||||
val substitutedArrayItemGetter = arrayItemGetter.descriptor.substitute(typeSubstitutor)!!
|
|
||||||
|
|
||||||
val kPropertiesField = IrFieldImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET,
|
val kPropertiesField = IrFieldImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET,
|
||||||
DECLARATION_ORIGIN_KPROPERTIES_FOR_DELEGATION,
|
DECLARATION_ORIGIN_KPROPERTIES_FOR_DELEGATION,
|
||||||
@@ -117,10 +112,7 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
irFile.transformChildrenVoid(object : IrElementTransformerVoid() {
|
irFile.transformChildrenVoid(object : IrElementTransformerVoidWithContext() {
|
||||||
override fun visitFunction(declaration: IrFunction): IrStatement {
|
|
||||||
return super.visitFunction(declaration)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitLocalDelegatedProperty(declaration: IrLocalDelegatedProperty): IrStatement {
|
override fun visitLocalDelegatedProperty(declaration: IrLocalDelegatedProperty): IrStatement {
|
||||||
declaration.transformChildrenVoid(this)
|
declaration.transformChildrenVoid(this)
|
||||||
@@ -141,53 +133,56 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa
|
|||||||
override fun visitPropertyReference(expression: IrPropertyReference): IrExpression {
|
override fun visitPropertyReference(expression: IrPropertyReference): IrExpression {
|
||||||
expression.transformChildrenVoid(this)
|
expression.transformChildrenVoid(this)
|
||||||
|
|
||||||
val receiversCount = listOf(expression.dispatchReceiver, expression.extensionReceiver).count { it != null }
|
val startOffset = expression.startOffset
|
||||||
if (receiversCount == 1) // Has receiver.
|
val endOffset = expression.endOffset
|
||||||
return createKProperty(expression)
|
val irBuilder = context.createIrBuilder(currentScope!!.scope.scopeOwnerSymbol, startOffset, endOffset)
|
||||||
else if (receiversCount == 2)
|
irBuilder.run {
|
||||||
throw AssertionError("Callable reference to properties with two receivers is not allowed: ${expression.descriptor}")
|
val receiversCount = listOf(expression.dispatchReceiver, expression.extensionReceiver).count { it != null }
|
||||||
else { // Cache KProperties with no arguments.
|
if (receiversCount == 1) // Has receiver.
|
||||||
val field = kProperties.getOrPut(expression.descriptor) {
|
return createKProperty(expression, this)
|
||||||
createKProperty(expression) to kProperties.size
|
else if (receiversCount == 2)
|
||||||
}
|
throw AssertionError("Callable reference to properties with two receivers is not allowed: ${expression.descriptor}")
|
||||||
|
else { // Cache KProperties with no arguments.
|
||||||
|
val field = kProperties.getOrPut(expression.descriptor) {
|
||||||
|
createKProperty(expression, this) to kProperties.size
|
||||||
|
}
|
||||||
|
|
||||||
return IrCallImpl(
|
return irCall(arrayItemGetter, typeArguments = listOf(kPropertyImplType)).apply {
|
||||||
expression.startOffset, expression.endOffset,
|
dispatchReceiver =
|
||||||
arrayItemGetter, substitutedArrayItemGetter
|
IrGetFieldImpl(expression.startOffset, expression.endOffset, kPropertiesField.symbol)
|
||||||
).apply {
|
|
||||||
dispatchReceiver =
|
|
||||||
IrGetFieldImpl(expression.startOffset, expression.endOffset, kPropertiesField.symbol)
|
|
||||||
|
|
||||||
putValueArgument(0, IrConstImpl.int(startOffset, endOffset, context.builtIns.intType, field.second))
|
putValueArgument(0, IrConstImpl.int(startOffset, endOffset, context.builtIns.intType, field.second))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitLocalDelegatedPropertyReference(expression: IrLocalDelegatedPropertyReference): IrExpression {
|
override fun visitLocalDelegatedPropertyReference(expression: IrLocalDelegatedPropertyReference): IrExpression {
|
||||||
expression.transformChildrenVoid(this)
|
expression.transformChildrenVoid(this)
|
||||||
val propertyDescriptor = expression.descriptor
|
|
||||||
|
|
||||||
val receiversCount = listOf(expression.dispatchReceiver, expression.extensionReceiver).count { it != null }
|
val startOffset = expression.startOffset
|
||||||
if (receiversCount == 2)
|
val endOffset = expression.endOffset
|
||||||
throw AssertionError("Callable reference to properties with two receivers is not allowed: $propertyDescriptor")
|
val irBuilder = context.createIrBuilder(currentScope!!.scope.scopeOwnerSymbol, startOffset, endOffset)
|
||||||
else { // Cache KProperties with no arguments.
|
irBuilder.run {
|
||||||
// TODO: what about `receiversCount == 1` case?
|
val propertyDescriptor = expression.descriptor
|
||||||
val field = kProperties.getOrPut(propertyDescriptor) {
|
|
||||||
createLocalKProperty(expression, propertyDescriptor) to kProperties.size
|
|
||||||
}
|
|
||||||
|
|
||||||
return IrCallImpl(
|
val receiversCount = listOf(expression.dispatchReceiver, expression.extensionReceiver).count { it != null }
|
||||||
expression.startOffset, expression.endOffset,
|
if (receiversCount == 2)
|
||||||
arrayItemGetter, substitutedArrayItemGetter
|
throw AssertionError("Callable reference to properties with two receivers is not allowed: $propertyDescriptor")
|
||||||
).apply {
|
else { // Cache KProperties with no arguments.
|
||||||
dispatchReceiver =
|
// TODO: what about `receiversCount == 1` case?
|
||||||
IrGetFieldImpl(expression.startOffset, expression.endOffset, kPropertiesField.symbol)
|
val field = kProperties.getOrPut(propertyDescriptor) {
|
||||||
|
createLocalKProperty(propertyDescriptor, this) to kProperties.size
|
||||||
|
}
|
||||||
|
|
||||||
putValueArgument(0, IrConstImpl.int(startOffset, endOffset, context.builtIns.intType, field.second))
|
return irCall(arrayItemGetter, typeArguments = listOf(kPropertyImplType)).apply {
|
||||||
|
dispatchReceiver =
|
||||||
|
IrGetFieldImpl(expression.startOffset, expression.endOffset, kPropertiesField.symbol)
|
||||||
|
|
||||||
|
putValueArgument(0, IrConstImpl.int(startOffset, endOffset, context.builtIns.intType, field.second))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -201,88 +196,106 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createKProperty(expression: IrPropertyReference): IrCallImpl {
|
private fun createKProperty(expression: IrPropertyReference, irBuilder: IrBuilderWithScope): IrExpression {
|
||||||
val startOffset = expression.startOffset
|
val startOffset = expression.startOffset
|
||||||
val endOffset = expression.endOffset
|
val endOffset = expression.endOffset
|
||||||
val receiverTypes = mutableListOf<KotlinType>()
|
return irBuilder.irBlock(expression) {
|
||||||
|
val receiverTypes = mutableListOf<KotlinType>()
|
||||||
val propertyDescriptor = expression.descriptor
|
val dispatchReceiver = expression.dispatchReceiver.let {
|
||||||
|
if (it == null)
|
||||||
val returnType = propertyDescriptor.type
|
null
|
||||||
val getterCallableReference = propertyDescriptor.getter?.let { getter ->
|
else
|
||||||
getter.extensionReceiverParameter.let {
|
irTemporary(value = it, nameHint = "\$dispatchReceiver${tempIndex++}").symbol
|
||||||
if (it != null && expression.extensionReceiver == null)
|
|
||||||
receiverTypes.add(it.type)
|
|
||||||
}
|
}
|
||||||
getter.dispatchReceiverParameter.let {
|
val extensionReceiver = expression.extensionReceiver.let {
|
||||||
if (it != null && expression.dispatchReceiver == null)
|
if (it == null)
|
||||||
receiverTypes.add(it.type)
|
null
|
||||||
|
else
|
||||||
|
irTemporary(value = it, nameHint = "\$extensionReceiver${tempIndex++}").symbol
|
||||||
}
|
}
|
||||||
val getterKFunctionType = context.reflectionTypes.getKFunctionType(
|
val propertyDescriptor = expression.descriptor
|
||||||
annotations = Annotations.EMPTY,
|
|
||||||
receiverType = receiverTypes.firstOrNull(),
|
|
||||||
parameterTypes = if (receiverTypes.size < 2) listOf() else listOf(receiverTypes[1]),
|
|
||||||
returnType = returnType)
|
|
||||||
IrFunctionReferenceImpl(
|
|
||||||
startOffset, endOffset,
|
|
||||||
getterKFunctionType, expression.getter!!, getter, null
|
|
||||||
).apply {
|
|
||||||
dispatchReceiver = expression.dispatchReceiver
|
|
||||||
extensionReceiver = expression.extensionReceiver
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val setterCallableReference = propertyDescriptor.setter?.let {
|
val returnType = propertyDescriptor.type
|
||||||
if (!isKMutablePropertyType(expression.type)) null
|
val getterCallableReference = propertyDescriptor.getter?.let { getter ->
|
||||||
else {
|
getter.extensionReceiverParameter.let {
|
||||||
val setterKFunctionType = context.reflectionTypes.getKFunctionType(
|
if (it != null && expression.extensionReceiver == null)
|
||||||
annotations = Annotations.EMPTY,
|
receiverTypes.add(it.type)
|
||||||
receiverType = receiverTypes.firstOrNull(),
|
}
|
||||||
parameterTypes = if (receiverTypes.size < 2) listOf(returnType) else listOf(receiverTypes[1], returnType),
|
getter.dispatchReceiverParameter.let {
|
||||||
returnType = context.builtIns.unitType)
|
if (it != null && expression.dispatchReceiver == null)
|
||||||
|
receiverTypes.add(it.type)
|
||||||
|
}
|
||||||
|
val getterKFunctionType = reflectionTypes.getKFunctionType(
|
||||||
|
annotations = Annotations.EMPTY,
|
||||||
|
receiverType = receiverTypes.firstOrNull(),
|
||||||
|
parameterTypes = if (receiverTypes.size < 2) listOf() else listOf(receiverTypes[1]),
|
||||||
|
returnType = returnType)
|
||||||
IrFunctionReferenceImpl(
|
IrFunctionReferenceImpl(
|
||||||
startOffset, endOffset,
|
startOffset = startOffset,
|
||||||
setterKFunctionType, expression.setter!!, it, null
|
endOffset = endOffset,
|
||||||
|
type = getterKFunctionType,
|
||||||
|
symbol = expression.getter!!,
|
||||||
|
descriptor = getter,
|
||||||
|
typeArguments = null
|
||||||
).apply {
|
).apply {
|
||||||
dispatchReceiver = expression.dispatchReceiver
|
this.dispatchReceiver = dispatchReceiver?.let { irGet(it) }
|
||||||
extensionReceiver = expression.extensionReceiver
|
this.extensionReceiver = extensionReceiver?.let { irGet(it) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
val (symbol, descriptor) = getKPropertyImplConstructor(
|
val setterCallableReference = propertyDescriptor.setter?.let {
|
||||||
receiverTypes = receiverTypes,
|
if (!isKMutablePropertyType(expression.type)) null
|
||||||
returnType = returnType,
|
else {
|
||||||
isLocal = false,
|
val setterKFunctionType = reflectionTypes.getKFunctionType(
|
||||||
isMutable = setterCallableReference != null)
|
annotations = Annotations.EMPTY,
|
||||||
val initializer = IrCallImpl(startOffset, endOffset, symbol, descriptor).apply {
|
receiverType = receiverTypes.firstOrNull(),
|
||||||
putValueArgument(0, IrConstImpl<String>(startOffset, endOffset,
|
parameterTypes = if (receiverTypes.size < 2) listOf(returnType) else listOf(receiverTypes[1], returnType),
|
||||||
context.builtIns.stringType, IrConstKind.String, propertyDescriptor.name.asString()))
|
returnType = context.builtIns.unitType)
|
||||||
if (getterCallableReference != null)
|
IrFunctionReferenceImpl(
|
||||||
putValueArgument(1, getterCallableReference)
|
startOffset = startOffset,
|
||||||
if (setterCallableReference != null)
|
endOffset = endOffset,
|
||||||
putValueArgument(2, setterCallableReference)
|
type = setterKFunctionType,
|
||||||
|
symbol = expression.setter!!,
|
||||||
|
descriptor = it,
|
||||||
|
typeArguments = null
|
||||||
|
).apply {
|
||||||
|
this.dispatchReceiver = dispatchReceiver?.let { irGet(it) }
|
||||||
|
this.extensionReceiver = extensionReceiver?.let { irGet(it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val (symbol, constructorTypeArguments) = getKPropertyImplConstructor(
|
||||||
|
receiverTypes = receiverTypes,
|
||||||
|
returnType = returnType,
|
||||||
|
isLocal = false,
|
||||||
|
isMutable = setterCallableReference != null)
|
||||||
|
val initializer = irCall(symbol, constructorTypeArguments).apply {
|
||||||
|
putValueArgument(0, irString(propertyDescriptor.name.asString()))
|
||||||
|
if (getterCallableReference != null)
|
||||||
|
putValueArgument(1, getterCallableReference)
|
||||||
|
if (setterCallableReference != null)
|
||||||
|
putValueArgument(2, setterCallableReference)
|
||||||
|
}
|
||||||
|
+initializer
|
||||||
}
|
}
|
||||||
return initializer
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createLocalKProperty(expression: IrLocalDelegatedPropertyReference, propertyDescriptor: VariableDescriptorWithAccessors): IrCallImpl {
|
private fun createLocalKProperty(propertyDescriptor: VariableDescriptorWithAccessors,
|
||||||
val startOffset = expression.startOffset
|
irBuilder: IrBuilderWithScope): IrExpression {
|
||||||
val endOffset = expression.endOffset
|
irBuilder.run {
|
||||||
|
val returnType = propertyDescriptor.type
|
||||||
|
|
||||||
val returnType = propertyDescriptor.type
|
val (symbol, constructorTypeArguments) = getKPropertyImplConstructor(
|
||||||
|
receiverTypes = emptyList(),
|
||||||
val (symbol, descriptor) = getKPropertyImplConstructor(
|
returnType = returnType,
|
||||||
receiverTypes = emptyList(),
|
isLocal = true,
|
||||||
returnType = returnType,
|
isMutable = false)
|
||||||
isLocal = true,
|
val initializer = irCall(symbol, constructorTypeArguments).apply {
|
||||||
isMutable = false)
|
putValueArgument(0, irString(propertyDescriptor.name.asString()))
|
||||||
|
}
|
||||||
val initializer = IrCallImpl(startOffset, endOffset, symbol, descriptor).apply {
|
return initializer
|
||||||
putValueArgument(0, IrConstImpl<String>(startOffset, endOffset,
|
|
||||||
context.builtIns.stringType, IrConstKind.String, propertyDescriptor.name.asString()))
|
|
||||||
}
|
}
|
||||||
return initializer
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isKMutablePropertyType(type: KotlinType): Boolean {
|
private fun isKMutablePropertyType(type: KotlinType): Boolean {
|
||||||
|
|||||||
Reference in New Issue
Block a user