Fixed bug with duplicate IR nodes

This commit is contained in:
Igor Chevdar
2017-05-23 16:31:57 +03:00
parent d08438da5f
commit 560822fca0
@@ -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 {