Prefix increment / decrement.

Refactor IrLValue.
This commit is contained in:
Dmitry Petrov
2016-08-18 14:57:18 +03:00
committed by Dmitry Petrov
parent 68cdcfa853
commit 4a62a6b7c3
14 changed files with 313 additions and 112 deletions
@@ -38,5 +38,5 @@ fun IrExpression.toExpectedType(expectedType: KotlinType?): IrExpression {
) )
} }
fun IrVariable.createDefaultGetExpression(): IrExpression = fun IrVariable.load(): IrExpression =
IrGetVariableExpressionImpl(startOffset, endOffset, descriptor) IrGetVariableExpressionImpl(startOffset, endOffset, descriptor)
@@ -22,7 +22,7 @@ import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.psiUtil.endOffset import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.startOffset 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.IrValue
import org.jetbrains.kotlin.psi2ir.generators.values.createRematerializableValue import org.jetbrains.kotlin.psi2ir.generators.values.createRematerializableValue
import org.jetbrains.kotlin.psi2ir.toExpectedType import org.jetbrains.kotlin.psi2ir.toExpectedType
@@ -51,7 +51,7 @@ class IrCallGenerator(val irStatementGenerator: IrStatementGenerator) : IrGenera
} }
val irTmpVar = temporaryVariableFactory.createTemporaryVariable(irExpression, nameHint) val irTmpVar = temporaryVariableFactory.createTemporaryVariable(irExpression, nameHint)
putValue(ktExpression, IrTemporaryVariableValue(irTmpVar)) putValue(ktExpression, IrVariableValue(irTmpVar))
return irTmpVar return irTmpVar
} }
@@ -63,7 +63,7 @@ class IrCallGenerator(val irStatementGenerator: IrStatementGenerator) : IrGenera
} }
val irTmpVar = temporaryVariableFactory.createTemporaryVariable(irExpression, valueParameterDescriptor.name.asString()) val irTmpVar = temporaryVariableFactory.createTemporaryVariable(irExpression, valueParameterDescriptor.name.asString())
putValue(valueParameterDescriptor, IrTemporaryVariableValue(irTmpVar)) putValue(valueParameterDescriptor, IrVariableValue(irTmpVar))
return irTmpVar return irTmpVar
} }
@@ -21,64 +21,87 @@ import org.jetbrains.kotlin.ir.expressions.IrOperator
import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.lexer.KtTokens
fun getIrBinaryOperator(ktOperator: IElementType): IrOperator? =
KT_TOKEN_TO_IR_BINARY_OPERATOR[ktOperator]
internal fun getIrOperator(ktOperator: IElementType): IrOperator? = fun getIrPrefixOperator(ktOperator: IElementType): IrOperator? =
KT_TOKEN_TO_IR_OPERATOR[ktOperator] KT_TOKEN_TO_IR_PREFIX_OPERATOR[ktOperator]
internal val KT_TOKEN_TO_IR_OPERATOR = fun getIrPostfixOperator(ktOperator: IElementType): IrOperator? =
mapOf( KT_TOKEN_TO_IR_POSTFIX_OPERATOR[ktOperator]
KtTokens.EQ to IrOperator.EQ,
KtTokens.PLUSEQ to IrOperator.PLUSEQ, private val KT_TOKEN_TO_IR_BINARY_OPERATOR = mapOf(
KtTokens.MINUSEQ to IrOperator.MINUSEQ, KtTokens.EQ to IrOperator.EQ,
KtTokens.MULTEQ to IrOperator.MULTEQ,
KtTokens.DIVEQ to IrOperator.DIVEQ,
KtTokens.PERCEQ to IrOperator.PERCEQ,
KtTokens.PLUS to IrOperator.PLUS, KtTokens.PLUSEQ to IrOperator.PLUSEQ,
KtTokens.MINUS to IrOperator.MINUS, KtTokens.MINUSEQ to IrOperator.MINUSEQ,
KtTokens.MUL to IrOperator.MUL, KtTokens.MULTEQ to IrOperator.MULTEQ,
KtTokens.DIV to IrOperator.DIV, KtTokens.DIVEQ to IrOperator.DIVEQ,
KtTokens.PERC to IrOperator.PERC, KtTokens.PERCEQ to IrOperator.PERCEQ,
KtTokens.RANGE to IrOperator.RANGE,
KtTokens.LT to IrOperator.LT, KtTokens.PLUS to IrOperator.PLUS,
KtTokens.LTEQ to IrOperator.LTEQ, KtTokens.MINUS to IrOperator.MINUS,
KtTokens.GT to IrOperator.GT, KtTokens.MUL to IrOperator.MUL,
KtTokens.GTEQ to IrOperator.GTEQ, KtTokens.DIV to IrOperator.DIV,
KtTokens.PERC to IrOperator.PERC,
KtTokens.RANGE to IrOperator.RANGE,
KtTokens.EQEQ to IrOperator.EQEQ, KtTokens.LT to IrOperator.LT,
KtTokens.EXCLEQ to IrOperator.EXCLEQ, KtTokens.LTEQ to IrOperator.LTEQ,
KtTokens.GT to IrOperator.GT,
KtTokens.GTEQ to IrOperator.GTEQ,
KtTokens.EQEQEQ to IrOperator.EQEQEQ, KtTokens.EQEQ to IrOperator.EQEQ,
KtTokens.EXCLEQEQEQ to IrOperator.EXCLEQEQ, KtTokens.EXCLEQ to IrOperator.EXCLEQ,
KtTokens.IN_KEYWORD to IrOperator.IN, KtTokens.EQEQEQ to IrOperator.EQEQEQ,
KtTokens.NOT_IN to IrOperator.NOT_IN, KtTokens.EXCLEQEQEQ to IrOperator.EXCLEQEQ,
KtTokens.ANDAND to IrOperator.ANDAND, KtTokens.IN_KEYWORD to IrOperator.IN,
KtTokens.OROR to IrOperator.OROR, 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) 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) 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) setOf(IrOperator.LT, IrOperator.LTEQ, IrOperator.GT, IrOperator.GTEQ)
internal val EQUALITY_OPERATORS = val EQUALITY_OPERATORS =
setOf(IrOperator.EQEQ, IrOperator.EXCLEQ) setOf(IrOperator.EQEQ, IrOperator.EXCLEQ)
internal val IDENTITY_OPERATORS = val IDENTITY_OPERATORS =
setOf(IrOperator.EQEQEQ, IrOperator.EXCLEQEQ) setOf(IrOperator.EQEQEQ, IrOperator.EXCLEQEQ)
internal val IN_OPERATORS = val IN_OPERATORS =
setOf(IrOperator.IN, IrOperator.NOT_IN) setOf(IrOperator.IN, IrOperator.NOT_IN)
internal val BINARY_BOOLEAN_OPERATORS = val BINARY_BOOLEAN_OPERATORS =
setOf(IrOperator.ANDAND, IrOperator.OROR) 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)
@@ -18,15 +18,14 @@ package org.jetbrains.kotlin.psi2ir.generators
import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
import org.jetbrains.kotlin.ir.expressions.IrBinaryOperatorExpressionImpl import org.jetbrains.kotlin.ir.expressions.*
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.psi.KtArrayAccessExpression import org.jetbrains.kotlin.psi.KtArrayAccessExpression
import org.jetbrains.kotlin.psi.KtBinaryExpression import org.jetbrains.kotlin.psi.KtBinaryExpression
import org.jetbrains.kotlin.psi.KtExpression 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.endOffset
import org.jetbrains.kotlin.psi.psiUtil.startOffset 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.generators.values.*
import org.jetbrains.kotlin.psi2ir.toExpectedType import org.jetbrains.kotlin.psi2ir.toExpectedType
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
@@ -37,9 +36,20 @@ import org.jetbrains.kotlin.types.typeUtil.makeNullable
class IrOperatorExpressionGenerator(val irStatementGenerator: IrStatementGenerator): IrGenerator { class IrOperatorExpressionGenerator(val irStatementGenerator: IrStatementGenerator): IrGenerator {
override val context: IrGeneratorContext get() = irStatementGenerator.context 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 { fun generateBinaryExpression(expression: KtBinaryExpression): IrExpression {
val ktOperator = expression.operationReference.getReferencedNameElementType() val ktOperator = expression.operationReference.getReferencedNameElementType()
val irOperator = getIrOperator(ktOperator) val irOperator = getIrBinaryOperator(ktOperator)
return when (irOperator) { return when (irOperator) {
null -> createDummyExpression(expression, ktOperator.toString()) null -> createDummyExpression(expression, ktOperator.toString())
@@ -142,25 +152,42 @@ class IrOperatorExpressionGenerator(val irStatementGenerator: IrStatementGenerat
return IrCallGenerator(irStatementGenerator).generateCall(expression, operatorCall, irOperator) 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 { private fun generateAugmentedAssignment(expression: KtBinaryExpression, irOperator: IrOperator): IrExpression {
val ktLeft = expression.left!! val ktLeft = expression.left!!
val irLValue = generateLValue(ktLeft, irOperator)
val irLhs = generateLValue(ktLeft, irOperator) val operatorCall = getResolvedCall(expression)!!
val isSimpleAssignment = get(BindingContext.VARIABLE_REASSIGNMENT, expression) ?: false val isSimpleAssignment = get(BindingContext.VARIABLE_REASSIGNMENT, expression) ?: false
val operatorCall = getResolvedCall(expression)!! if (isSimpleAssignment && irLValue is IrLValueWithAugmentedStore) {
return irLValue.augmentedStore(operatorCall, irStatementGenerator.generateExpression(expression.right!!))
if (isSimpleAssignment && irLhs is IrLValueWithAugmentedStore) {
return irLhs.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) val irOpCall = opCallGenerator.generateCall(expression, operatorCall, irOperator)
return if (isSimpleAssignment) { return if (isSimpleAssignment) {
// Set( Op( Get(), RHS ) ) // Set( Op( Get(), RHS ) )
irLhs.store(irOpCall) irLValue.store(irOpCall)
} }
else { else {
// Op( Get(), RHS ) // Op( Get(), RHS )
@@ -171,8 +198,8 @@ class IrOperatorExpressionGenerator(val irStatementGenerator: IrStatementGenerat
private fun generateAssignment(expression: KtBinaryExpression): IrExpression { private fun generateAssignment(expression: KtBinaryExpression): IrExpression {
val ktLeft = expression.left!! val ktLeft = expression.left!!
val ktRight = expression.right!! val ktRight = expression.right!!
val lhsReference = generateLValue(ktLeft, IrOperator.EQ) val irLValue = generateLValue(ktLeft, IrOperator.EQ)
return lhsReference.store(irStatementGenerator.generateExpression(ktRight)) return irLValue.store(irStatementGenerator.generateExpression(ktRight))
} }
private fun generateLValue(ktLeft: KtExpression, irOperator: IrOperator?): IrLValue { 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 indexExpressions = ktLeft.indexExpressions.map { it to irStatementGenerator.generateExpression(it) }
val indexedGetCall = get(BindingContext.INDEXED_LVALUE_GET, ktLeft) val indexedGetCall = get(BindingContext.INDEXED_LVALUE_GET, ktLeft)
val indexedSetCall = get(BindingContext.INDEXED_LVALUE_SET, 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, return IrIndexedLValue(irStatementGenerator, ktLeft, irOperator,
irArrayValue, indexExpressions, indexedGetCall, indexedSetCall) irArrayValue, type, indexExpressions, indexedGetCall, indexedSetCall)
} }
val resolvedCall = getResolvedCall(ktLeft) ?: TODO("no resolved call for LHS") val resolvedCall = getResolvedCall(ktLeft) ?: TODO("no resolved call for LHS")
@@ -193,7 +223,7 @@ class IrOperatorExpressionGenerator(val irStatementGenerator: IrStatementGenerat
if (descriptor.isDelegated) if (descriptor.isDelegated)
TODO("Delegated local variable") TODO("Delegated local variable")
else else
IrVariableLValueValue(ktLeft, irOperator, descriptor) IrVariableValue(ktLeft.startOffset, ktLeft.endOffset, descriptor, irOperator)
is PropertyDescriptor -> is PropertyDescriptor ->
IrCallGenerator(irStatementGenerator).run { IrCallGenerator(irStatementGenerator).run {
IrPropertyLValueValue( IrPropertyLValueValue(
@@ -207,4 +237,5 @@ class IrOperatorExpressionGenerator(val irStatementGenerator: IrStatementGenerat
TODO("Other cases of LHS") TODO("Other cases of LHS")
} }
} }
} }
@@ -26,7 +26,7 @@ import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.endOffset import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.startOffset import org.jetbrains.kotlin.psi.psiUtil.startOffset
import org.jetbrains.kotlin.psi2ir.deparenthesize 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.psi2ir.toExpectedType
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.BindingContextUtils import org.jetbrains.kotlin.resolve.BindingContextUtils
@@ -79,7 +79,7 @@ class IrStatementGenerator(
irBlock.addStatement(irTmpInitializer) irBlock.addStatement(irTmpInitializer)
val irCallGenerator = IrCallGenerator(this) val irCallGenerator = IrCallGenerator(this)
irCallGenerator.putValue(ktInitializer, IrTemporaryVariableValue(irTmpInitializer)) irCallGenerator.putValue(ktInitializer, IrVariableValue(irTmpInitializer))
for ((index, ktEntry) in multiDeclaration.entries.withIndex()) { for ((index, ktEntry) in multiDeclaration.entries.withIndex()) {
val componentResolvedCall = getOrFail(BindingContext.COMPONENT_RESOLVED_CALL, ktEntry) val componentResolvedCall = getOrFail(BindingContext.COMPONENT_RESOLVED_CALL, ktEntry)
@@ -241,4 +241,7 @@ class IrStatementGenerator(
override fun visitBinaryExpression(expression: KtBinaryExpression, data: Nothing?): IrStatement = override fun visitBinaryExpression(expression: KtBinaryExpression, data: Nothing?): IrStatement =
IrOperatorExpressionGenerator(this).generateBinaryExpression(expression) IrOperatorExpressionGenerator(this).generateBinaryExpression(expression)
override fun visitPrefixExpression(expression: KtPrefixExpression, data: Nothing?): IrStatement =
IrOperatorExpressionGenerator(this).generatePrefixExpression(expression)
} }
@@ -21,15 +21,18 @@ import org.jetbrains.kotlin.psi.KtArrayAccessExpression
import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.psiUtil.endOffset import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.startOffset 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.IrCallGenerator
import org.jetbrains.kotlin.psi2ir.generators.IrStatementGenerator import org.jetbrains.kotlin.psi2ir.generators.IrStatementGenerator
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.types.KotlinType
class IrIndexedLValue( class IrIndexedLValue(
var irStatementGenerator: IrStatementGenerator, var irStatementGenerator: IrStatementGenerator,
val ktArrayAccessExpression: KtArrayAccessExpression, val ktArrayAccessExpression: KtArrayAccessExpression,
val irOperator: IrOperator?, val irOperator: IrOperator?,
val irArray: IrExpression, val irArray: IrExpression,
override val type: KotlinType?,
val indexValues: List<Pair<KtExpression, IrExpression>>, val indexValues: List<Pair<KtExpression, IrExpression>>,
val indexedGetCall: ResolvedCall<*>?, val indexedGetCall: ResolvedCall<*>?,
val indexedSetCall: ResolvedCall<*>? val indexedSetCall: ResolvedCall<*>?
@@ -37,50 +40,64 @@ class IrIndexedLValue(
override fun load(): IrExpression { override fun load(): IrExpression {
if (indexedGetCall == null) throw AssertionError("Indexed LValue has no 'get' call: ${ktArrayAccessExpression.text}") if (indexedGetCall == null) throw AssertionError("Indexed LValue has no 'get' call: ${ktArrayAccessExpression.text}")
val irBlock = IrBlockExpressionImpl(ktArrayAccessExpression.startOffset, ktArrayAccessExpression.endOffset, return generateGetOrSetCallAsDesugaredBlock(indexedGetCall)
indexedGetCall.resultingDescriptor.returnType,
hasResult = true, isDesugared = true)
val callGenerator = IrCallGenerator(irStatementGenerator)
defineContextVariables(irBlock, callGenerator)
irBlock.addStatement(callGenerator.generateCall(ktArrayAccessExpression, indexedGetCall, irOperator))
return irBlock
} }
override fun store(irExpression: IrExpression): IrExpression { override fun store(irExpression: IrExpression): IrExpression {
if (indexedSetCall == null) throw AssertionError("Indexed LValue has no 'set' call: ${ktArrayAccessExpression.text}") if (indexedSetCall == null) throw AssertionError("Indexed LValue has no 'set' call: ${ktArrayAccessExpression.text}")
val irBlock = IrBlockExpressionImpl(ktArrayAccessExpression.startOffset, ktArrayAccessExpression.endOffset, return generateGetOrSetCallAsDesugaredBlock(indexedSetCall)
indexedSetCall.resultingDescriptor.returnType, }
hasResult = true, isDesugared = true)
private fun generateGetOrSetCallAsDesugaredBlock(call: ResolvedCall<*>, irArgument: IrExpression? = null): IrExpression {
val callGenerator = IrCallGenerator(irStatementGenerator) 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 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 (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}") if (indexedSetCall == null) throw AssertionError("Indexed LValue has no 'set' call: ${ktArrayAccessExpression.text}")
val irBlock = IrBlockExpressionImpl(ktArrayAccessExpression.startOffset, ktArrayAccessExpression.endOffset, val callGenerator = IrCallGenerator(irStatementGenerator)
indexedSetCall.resultingDescriptor.returnType,
hasResult = true, isDesugared = true) 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) 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 val operatorCallReceiver = operatorCall.extensionReceiver ?: operatorCall.dispatchReceiver
callGenerator.putValue(operatorCallReceiver!!, callGenerator.putValue(operatorCallReceiver!!,
@@ -94,6 +111,16 @@ class IrIndexedLValue(
return irBlock 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) { private fun defineContextVariables(irBlock: IrBlockExpression, callGenerator: IrCallGenerator) {
irBlock.addIfNotNull(callGenerator.introduceTemporary(ktArrayAccessExpression.arrayExpression!!, irArray, "array")) irBlock.addIfNotNull(callGenerator.introduceTemporary(ktArrayAccessExpression.arrayExpression!!, irArray, "array"))
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.psiUtil.endOffset import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.startOffset import org.jetbrains.kotlin.psi.psiUtil.startOffset
import org.jetbrains.kotlin.psi2ir.toExpectedType import org.jetbrains.kotlin.psi2ir.toExpectedType
import org.jetbrains.kotlin.types.KotlinType
class IrPropertyLValueValue( class IrPropertyLValueValue(
val ktElement: KtElement, val ktElement: KtElement,
@@ -31,6 +32,9 @@ class IrPropertyLValueValue(
val extensionReceiver: IrExpression?, val extensionReceiver: IrExpression?,
val isSafe: Boolean val isSafe: Boolean
) : IrLValue { ) : IrLValue {
override val type: KotlinType?
get() = descriptor.type
private fun IrPropertyAccessExpression.setReceivers() = private fun IrPropertyAccessExpression.setReceivers() =
apply { apply {
dispatchReceiver = this@IrPropertyLValueValue.dispatchReceiver dispatchReceiver = this@IrPropertyLValueValue.dispatchReceiver
@@ -17,8 +17,14 @@
package org.jetbrains.kotlin.psi2ir.generators.values package org.jetbrains.kotlin.psi2ir.generators.values
import org.jetbrains.kotlin.ir.expressions.* 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? = fun createRematerializableValue(irExpression: IrExpression): IrRematerializableValue? =
when (irExpression) { when (irExpression) {
@@ -29,23 +35,23 @@ fun createRematerializableValue(irExpression: IrExpression): IrRematerializableV
else -> null else -> null
} }
class IrRematerializableLiteralValue(val irExpression: IrLiteralExpression<*>): IrRematerializableValue { class IrRematerializableLiteralValue(override val irExpression: IrLiteralExpression<*>): IrRematerializableValue {
override fun load(): IrExpression = override fun load(): IrExpression =
IrLiteralExpressionImpl(irExpression.startOffset, irExpression.endOffset, irExpression.type, IrLiteralExpressionImpl(irExpression.startOffset, irExpression.endOffset, irExpression.type,
irExpression.kind, irExpression.kind.valueOf(irExpression)) irExpression.kind, irExpression.kind.valueOf(irExpression))
} }
class IrRematerializableVariableValue(val irExpression: IrGetVariableExpression) : IrRematerializableValue { class IrRematerializableVariableValue(override val irExpression: IrGetVariableExpression) : IrRematerializableValue {
override fun load(): IrExpression = override fun load(): IrExpression =
IrGetVariableExpressionImpl(irExpression.startOffset, irExpression.endOffset, irExpression.descriptor) IrGetVariableExpressionImpl(irExpression.startOffset, irExpression.endOffset, irExpression.descriptor)
} }
class IrRematerializableExtensionReceiverValue(val irExpression: IrGetExtensionReceiverExpression) : IrRematerializableValue { class IrRematerializableExtensionReceiverValue(override val irExpression: IrGetExtensionReceiverExpression) : IrRematerializableValue {
override fun load(): IrExpression = override fun load(): IrExpression =
IrGetExtensionReceiverExpressionImpl(irExpression.startOffset, irExpression.endOffset, irExpression.type, irExpression.descriptor) 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 = override fun load(): IrExpression =
IrThisExpressionImpl(irExpression.startOffset, irExpression.endOffset, irExpression.type, irExpression.classDescriptor) IrThisExpressionImpl(irExpression.startOffset, irExpression.endOffset, irExpression.type, irExpression.classDescriptor)
} }
@@ -17,18 +17,13 @@
package org.jetbrains.kotlin.psi2ir.generators.values package org.jetbrains.kotlin.psi2ir.generators.values
import org.jetbrains.kotlin.ir.assertDetached import org.jetbrains.kotlin.ir.assertDetached
import org.jetbrains.kotlin.ir.declarations.IrVariable
import org.jetbrains.kotlin.ir.expressions.IrExpression 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.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.types.KotlinType
interface IrValue { interface IrValue {
fun load(): IrExpression fun load(): IrExpression
} val type: KotlinType?
class IrTemporaryVariableValue(val irVariable: IrVariable) : IrValue {
override fun load(): IrExpression =
irVariable.createDefaultGetExpression()
} }
class IrSingleExpressionValue(val irExpression: IrExpression) : IrValue { class IrSingleExpressionValue(val irExpression: IrExpression) : IrValue {
@@ -45,6 +40,8 @@ class IrSingleExpressionValue(val irExpression: IrExpression) : IrValue {
} }
else else
throw AssertionError("Single exprssion value is already instantiated") throw AssertionError("Single exprssion value is already instantiated")
override val type: KotlinType? get() = irExpression.type
} }
interface IrLValue : IrValue { interface IrLValue : IrValue {
@@ -52,6 +49,7 @@ interface IrLValue : IrValue {
} }
interface IrLValueWithAugmentedStore : IrLValue { interface IrLValueWithAugmentedStore : IrLValue {
fun augmentedStore(operatorCall: ResolvedCall<*>, irRhs: IrExpression): IrExpression fun prefixAugmentedStore(operatorCall: ResolvedCall<*>): IrExpression
fun augmentedStore(operatorCall: ResolvedCall<*>, irOperatorArgument: IrExpression): IrExpression
} }
@@ -17,29 +17,31 @@
package org.jetbrains.kotlin.psi2ir.generators.values package org.jetbrains.kotlin.psi2ir.generators.values
import org.jetbrains.kotlin.descriptors.VariableDescriptor 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.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrGetVariableExpressionImpl import org.jetbrains.kotlin.ir.expressions.IrGetVariableExpressionImpl
import org.jetbrains.kotlin.ir.expressions.IrOperator import org.jetbrains.kotlin.ir.expressions.IrOperator
import org.jetbrains.kotlin.ir.expressions.IrSetVariableExpressionImpl 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.psi2ir.toExpectedType
import org.jetbrains.kotlin.types.KotlinType
class IrVariableLValueValue( class IrVariableValue(
val ktElement: KtElement, val startOffset: Int,
val irOperator: IrOperator?, val endOffset: Int,
val descriptor: VariableDescriptor val descriptor: VariableDescriptor,
val irOperator: IrOperator? = null
) : IrLValue { ) : 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 = override fun load(): IrExpression =
IrGetVariableExpressionImpl( IrGetVariableExpressionImpl(startOffset, endOffset, descriptor, irOperator)
ktElement.startOffset, ktElement.endOffset,
descriptor, irOperator
)
override fun store(irExpression: IrExpression): IrExpression = override fun store(irExpression: IrExpression): IrExpression =
IrSetVariableExpressionImpl( IrSetVariableExpressionImpl(startOffset, endOffset, descriptor,
ktElement.startOffset, ktElement.endOffset, irExpression.toExpectedType(descriptor.type), irOperator)
descriptor, irExpression.toExpectedType(descriptor.type), irOperator
)
} }
@@ -20,10 +20,12 @@ abstract class IrOperator(val debugName: String) {
override fun toString(): String = debugName override fun toString(): String = debugName
object INVOKE : IrOperator("INVOKE") object INVOKE : IrOperator("INVOKE")
object PREFIX_INCR : IrOperator("PREFIX_INCR") object PREFIX_INCR : IrOperator("PREFIX_INCR")
object PREFIX_DECR : IrOperator("PREFIX_DECR") object PREFIX_DECR : IrOperator("PREFIX_DECR")
object POSTFIX_INCR : IrOperator("POSTFIX_INCR") object POSTFIX_INCR : IrOperator("POSTFIX_INCR")
object POSTFIX_DECR : IrOperator("POSTFIX_DECR") object POSTFIX_DECR : IrOperator("POSTFIX_DECR")
object UMINUS : IrOperator("UMINUS") object UMINUS : IrOperator("UMINUS")
object EXCL : IrOperator("EXCL") object EXCL : IrOperator("EXCL")
object EXCLEXCL : IrOperator("EXCLEXCL") object EXCLEXCL : IrOperator("EXCLEXCL")
+18
View File
@@ -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]
}
+81
View File
@@ -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=<no-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=<no-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=<no-type>
GET_VAR tmp1 type=kotlin.Int
GET_VAR tmp1 type=kotlin.Int
IrFunction public fun testProp(): kotlin.Unit
IrExpressionBody
BLOCK type=<no-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=<no-type>
$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=<no-type>
$value: GET_VAR tmp1 type=kotlin.Int
GET_VAR tmp1 type=kotlin.Int
IrFunction public fun testArray(): kotlin.Unit
IrExpressionBody
BLOCK type=<no-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
@@ -137,6 +137,12 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase {
doTest(fileName); 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") @TestMetadata("primitiveComparisons.kt")
public void testPrimitiveComparisons() throws Exception { public void testPrimitiveComparisons() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/primitiveComparisons.kt"); String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/primitiveComparisons.kt");