Prefix increment / decrement.
Refactor IrLValue.
This commit is contained in:
committed by
Dmitry Petrov
parent
68cdcfa853
commit
4a62a6b7c3
@@ -38,5 +38,5 @@ fun IrExpression.toExpectedType(expectedType: KotlinType?): IrExpression {
|
||||
)
|
||||
}
|
||||
|
||||
fun IrVariable.createDefaultGetExpression(): IrExpression =
|
||||
fun IrVariable.load(): IrExpression =
|
||||
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.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
|
||||
}
|
||||
|
||||
|
||||
+61
-38
@@ -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)
|
||||
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)
|
||||
+48
-17
@@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+5
-2
@@ -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)
|
||||
}
|
||||
|
||||
+50
-23
@@ -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<Pair<KtExpression, IrExpression>>,
|
||||
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"))
|
||||
|
||||
|
||||
+4
@@ -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
|
||||
|
||||
+11
-5
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
+17
-15
@@ -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)
|
||||
}
|
||||
@@ -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")
|
||||
|
||||
@@ -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]
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@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");
|
||||
|
||||
Reference in New Issue
Block a user