diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/IrUtils.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/IrUtils.kt index b13da7557f8..8753c6b6d56 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/IrUtils.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/IrUtils.kt @@ -38,5 +38,5 @@ fun IrExpression.toExpectedType(expectedType: KotlinType?): IrExpression { ) } -fun IrVariable.createDefaultGetExpression(): IrExpression = +fun IrVariable.load(): IrExpression = IrGetVariableExpressionImpl(startOffset, endOffset, descriptor) \ No newline at end of file diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/IrCallGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/IrCallGenerator.kt index e81c244430f..0d8df069405 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/IrCallGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/IrCallGenerator.kt @@ -22,7 +22,7 @@ import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.psiUtil.endOffset import org.jetbrains.kotlin.psi.psiUtil.startOffset -import org.jetbrains.kotlin.psi2ir.generators.values.IrTemporaryVariableValue +import org.jetbrains.kotlin.psi2ir.generators.values.IrVariableValue import org.jetbrains.kotlin.psi2ir.generators.values.IrValue import org.jetbrains.kotlin.psi2ir.generators.values.createRematerializableValue import org.jetbrains.kotlin.psi2ir.toExpectedType @@ -51,7 +51,7 @@ class IrCallGenerator(val irStatementGenerator: IrStatementGenerator) : IrGenera } val irTmpVar = temporaryVariableFactory.createTemporaryVariable(irExpression, nameHint) - putValue(ktExpression, IrTemporaryVariableValue(irTmpVar)) + putValue(ktExpression, IrVariableValue(irTmpVar)) return irTmpVar } @@ -63,7 +63,7 @@ class IrCallGenerator(val irStatementGenerator: IrStatementGenerator) : IrGenera } val irTmpVar = temporaryVariableFactory.createTemporaryVariable(irExpression, valueParameterDescriptor.name.asString()) - putValue(valueParameterDescriptor, IrTemporaryVariableValue(irTmpVar)) + putValue(valueParameterDescriptor, IrVariableValue(irTmpVar)) return irTmpVar } diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/IrOperatorConventions.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/IrOperatorConventions.kt index 4ba86a02ee3..9bfb0511586 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/IrOperatorConventions.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/IrOperatorConventions.kt @@ -21,64 +21,87 @@ import org.jetbrains.kotlin.ir.expressions.IrOperator import org.jetbrains.kotlin.lexer.KtTokens +fun getIrBinaryOperator(ktOperator: IElementType): IrOperator? = + KT_TOKEN_TO_IR_BINARY_OPERATOR[ktOperator] -internal fun getIrOperator(ktOperator: IElementType): IrOperator? = - KT_TOKEN_TO_IR_OPERATOR[ktOperator] +fun getIrPrefixOperator(ktOperator: IElementType): IrOperator? = + KT_TOKEN_TO_IR_PREFIX_OPERATOR[ktOperator] -internal val KT_TOKEN_TO_IR_OPERATOR = - mapOf( - KtTokens.EQ to IrOperator.EQ, +fun getIrPostfixOperator(ktOperator: IElementType): IrOperator? = + KT_TOKEN_TO_IR_POSTFIX_OPERATOR[ktOperator] - KtTokens.PLUSEQ to IrOperator.PLUSEQ, - KtTokens.MINUSEQ to IrOperator.MINUSEQ, - KtTokens.MULTEQ to IrOperator.MULTEQ, - KtTokens.DIVEQ to IrOperator.DIVEQ, - KtTokens.PERCEQ to IrOperator.PERCEQ, +private val KT_TOKEN_TO_IR_BINARY_OPERATOR = mapOf( + KtTokens.EQ to IrOperator.EQ, - KtTokens.PLUS to IrOperator.PLUS, - KtTokens.MINUS to IrOperator.MINUS, - KtTokens.MUL to IrOperator.MUL, - KtTokens.DIV to IrOperator.DIV, - KtTokens.PERC to IrOperator.PERC, - KtTokens.RANGE to IrOperator.RANGE, + KtTokens.PLUSEQ to IrOperator.PLUSEQ, + KtTokens.MINUSEQ to IrOperator.MINUSEQ, + KtTokens.MULTEQ to IrOperator.MULTEQ, + KtTokens.DIVEQ to IrOperator.DIVEQ, + KtTokens.PERCEQ to IrOperator.PERCEQ, - KtTokens.LT to IrOperator.LT, - KtTokens.LTEQ to IrOperator.LTEQ, - KtTokens.GT to IrOperator.GT, - KtTokens.GTEQ to IrOperator.GTEQ, + KtTokens.PLUS to IrOperator.PLUS, + KtTokens.MINUS to IrOperator.MINUS, + KtTokens.MUL to IrOperator.MUL, + KtTokens.DIV to IrOperator.DIV, + KtTokens.PERC to IrOperator.PERC, + KtTokens.RANGE to IrOperator.RANGE, - KtTokens.EQEQ to IrOperator.EQEQ, - KtTokens.EXCLEQ to IrOperator.EXCLEQ, + KtTokens.LT to IrOperator.LT, + KtTokens.LTEQ to IrOperator.LTEQ, + KtTokens.GT to IrOperator.GT, + KtTokens.GTEQ to IrOperator.GTEQ, - KtTokens.EQEQEQ to IrOperator.EQEQEQ, - KtTokens.EXCLEQEQEQ to IrOperator.EXCLEQEQ, + KtTokens.EQEQ to IrOperator.EQEQ, + KtTokens.EXCLEQ to IrOperator.EXCLEQ, - KtTokens.IN_KEYWORD to IrOperator.IN, - KtTokens.NOT_IN to IrOperator.NOT_IN, + KtTokens.EQEQEQ to IrOperator.EQEQEQ, + KtTokens.EXCLEQEQEQ to IrOperator.EXCLEQEQ, - KtTokens.ANDAND to IrOperator.ANDAND, - KtTokens.OROR to IrOperator.OROR, + KtTokens.IN_KEYWORD to IrOperator.IN, + KtTokens.NOT_IN to IrOperator.NOT_IN, - KtTokens.ELVIS to IrOperator.ELVIS - ) + KtTokens.ANDAND to IrOperator.ANDAND, + KtTokens.OROR to IrOperator.OROR, -internal val AUGMENTED_ASSIGNMENTS = + KtTokens.ELVIS to IrOperator.ELVIS +) + +private val KT_TOKEN_TO_IR_PREFIX_OPERATOR = mapOf( + KtTokens.PLUSPLUS to IrOperator.PREFIX_INCR, + KtTokens.MINUSMINUS to IrOperator.PREFIX_DECR, + KtTokens.EXCL to IrOperator.EXCL, + KtTokens.MINUS to IrOperator.UMINUS +) + +private val KT_TOKEN_TO_IR_POSTFIX_OPERATOR = mapOf( + KtTokens.PLUSPLUS to IrOperator.POSTFIX_INCR, + KtTokens.MINUSMINUS to IrOperator.POSTFIX_DECR, + KtTokens.EXCLEXCL to IrOperator.EXCLEXCL +) + +val AUGMENTED_ASSIGNMENTS = setOf(IrOperator.PLUSEQ, IrOperator.MINUSEQ, IrOperator.MULTEQ, IrOperator.DIVEQ, IrOperator.PERCEQ) -internal val BINARY_OPERATORS_DESUGARED_TO_CALLS = +val BINARY_OPERATORS_DESUGARED_TO_CALLS = setOf(IrOperator.PLUS, IrOperator.MINUS, IrOperator.MUL, IrOperator.DIV, IrOperator.PERC, IrOperator.RANGE) -internal val COMPARISON_OPERATORS = +val COMPARISON_OPERATORS = setOf(IrOperator.LT, IrOperator.LTEQ, IrOperator.GT, IrOperator.GTEQ) -internal val EQUALITY_OPERATORS = +val EQUALITY_OPERATORS = setOf(IrOperator.EQEQ, IrOperator.EXCLEQ) -internal val IDENTITY_OPERATORS = +val IDENTITY_OPERATORS = setOf(IrOperator.EQEQEQ, IrOperator.EXCLEQEQ) -internal val IN_OPERATORS = +val IN_OPERATORS = setOf(IrOperator.IN, IrOperator.NOT_IN) -internal val BINARY_BOOLEAN_OPERATORS = - setOf(IrOperator.ANDAND, IrOperator.OROR) \ No newline at end of file +val BINARY_BOOLEAN_OPERATORS = + setOf(IrOperator.ANDAND, IrOperator.OROR) + +val PREFIX_INCREMENT_DECREMENT_OPERATORS = + setOf(IrOperator.PREFIX_INCR, IrOperator.PREFIX_DECR) + +val POSTFIX_INCREMENT_DECREMENT_OPERATORS = + setOf(IrOperator.POSTFIX_INCR, IrOperator.POSTFIX_DECR) \ No newline at end of file diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/IrOperatorExpressionGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/IrOperatorExpressionGenerator.kt index 2dd0535efd2..911d3fe0e6d 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/IrOperatorExpressionGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/IrOperatorExpressionGenerator.kt @@ -18,15 +18,14 @@ package org.jetbrains.kotlin.psi2ir.generators import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor -import org.jetbrains.kotlin.ir.expressions.IrBinaryOperatorExpressionImpl -import org.jetbrains.kotlin.ir.expressions.IrExpression -import org.jetbrains.kotlin.ir.expressions.IrOperator -import org.jetbrains.kotlin.ir.expressions.IrUnaryOperatorExpressionImpl +import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.psi.KtArrayAccessExpression import org.jetbrains.kotlin.psi.KtBinaryExpression import org.jetbrains.kotlin.psi.KtExpression +import org.jetbrains.kotlin.psi.KtPrefixExpression import org.jetbrains.kotlin.psi.psiUtil.endOffset import org.jetbrains.kotlin.psi.psiUtil.startOffset +import org.jetbrains.kotlin.psi2ir.load import org.jetbrains.kotlin.psi2ir.generators.values.* import org.jetbrains.kotlin.psi2ir.toExpectedType import org.jetbrains.kotlin.resolve.BindingContext @@ -37,9 +36,20 @@ import org.jetbrains.kotlin.types.typeUtil.makeNullable class IrOperatorExpressionGenerator(val irStatementGenerator: IrStatementGenerator): IrGenerator { override val context: IrGeneratorContext get() = irStatementGenerator.context + fun generatePrefixExpression(expression: KtPrefixExpression): IrExpression { + val ktOperator = expression.operationReference.getReferencedNameElementType() + val irOperator = getIrPrefixOperator(ktOperator) + + return when (irOperator) { + null -> createDummyExpression(expression, ktOperator.toString()) + in PREFIX_INCREMENT_DECREMENT_OPERATORS -> generatePrefixIncrementDecrementOperator(expression, irOperator) + else -> createDummyExpression(expression, ktOperator.toString()) + } + } + fun generateBinaryExpression(expression: KtBinaryExpression): IrExpression { val ktOperator = expression.operationReference.getReferencedNameElementType() - val irOperator = getIrOperator(ktOperator) + val irOperator = getIrBinaryOperator(ktOperator) return when (irOperator) { null -> createDummyExpression(expression, ktOperator.toString()) @@ -142,25 +152,42 @@ class IrOperatorExpressionGenerator(val irStatementGenerator: IrStatementGenerat return IrCallGenerator(irStatementGenerator).generateCall(expression, operatorCall, irOperator) } + private fun generatePrefixIncrementDecrementOperator(expression: KtPrefixExpression, irOperator: IrOperator): IrExpression { + val ktBaseExpression = expression.baseExpression!! + val irLValue = generateLValue(ktBaseExpression, irOperator) + val operatorCall = getResolvedCall(expression)!! + + if (irLValue is IrLValueWithAugmentedStore) { + return irLValue.prefixAugmentedStore(operatorCall) + } + + val opCallGenerator = IrCallGenerator(irStatementGenerator).apply { putValue(ktBaseExpression, irLValue) } + val irBlock = IrBlockExpressionImpl(expression.startOffset, expression.endOffset, irLValue.type, true, true) + val irOpCall = opCallGenerator.generateCall(expression, operatorCall, irOperator) + val irTmp = irStatementGenerator.temporaryVariableFactory.createTemporaryVariable(irOpCall) + irBlock.addStatement(irTmp) + irBlock.addStatement(irLValue.store(irTmp.load())) + irBlock.addStatement(irTmp.load()) + return irBlock + } + private fun generateAugmentedAssignment(expression: KtBinaryExpression, irOperator: IrOperator): IrExpression { val ktLeft = expression.left!! - - val irLhs = generateLValue(ktLeft, irOperator) + val irLValue = generateLValue(ktLeft, irOperator) + val operatorCall = getResolvedCall(expression)!! val isSimpleAssignment = get(BindingContext.VARIABLE_REASSIGNMENT, expression) ?: false - val operatorCall = getResolvedCall(expression)!! - - if (isSimpleAssignment && irLhs is IrLValueWithAugmentedStore) { - return irLhs.augmentedStore(operatorCall, irStatementGenerator.generateExpression(expression.right!!)) + if (isSimpleAssignment && irLValue is IrLValueWithAugmentedStore) { + return irLValue.augmentedStore(operatorCall, irStatementGenerator.generateExpression(expression.right!!)) } - val opCallGenerator = IrCallGenerator(irStatementGenerator).apply { putValue(ktLeft, irLhs) } + val opCallGenerator = IrCallGenerator(irStatementGenerator).apply { putValue(ktLeft, irLValue) } val irOpCall = opCallGenerator.generateCall(expression, operatorCall, irOperator) return if (isSimpleAssignment) { // Set( Op( Get(), RHS ) ) - irLhs.store(irOpCall) + irLValue.store(irOpCall) } else { // Op( Get(), RHS ) @@ -171,8 +198,8 @@ class IrOperatorExpressionGenerator(val irStatementGenerator: IrStatementGenerat private fun generateAssignment(expression: KtBinaryExpression): IrExpression { val ktLeft = expression.left!! val ktRight = expression.right!! - val lhsReference = generateLValue(ktLeft, IrOperator.EQ) - return lhsReference.store(irStatementGenerator.generateExpression(ktRight)) + val irLValue = generateLValue(ktLeft, IrOperator.EQ) + return irLValue.store(irStatementGenerator.generateExpression(ktRight)) } private fun generateLValue(ktLeft: KtExpression, irOperator: IrOperator?): IrLValue { @@ -181,8 +208,11 @@ class IrOperatorExpressionGenerator(val irStatementGenerator: IrStatementGenerat val indexExpressions = ktLeft.indexExpressions.map { it to irStatementGenerator.generateExpression(it) } val indexedGetCall = get(BindingContext.INDEXED_LVALUE_GET, ktLeft) val indexedSetCall = get(BindingContext.INDEXED_LVALUE_SET, ktLeft) + val type = indexedGetCall?.run { resultingDescriptor.returnType } + ?: indexedSetCall?.run { resultingDescriptor.valueParameters.last().type } + ?: throw AssertionError("Either 'get' or 'set' call should be present for an indexed LValue: ${ktLeft.text}") return IrIndexedLValue(irStatementGenerator, ktLeft, irOperator, - irArrayValue, indexExpressions, indexedGetCall, indexedSetCall) + irArrayValue, type, indexExpressions, indexedGetCall, indexedSetCall) } val resolvedCall = getResolvedCall(ktLeft) ?: TODO("no resolved call for LHS") @@ -193,7 +223,7 @@ class IrOperatorExpressionGenerator(val irStatementGenerator: IrStatementGenerat if (descriptor.isDelegated) TODO("Delegated local variable") else - IrVariableLValueValue(ktLeft, irOperator, descriptor) + IrVariableValue(ktLeft.startOffset, ktLeft.endOffset, descriptor, irOperator) is PropertyDescriptor -> IrCallGenerator(irStatementGenerator).run { IrPropertyLValueValue( @@ -207,4 +237,5 @@ class IrOperatorExpressionGenerator(val irStatementGenerator: IrStatementGenerat TODO("Other cases of LHS") } } + } diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/IrStatementGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/IrStatementGenerator.kt index 32dd31d6791..1a6987b82e6 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/IrStatementGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/IrStatementGenerator.kt @@ -26,7 +26,7 @@ import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.endOffset import org.jetbrains.kotlin.psi.psiUtil.startOffset import org.jetbrains.kotlin.psi2ir.deparenthesize -import org.jetbrains.kotlin.psi2ir.generators.values.IrTemporaryVariableValue +import org.jetbrains.kotlin.psi2ir.generators.values.IrVariableValue import org.jetbrains.kotlin.psi2ir.toExpectedType import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContextUtils @@ -79,7 +79,7 @@ class IrStatementGenerator( irBlock.addStatement(irTmpInitializer) val irCallGenerator = IrCallGenerator(this) - irCallGenerator.putValue(ktInitializer, IrTemporaryVariableValue(irTmpInitializer)) + irCallGenerator.putValue(ktInitializer, IrVariableValue(irTmpInitializer)) for ((index, ktEntry) in multiDeclaration.entries.withIndex()) { val componentResolvedCall = getOrFail(BindingContext.COMPONENT_RESOLVED_CALL, ktEntry) @@ -241,4 +241,7 @@ class IrStatementGenerator( override fun visitBinaryExpression(expression: KtBinaryExpression, data: Nothing?): IrStatement = IrOperatorExpressionGenerator(this).generateBinaryExpression(expression) + + override fun visitPrefixExpression(expression: KtPrefixExpression, data: Nothing?): IrStatement = + IrOperatorExpressionGenerator(this).generatePrefixExpression(expression) } diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/values/IrIndexedLValue.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/values/IrIndexedLValue.kt index b88c89b124e..c5e679e74ab 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/values/IrIndexedLValue.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/values/IrIndexedLValue.kt @@ -21,15 +21,18 @@ import org.jetbrains.kotlin.psi.KtArrayAccessExpression import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.psiUtil.endOffset import org.jetbrains.kotlin.psi.psiUtil.startOffset +import org.jetbrains.kotlin.psi2ir.load import org.jetbrains.kotlin.psi2ir.generators.IrCallGenerator import org.jetbrains.kotlin.psi2ir.generators.IrStatementGenerator import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall +import org.jetbrains.kotlin.types.KotlinType class IrIndexedLValue( var irStatementGenerator: IrStatementGenerator, val ktArrayAccessExpression: KtArrayAccessExpression, val irOperator: IrOperator?, val irArray: IrExpression, + override val type: KotlinType?, val indexValues: List>, val indexedGetCall: ResolvedCall<*>?, val indexedSetCall: ResolvedCall<*>? @@ -37,50 +40,64 @@ class IrIndexedLValue( override fun load(): IrExpression { if (indexedGetCall == null) throw AssertionError("Indexed LValue has no 'get' call: ${ktArrayAccessExpression.text}") - val irBlock = IrBlockExpressionImpl(ktArrayAccessExpression.startOffset, ktArrayAccessExpression.endOffset, - indexedGetCall.resultingDescriptor.returnType, - hasResult = true, isDesugared = true) - - val callGenerator = IrCallGenerator(irStatementGenerator) - - defineContextVariables(irBlock, callGenerator) - - irBlock.addStatement(callGenerator.generateCall(ktArrayAccessExpression, indexedGetCall, irOperator)) - - return irBlock + return generateGetOrSetCallAsDesugaredBlock(indexedGetCall) } override fun store(irExpression: IrExpression): IrExpression { if (indexedSetCall == null) throw AssertionError("Indexed LValue has no 'set' call: ${ktArrayAccessExpression.text}") - val irBlock = IrBlockExpressionImpl(ktArrayAccessExpression.startOffset, ktArrayAccessExpression.endOffset, - indexedSetCall.resultingDescriptor.returnType, - hasResult = true, isDesugared = true) + return generateGetOrSetCallAsDesugaredBlock(indexedSetCall) + } + private fun generateGetOrSetCallAsDesugaredBlock(call: ResolvedCall<*>, irArgument: IrExpression? = null): IrExpression { val callGenerator = IrCallGenerator(irStatementGenerator) - defineContextVariables(irBlock, callGenerator) + val hasResult = irArgument == null + val irBlock = createDesugaredBlock(call, callGenerator, hasResult) - callGenerator.putValue(indexedSetCall.resultingDescriptor.valueParameters.last(), IrSingleExpressionValue(irExpression)) + if (irArgument != null) { + callGenerator.putValue(call.resultingDescriptor.valueParameters.last(), IrSingleExpressionValue(irArgument)) + } - irBlock.addStatement(callGenerator.generateCall(ktArrayAccessExpression, indexedSetCall, irOperator)) + irBlock.addStatement(callGenerator.generateCall(ktArrayAccessExpression, call, irOperator)) return irBlock } - override fun augmentedStore(operatorCall: ResolvedCall<*>, irRhs: IrExpression): IrExpression { + override fun prefixAugmentedStore(operatorCall: ResolvedCall<*>): IrExpression { if (indexedGetCall == null) throw AssertionError("Indexed LValue has no 'get' call: ${ktArrayAccessExpression.text}") if (indexedSetCall == null) throw AssertionError("Indexed LValue has no 'set' call: ${ktArrayAccessExpression.text}") - val irBlock = IrBlockExpressionImpl(ktArrayAccessExpression.startOffset, ktArrayAccessExpression.endOffset, - indexedSetCall.resultingDescriptor.returnType, - hasResult = true, isDesugared = true) + val callGenerator = IrCallGenerator(irStatementGenerator) + + val irBlock = createDesugaredBlock(indexedSetCall, callGenerator, true) + + val operatorCallReceiver = operatorCall.extensionReceiver ?: operatorCall.dispatchReceiver + callGenerator.putValue(operatorCallReceiver!!, + IrSingleExpressionValue(callGenerator.generateCall(ktArrayAccessExpression, indexedGetCall, irOperator))) + val irTmp = irStatementGenerator.temporaryVariableFactory.createTemporaryVariable( + callGenerator.generateCall(ktArrayAccessExpression, operatorCall, irOperator)) + irBlock.addStatement(irTmp) + + callGenerator.putValue(indexedSetCall.resultingDescriptor.valueParameters.last(), + IrVariableValue(irTmp)) + + irBlock.addStatement(callGenerator.generateCall(ktArrayAccessExpression, indexedSetCall, irOperator)) + + irBlock.addStatement(irTmp.load()) + + return irBlock + } + + override fun augmentedStore(operatorCall: ResolvedCall<*>, irOperatorArgument: IrExpression): IrExpression { + if (indexedGetCall == null) throw AssertionError("Indexed LValue has no 'get' call: ${ktArrayAccessExpression.text}") + if (indexedSetCall == null) throw AssertionError("Indexed LValue has no 'set' call: ${ktArrayAccessExpression.text}") val callGenerator = IrCallGenerator(irStatementGenerator) - defineContextVariables(irBlock, callGenerator) + val irBlock = createDesugaredBlock(indexedSetCall, callGenerator, false) - callGenerator.putValue(operatorCall.resultingDescriptor.valueParameters[0], IrSingleExpressionValue(irRhs)) + callGenerator.putValue(operatorCall.resultingDescriptor.valueParameters[0], IrSingleExpressionValue(irOperatorArgument)) val operatorCallReceiver = operatorCall.extensionReceiver ?: operatorCall.dispatchReceiver callGenerator.putValue(operatorCallReceiver!!, @@ -94,6 +111,16 @@ class IrIndexedLValue( return irBlock } + private fun createDesugaredBlock(call: ResolvedCall<*>, callGenerator: IrCallGenerator, hasResult: Boolean): IrBlockExpressionImpl { + val irBlock = IrBlockExpressionImpl(ktArrayAccessExpression.startOffset, ktArrayAccessExpression.endOffset, + call.resultingDescriptor.returnType, + hasResult, true) + + defineContextVariables(irBlock, callGenerator) + + return irBlock + } + private fun defineContextVariables(irBlock: IrBlockExpression, callGenerator: IrCallGenerator) { irBlock.addIfNotNull(callGenerator.introduceTemporary(ktArrayAccessExpression.arrayExpression!!, irArray, "array")) diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/values/IrPropertyLValueValue.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/values/IrPropertyLValueValue.kt index 16529d6d01a..f7363ac3bd5 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/values/IrPropertyLValueValue.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/values/IrPropertyLValueValue.kt @@ -22,6 +22,7 @@ import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.psiUtil.endOffset import org.jetbrains.kotlin.psi.psiUtil.startOffset import org.jetbrains.kotlin.psi2ir.toExpectedType +import org.jetbrains.kotlin.types.KotlinType class IrPropertyLValueValue( val ktElement: KtElement, @@ -31,6 +32,9 @@ class IrPropertyLValueValue( val extensionReceiver: IrExpression?, val isSafe: Boolean ) : IrLValue { + override val type: KotlinType? + get() = descriptor.type + private fun IrPropertyAccessExpression.setReceivers() = apply { dispatchReceiver = this@IrPropertyLValueValue.dispatchReceiver diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/values/IrRematerializableValue.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/values/IrRematerializableValue.kt index a7a015df8c3..a4ccb044279 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/values/IrRematerializableValue.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/values/IrRematerializableValue.kt @@ -17,8 +17,14 @@ package org.jetbrains.kotlin.psi2ir.generators.values import org.jetbrains.kotlin.ir.expressions.* +import org.jetbrains.kotlin.types.KotlinType -interface IrRematerializableValue : IrValue +interface IrRematerializableValue : IrValue { + val irExpression: IrExpression + + override val type: KotlinType? + get() = irExpression.type +} fun createRematerializableValue(irExpression: IrExpression): IrRematerializableValue? = when (irExpression) { @@ -29,23 +35,23 @@ fun createRematerializableValue(irExpression: IrExpression): IrRematerializableV else -> null } -class IrRematerializableLiteralValue(val irExpression: IrLiteralExpression<*>): IrRematerializableValue { +class IrRematerializableLiteralValue(override val irExpression: IrLiteralExpression<*>): IrRematerializableValue { override fun load(): IrExpression = IrLiteralExpressionImpl(irExpression.startOffset, irExpression.endOffset, irExpression.type, irExpression.kind, irExpression.kind.valueOf(irExpression)) } -class IrRematerializableVariableValue(val irExpression: IrGetVariableExpression) : IrRematerializableValue { +class IrRematerializableVariableValue(override val irExpression: IrGetVariableExpression) : IrRematerializableValue { override fun load(): IrExpression = IrGetVariableExpressionImpl(irExpression.startOffset, irExpression.endOffset, irExpression.descriptor) } -class IrRematerializableExtensionReceiverValue(val irExpression: IrGetExtensionReceiverExpression) : IrRematerializableValue { +class IrRematerializableExtensionReceiverValue(override val irExpression: IrGetExtensionReceiverExpression) : IrRematerializableValue { override fun load(): IrExpression = IrGetExtensionReceiverExpressionImpl(irExpression.startOffset, irExpression.endOffset, irExpression.type, irExpression.descriptor) } -class IrRematerializableThisValue(val irExpression: IrThisExpression): IrRematerializableValue { +class IrRematerializableThisValue(override val irExpression: IrThisExpression): IrRematerializableValue { override fun load(): IrExpression = IrThisExpressionImpl(irExpression.startOffset, irExpression.endOffset, irExpression.type, irExpression.classDescriptor) } diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/values/IrValue.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/values/IrValue.kt index d31fd977f81..a302aa9f092 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/values/IrValue.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/values/IrValue.kt @@ -17,18 +17,13 @@ package org.jetbrains.kotlin.psi2ir.generators.values import org.jetbrains.kotlin.ir.assertDetached -import org.jetbrains.kotlin.ir.declarations.IrVariable import org.jetbrains.kotlin.ir.expressions.IrExpression -import org.jetbrains.kotlin.psi2ir.createDefaultGetExpression import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall +import org.jetbrains.kotlin.types.KotlinType interface IrValue { fun load(): IrExpression -} - -class IrTemporaryVariableValue(val irVariable: IrVariable) : IrValue { - override fun load(): IrExpression = - irVariable.createDefaultGetExpression() + val type: KotlinType? } class IrSingleExpressionValue(val irExpression: IrExpression) : IrValue { @@ -45,6 +40,8 @@ class IrSingleExpressionValue(val irExpression: IrExpression) : IrValue { } else throw AssertionError("Single exprssion value is already instantiated") + + override val type: KotlinType? get() = irExpression.type } interface IrLValue : IrValue { @@ -52,6 +49,7 @@ interface IrLValue : IrValue { } interface IrLValueWithAugmentedStore : IrLValue { - fun augmentedStore(operatorCall: ResolvedCall<*>, irRhs: IrExpression): IrExpression + fun prefixAugmentedStore(operatorCall: ResolvedCall<*>): IrExpression + fun augmentedStore(operatorCall: ResolvedCall<*>, irOperatorArgument: IrExpression): IrExpression } diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/values/IrVariableLValueValue.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/values/IrVariableValue.kt similarity index 59% rename from compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/values/IrVariableLValueValue.kt rename to compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/values/IrVariableValue.kt index 13bb95337a6..7b0a3a0fd7f 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/values/IrVariableLValueValue.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/values/IrVariableValue.kt @@ -17,29 +17,31 @@ package org.jetbrains.kotlin.psi2ir.generators.values import org.jetbrains.kotlin.descriptors.VariableDescriptor +import org.jetbrains.kotlin.ir.declarations.IrVariable import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrGetVariableExpressionImpl import org.jetbrains.kotlin.ir.expressions.IrOperator import org.jetbrains.kotlin.ir.expressions.IrSetVariableExpressionImpl -import org.jetbrains.kotlin.psi.KtElement -import org.jetbrains.kotlin.psi.psiUtil.endOffset -import org.jetbrains.kotlin.psi.psiUtil.startOffset import org.jetbrains.kotlin.psi2ir.toExpectedType +import org.jetbrains.kotlin.types.KotlinType -class IrVariableLValueValue( - val ktElement: KtElement, - val irOperator: IrOperator?, - val descriptor: VariableDescriptor +class IrVariableValue( + val startOffset: Int, + val endOffset: Int, + val descriptor: VariableDescriptor, + val irOperator: IrOperator? = null ) : IrLValue { + constructor( + irVariable: IrVariable, + irOperator: IrOperator? = null + ) : this(irVariable.startOffset, irVariable.endOffset, irVariable.descriptor, irOperator) + + override val type: KotlinType? get() = descriptor.type + override fun load(): IrExpression = - IrGetVariableExpressionImpl( - ktElement.startOffset, ktElement.endOffset, - descriptor, irOperator - ) + IrGetVariableExpressionImpl(startOffset, endOffset, descriptor, irOperator) override fun store(irExpression: IrExpression): IrExpression = - IrSetVariableExpressionImpl( - ktElement.startOffset, ktElement.endOffset, - descriptor, irExpression.toExpectedType(descriptor.type), irOperator - ) + IrSetVariableExpressionImpl(startOffset, endOffset, descriptor, + irExpression.toExpectedType(descriptor.type), irOperator) } \ No newline at end of file diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrOperator.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrOperator.kt index 95610bd015a..10b057fe254 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrOperator.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrOperator.kt @@ -20,10 +20,12 @@ abstract class IrOperator(val debugName: String) { override fun toString(): String = debugName object INVOKE : IrOperator("INVOKE") + object PREFIX_INCR : IrOperator("PREFIX_INCR") object PREFIX_DECR : IrOperator("PREFIX_DECR") object POSTFIX_INCR : IrOperator("POSTFIX_INCR") object POSTFIX_DECR : IrOperator("POSTFIX_DECR") + object UMINUS : IrOperator("UMINUS") object EXCL : IrOperator("EXCL") object EXCLEXCL : IrOperator("EXCLEXCL") diff --git a/compiler/testData/ir/irText/incrementDecrement.kt b/compiler/testData/ir/irText/incrementDecrement.kt new file mode 100644 index 00000000000..8f599f2a348 --- /dev/null +++ b/compiler/testData/ir/irText/incrementDecrement.kt @@ -0,0 +1,18 @@ +var p: Int = 0 +val arr = intArrayOf(1, 2, 3) + +fun testVar() { + var x = 0 + val x1 = ++x + val x2 = --x +} + +fun testProp() { + val p1 = ++p + val p2 = --p +} + +fun testArray() { + val a1 = ++arr[0] + val a2 = --arr[0] +} \ No newline at end of file diff --git a/compiler/testData/ir/irText/incrementDecrement.txt b/compiler/testData/ir/irText/incrementDecrement.txt new file mode 100644 index 00000000000..1957e59eeba --- /dev/null +++ b/compiler/testData/ir/irText/incrementDecrement.txt @@ -0,0 +1,81 @@ +IrFile /incrementDecrement.kt + IrProperty public var p: kotlin.Int getter=null setter=null + IrExpressionBody + LITERAL Int type=kotlin.Int value='0' + IrProperty public val arr: kotlin.IntArray getter=null setter=null + IrExpressionBody + CALL .intArrayOf type=kotlin.IntArray operator= + elements: DUMMY vararg type=kotlin.Int + IrFunction public fun testVar(): kotlin.Unit + IrExpressionBody + BLOCK type= hasResult=false isDesugared=false + VAR var x: kotlin.Int + LITERAL Int type=kotlin.Int value='0' + VAR val x1: kotlin.Int + BLOCK type=kotlin.Int hasResult=true isDesugared=true + VAR val tmp0: kotlin.Int + CALL .inc type=kotlin.Int operator=PREFIX_INCR + $this: GET_VAR x type=kotlin.Int + SET_VAR x type= + GET_VAR tmp0 type=kotlin.Int + GET_VAR tmp0 type=kotlin.Int + VAR val x2: kotlin.Int + BLOCK type=kotlin.Int hasResult=true isDesugared=true + VAR val tmp1: kotlin.Int + CALL .dec type=kotlin.Int operator=PREFIX_DECR + $this: GET_VAR x type=kotlin.Int + SET_VAR x type= + GET_VAR tmp1 type=kotlin.Int + GET_VAR tmp1 type=kotlin.Int + IrFunction public fun testProp(): kotlin.Unit + IrExpressionBody + BLOCK type= hasResult=false isDesugared=false + VAR val p1: kotlin.Int + BLOCK type=kotlin.Int hasResult=true isDesugared=true + VAR val tmp0: kotlin.Int + CALL .inc type=kotlin.Int operator=PREFIX_INCR + $this: GET_PROPERTY .p type=kotlin.Int + SET_PROPERTY .ptype= + $value: GET_VAR tmp0 type=kotlin.Int + GET_VAR tmp0 type=kotlin.Int + VAR val p2: kotlin.Int + BLOCK type=kotlin.Int hasResult=true isDesugared=true + VAR val tmp1: kotlin.Int + CALL .dec type=kotlin.Int operator=PREFIX_DECR + $this: GET_PROPERTY .p type=kotlin.Int + SET_PROPERTY .ptype= + $value: GET_VAR tmp1 type=kotlin.Int + GET_VAR tmp1 type=kotlin.Int + IrFunction public fun testArray(): kotlin.Unit + IrExpressionBody + BLOCK type= hasResult=false isDesugared=false + VAR val a1: kotlin.Int + TYPE_OP operator=IMPLICIT_CAST typeOperand=kotlin.Int + BLOCK type=kotlin.Unit hasResult=true isDesugared=true + VAR val tmp0_array: kotlin.IntArray + GET_PROPERTY .arr type=kotlin.IntArray + VAR val tmp1: kotlin.Int + CALL .inc type=kotlin.Int operator=PREFIX_INCR + $this: CALL .get type=kotlin.Int operator=PREFIX_INCR + $this: GET_VAR tmp0_array type=kotlin.IntArray + index: LITERAL Int type=kotlin.Int value='0' + CALL .set type=kotlin.Unit operator=PREFIX_INCR + $this: GET_VAR tmp0_array type=kotlin.IntArray + index: LITERAL Int type=kotlin.Int value='0' + value: GET_VAR tmp1 type=kotlin.Int + GET_VAR tmp1 type=kotlin.Int + VAR val a2: kotlin.Int + TYPE_OP operator=IMPLICIT_CAST typeOperand=kotlin.Int + BLOCK type=kotlin.Unit hasResult=true isDesugared=true + VAR val tmp2_array: kotlin.IntArray + GET_PROPERTY .arr type=kotlin.IntArray + VAR val tmp3: kotlin.Int + CALL .dec type=kotlin.Int operator=PREFIX_DECR + $this: CALL .get type=kotlin.Int operator=PREFIX_DECR + $this: GET_VAR tmp2_array type=kotlin.IntArray + index: LITERAL Int type=kotlin.Int value='0' + CALL .set type=kotlin.Unit operator=PREFIX_DECR + $this: GET_VAR tmp2_array type=kotlin.IntArray + index: LITERAL Int type=kotlin.Int value='0' + value: GET_VAR tmp3 type=kotlin.Int + GET_VAR tmp3 type=kotlin.Int diff --git a/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java b/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java index 850c613e970..f1ab3bdd427 100644 --- a/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java @@ -137,6 +137,12 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase { doTest(fileName); } + @TestMetadata("incrementDecrement.kt") + public void testIncrementDecrement() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/incrementDecrement.kt"); + doTest(fileName); + } + @TestMetadata("primitiveComparisons.kt") public void testPrimitiveComparisons() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/primitiveComparisons.kt");