diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/AssignmentGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/AssignmentGenerator.kt index cb992e6ca0b..c8dc94713b6 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/AssignmentGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/AssignmentGenerator.kt @@ -263,19 +263,20 @@ class AssignmentGenerator(statementGenerator: StatementGenerator) : StatementGen ktLeft: KtArrayAccessExpression, origin: IrStatementOrigin ): ArrayAccessAssignmentReceiver { - val irArray = ktLeft.arrayExpression!!.genExpr() - val irIndexExpressions = ktLeft.indexExpressions.map { it.genExpr() } - val indexedGetResolvedCall = get(BindingContext.INDEXED_LVALUE_GET, ktLeft) - val indexedGetCall = indexedGetResolvedCall?.let { statementGenerator.pregenerateCallReceivers(it) } - val indexedSetResolvedCall = get(BindingContext.INDEXED_LVALUE_SET, ktLeft) - val indexedSetCall = indexedSetResolvedCall?.let { statementGenerator.pregenerateCallReceivers(it) } return ArrayAccessAssignmentReceiver( - irArray, irIndexExpressions, indexedGetCall, indexedSetCall, + ktLeft.arrayExpression!!.genExpr(), + ktLeft.indexExpressions.map { it.genExpr() }, + indexedGetResolvedCall, + indexedSetResolvedCall, + { indexedGetResolvedCall?.let { statementGenerator.pregenerateCallReceivers(it) } }, + { indexedSetResolvedCall?.let { statementGenerator.pregenerateCallReceivers(it) } }, CallGenerator(statementGenerator), - ktLeft.startOffsetSkippingComments, ktLeft.endOffset, origin + ktLeft.startOffsetSkippingComments, + ktLeft.endOffset, + origin ) } diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/ArrayAccessAssignmentReceiver.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/ArrayAccessAssignmentReceiver.kt index c6f2b007e41..3584794a03e 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/ArrayAccessAssignmentReceiver.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/ArrayAccessAssignmentReceiver.kt @@ -16,31 +16,40 @@ package org.jetbrains.kotlin.psi2ir.intermediate +import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin import org.jetbrains.kotlin.ir.expressions.impl.IrBlockImpl import org.jetbrains.kotlin.ir.expressions.impl.inlineStatement import org.jetbrains.kotlin.ir.expressions.isAssignmentOperatorWithResult import org.jetbrains.kotlin.psi2ir.generators.CallGenerator +import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.types.KotlinType -import java.lang.AssertionError class ArrayAccessAssignmentReceiver( private val irArray: IrExpression, private val irIndices: List, - private val indexedGetCall: CallBuilder?, - private val indexedSetCall: CallBuilder?, + private val indexedGetResolvedCall: ResolvedCall?, + private val indexedSetResolvedCall: ResolvedCall?, + private val indexedGetCall: () -> CallBuilder?, + private val indexedSetCall: () -> CallBuilder?, private val callGenerator: CallGenerator, private val startOffset: Int, private val endOffset: Int, private val origin: IrStatementOrigin ) : AssignmentReceiver { - private val kotlinType: KotlinType = - indexedGetCall?.run { descriptor.returnType!! } ?: indexedSetCall?.run { descriptor.valueParameters.last().type } - ?: throw AssertionError("Array access should have either indexed-get call or indexed-set call") + private val descriptor = + indexedGetResolvedCall?.resultingDescriptor + ?: indexedSetResolvedCall?.resultingDescriptor + ?: throw AssertionError("Array access should have either indexed-get call or indexed-set call") override fun assign(withLValue: (LValue) -> IrExpression): IrExpression { + val kotlinType: KotlinType = + indexedGetResolvedCall?.run { resultingDescriptor.returnType!! } + ?: indexedSetResolvedCall?.run { resultingDescriptor.valueParameters.last().type } + ?: throw AssertionError("Array access should have either indexed-get call or indexed-set call") + val hasResult = origin.isAssignmentOperatorWithResult() val resultType = if (hasResult) kotlinType else callGenerator.context.builtIns.unitType val irResultType = callGenerator.translateType(resultType) @@ -52,11 +61,11 @@ class ArrayAccessAssignmentReceiver( callGenerator.scope.createTemporaryVariableInBlock(callGenerator.context, irIndex, irBlock, "index$i") } - indexedGetCall?.fillArrayAndIndexArguments(irArrayValue, irIndexValues) - indexedSetCall?.fillArrayAndIndexArguments(irArrayValue, irIndexValues) val irLValue = LValueWithGetterAndSetterCalls( callGenerator, - indexedGetCall, indexedSetCall, + descriptor, + { indexedGetCall()?.fillArrayAndIndexArguments(irArrayValue, irIndexValues) }, + { indexedSetCall()?.fillArrayAndIndexArguments(irArrayValue, irIndexValues) }, callGenerator.translateType(kotlinType), startOffset, endOffset, origin ) @@ -66,16 +75,16 @@ class ArrayAccessAssignmentReceiver( } override fun assign(value: IrExpression): IrExpression { - if (indexedSetCall == null) throw AssertionError("Array access without indexed-get call") - indexedSetCall.setExplicitReceiverValue(OnceExpressionValue(irArray)) + val call = indexedSetCall() ?: throw AssertionError("Array access without indexed-get call") + call.setExplicitReceiverValue(OnceExpressionValue(irArray)) irIndices.forEachIndexed { i, irIndex -> - indexedSetCall.irValueArgumentsByIndex[i] = irIndex + call.irValueArgumentsByIndex[i] = irIndex } - indexedSetCall.lastArgument = value - return callGenerator.generateCall(startOffset, endOffset, indexedSetCall, IrStatementOrigin.EQ) + call.lastArgument = value + return callGenerator.generateCall(startOffset, endOffset, call, IrStatementOrigin.EQ) } - private fun CallBuilder.fillArrayAndIndexArguments(arrayValue: IntermediateValue, indexValues: List) { + private fun CallBuilder.fillArrayAndIndexArguments(arrayValue: IntermediateValue, indexValues: List) = apply { setExplicitReceiverValue(arrayValue) indexValues.forEachIndexed { i, irIndexValue -> irValueArgumentsByIndex[i] = irIndexValue.load() diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/LValueWithGetterAndSetterCalls.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/LValueWithGetterAndSetterCalls.kt index 67d2a5f5ab9..3d9d9423ef6 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/LValueWithGetterAndSetterCalls.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/LValueWithGetterAndSetterCalls.kt @@ -21,31 +21,27 @@ import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.psi2ir.generators.CallGenerator -import org.jetbrains.kotlin.types.KotlinType class LValueWithGetterAndSetterCalls( val callGenerator: CallGenerator, - val getterCall: CallBuilder?, - val setterCall: CallBuilder?, + val descriptor: CallableDescriptor, + val getterCall: () -> CallBuilder?, + val setterCall: () -> CallBuilder?, override val type: IrType, val startOffset: Int, val endOffset: Int, val origin: IrStatementOrigin? = null ) : LValue { - private val descriptor: CallableDescriptor = - getterCall?.descriptor ?: setterCall?.descriptor - ?: throw AssertionError("Call-based LValue should have either a getter or a setter call") - override fun load(): IrExpression { - if (getterCall == null) throw AssertionError("No getter call for $descriptor") - return callGenerator.generateCall(startOffset, endOffset, getterCall, origin) + val call = getterCall() ?: throw AssertionError("No getter call for $descriptor") + return callGenerator.generateCall(startOffset, endOffset, call, origin) } override fun store(irExpression: IrExpression): IrExpression { - if (setterCall == null) throw AssertionError("No setter call for $descriptor") - setterCall.irValueArgumentsByIndex[setterCall.argumentsCount - 1] = irExpression - return callGenerator.generateCall(startOffset, endOffset, setterCall, origin) + val call = setterCall() ?: throw AssertionError("No setter call for $descriptor") + call.irValueArgumentsByIndex[call.argumentsCount - 1] = irExpression + return callGenerator.generateCall(startOffset, endOffset, call, origin) } } diff --git a/compiler/tests-common/tests/org/jetbrains/kotlin/ir/AbstractIrTextTestCase.kt b/compiler/tests-common/tests/org/jetbrains/kotlin/ir/AbstractIrTextTestCase.kt index 5ba0570a890..6ca1a84f2b8 100644 --- a/compiler/tests-common/tests/org/jetbrains/kotlin/ir/AbstractIrTextTestCase.kt +++ b/compiler/tests-common/tests/org/jetbrains/kotlin/ir/AbstractIrTextTestCase.kt @@ -136,8 +136,18 @@ abstract class AbstractIrTextTestCase : AbstractIrGeneratorTestCase() { } } + private val elementsAreUniqueChecker = object : IrElementVisitorVoid { + private val elements = HashSet() + + override fun visitElement(element: IrElement) { + require(elements.add(element)) { "Non-unique element: ${element.render()}" } + element.acceptChildrenVoid(this) + } + } + fun verifyWithAssert(irFile: IrFile) { irFile.acceptChildrenVoid(this) + irFile.acceptChildrenVoid(elementsAreUniqueChecker) TestCase.assertFalse(errorsAsMessage + "\n\n\n" + irFile.dump(), hasErrors) }