IR: augmented assignment for array access expressions
This commit is contained in:
committed by
Dmitry Petrov
parent
0a57eb8ea4
commit
d7412c449e
@@ -38,5 +38,5 @@ fun IrExpression.toExpectedType(expectedType: KotlinType?): IrExpression {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun IrVariable.implicitGetExpression(): IrExpression =
|
fun IrVariable.createDefaultGetExpression(): IrExpression =
|
||||||
IrGetVariableExpressionImpl(startOffset, endOffset, descriptor)
|
IrGetVariableExpressionImpl(startOffset, endOffset, descriptor)
|
||||||
+21
-8
@@ -17,6 +17,7 @@
|
|||||||
package org.jetbrains.kotlin.psi2ir.generators
|
package org.jetbrains.kotlin.psi2ir.generators
|
||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrVariable
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
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
|
||||||
@@ -35,7 +36,13 @@ class IrCallGenerator(
|
|||||||
|
|
||||||
private val expressionValues = HashMap<KtExpression, IrValue>()
|
private val expressionValues = HashMap<KtExpression, IrValue>()
|
||||||
private val receiverValues = HashMap<ReceiverValue, IrValue>()
|
private val receiverValues = HashMap<ReceiverValue, IrValue>()
|
||||||
private val valueArgumentValues = HashMap<ResolvedValueArgument, IrValue>()
|
private val valueArgumentValues = HashMap<ValueParameterDescriptor, IrValue>()
|
||||||
|
|
||||||
|
fun createTemporary(ktExpression: KtExpression, irExpression: IrExpression): IrVariable {
|
||||||
|
val irTmpVar = irStatementGenerator.declarationFactory.createTemporaryVariable(irExpression)
|
||||||
|
putValue(ktExpression, IrTemporaryVariableValue(irTmpVar))
|
||||||
|
return irTmpVar
|
||||||
|
}
|
||||||
|
|
||||||
fun putValue(ktExpression: KtExpression, irValue: IrValue) {
|
fun putValue(ktExpression: KtExpression, irValue: IrValue) {
|
||||||
expressionValues[ktExpression] = irValue
|
expressionValues[ktExpression] = irValue
|
||||||
@@ -45,7 +52,7 @@ class IrCallGenerator(
|
|||||||
receiverValues[receiver] = irValue
|
receiverValues[receiver] = irValue
|
||||||
}
|
}
|
||||||
|
|
||||||
fun putValue(valueArgument: ResolvedValueArgument, irValue: IrValue) {
|
fun putValue(valueArgument: ValueParameterDescriptor, irValue: IrValue) {
|
||||||
valueArgumentValues[valueArgument] = irValue
|
valueArgumentValues[valueArgument] = irValue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,9 +141,15 @@ class IrCallGenerator(
|
|||||||
hasResult = isUsedAsExpression(ktExpression),
|
hasResult = isUsedAsExpression(ktExpression),
|
||||||
isDesugared = true)
|
isDesugared = true)
|
||||||
|
|
||||||
|
val valueArgumentsToValueParameters = HashMap<ResolvedValueArgument, ValueParameterDescriptor>()
|
||||||
|
for ((index, valueArgument) in resolvedCall.valueArgumentsByIndex!!.withIndex()) {
|
||||||
|
val valueParameter = resolvedCall.resultingDescriptor.valueParameters[index]
|
||||||
|
valueArgumentsToValueParameters[valueArgument] = valueParameter
|
||||||
|
}
|
||||||
|
|
||||||
val temporariesForValueArguments = HashMap<ResolvedValueArgument, Pair<VariableDescriptor, IrExpression>>()
|
val temporariesForValueArguments = HashMap<ResolvedValueArgument, Pair<VariableDescriptor, IrExpression>>()
|
||||||
for (valueArgument in valueArgumentsInEvaluationOrder) {
|
for (valueArgument in valueArgumentsInEvaluationOrder) {
|
||||||
val irArgument = generateValueArgument(valueArgument) ?: continue
|
val irArgument = generateValueArgument(valueArgument, valueArgumentsToValueParameters[valueArgument]!!) ?: continue
|
||||||
val irTemporary = irStatementGenerator.declarationFactory.createTemporaryVariable(irArgument)
|
val irTemporary = irStatementGenerator.declarationFactory.createTemporaryVariable(irArgument)
|
||||||
temporariesForValueArguments[valueArgument] = Pair(irTemporary.descriptor, irArgument)
|
temporariesForValueArguments[valueArgument] = Pair(irTemporary.descriptor, irArgument)
|
||||||
irBlock.addStatement(irTemporary)
|
irBlock.addStatement(irTemporary)
|
||||||
@@ -187,17 +200,17 @@ class IrCallGenerator(
|
|||||||
|
|
||||||
fun generateValueArgument(valueArgument: ResolvedValueArgument, valueParameterDescriptor: ValueParameterDescriptor): IrExpression? =
|
fun generateValueArgument(valueArgument: ResolvedValueArgument, valueParameterDescriptor: ValueParameterDescriptor): IrExpression? =
|
||||||
if (valueParameterDescriptor.varargElementType != null) {
|
if (valueParameterDescriptor.varargElementType != null) {
|
||||||
generateValueArgument(valueArgument)
|
doGenerateValueArgument(valueArgument, valueParameterDescriptor)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
generateValueArgument(valueArgument)?.toExpectedType(valueParameterDescriptor.type)
|
doGenerateValueArgument(valueArgument, valueParameterDescriptor)?.toExpectedType(valueParameterDescriptor.type)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun generateValueArgument(valueArgument: ResolvedValueArgument): IrExpression? =
|
private fun doGenerateValueArgument(valueArgument: ResolvedValueArgument, valueParameterDescriptor: ValueParameterDescriptor): IrExpression? =
|
||||||
if (valueArgument is DefaultValueArgument)
|
if (valueArgument is DefaultValueArgument)
|
||||||
null
|
null
|
||||||
else
|
else
|
||||||
valueArgumentValues[valueArgument]?.load() ?: doGenerateValueArgument(valueArgument)
|
valueArgumentValues[valueParameterDescriptor]?.load() ?: doGenerateValueArgument(valueArgument)
|
||||||
|
|
||||||
|
|
||||||
private fun doGenerateValueArgument(valueArgument: ResolvedValueArgument): IrExpression? =
|
private fun doGenerateValueArgument(valueArgument: ResolvedValueArgument): IrExpression? =
|
||||||
@@ -205,7 +218,7 @@ class IrCallGenerator(
|
|||||||
is ExpressionValueArgument ->
|
is ExpressionValueArgument ->
|
||||||
generateExpression(valueArgument.valueArgument!!.getArgumentExpression()!!)
|
generateExpression(valueArgument.valueArgument!!.getArgumentExpression()!!)
|
||||||
is VarargValueArgument ->
|
is VarargValueArgument ->
|
||||||
TODO("vararg")
|
createDummyExpression(valueArgument.arguments[0].getArgumentExpression()!!, "vararg")
|
||||||
else ->
|
else ->
|
||||||
TODO("Unexpected valueArgument: ${valueArgument.javaClass.simpleName}")
|
TODO("Unexpected valueArgument: ${valueArgument.javaClass.simpleName}")
|
||||||
}
|
}
|
||||||
|
|||||||
+23
-10
@@ -22,12 +22,11 @@ import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
|
|||||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrOperator
|
import org.jetbrains.kotlin.ir.expressions.IrOperator
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
|
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.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.calls.callUtil.isSafeCall
|
import org.jetbrains.kotlin.resolve.calls.callUtil.isSafeCall
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
|
||||||
|
|
||||||
val KT_OPERATOR_TO_IR_OPERATOR = hashMapOf(
|
val KT_OPERATOR_TO_IR_OPERATOR = hashMapOf(
|
||||||
KtTokens.PLUSEQ to IrOperator.PLUSEQ,
|
KtTokens.PLUSEQ to IrOperator.PLUSEQ,
|
||||||
@@ -54,18 +53,22 @@ class IrOperatorExpressionGenerator(val irStatementGenerator: IrStatementGenerat
|
|||||||
val ktLeft = expression.left!!
|
val ktLeft = expression.left!!
|
||||||
|
|
||||||
val irOperator = getIrOperator(ktOperator)
|
val irOperator = getIrOperator(ktOperator)
|
||||||
val lhs = generateReferenceForAssignmentLhs(ktLeft, irOperator)
|
val irLhs = generateLValue(ktLeft, irOperator)
|
||||||
|
|
||||||
val isSimpleAssignment = get(BindingContext.VARIABLE_REASSIGNMENT, expression) ?: false
|
val isSimpleAssignment = get(BindingContext.VARIABLE_REASSIGNMENT, expression) ?: false
|
||||||
|
|
||||||
val operatorCall = getResolvedCall(expression)!!
|
val operatorCall = getResolvedCall(expression)!!
|
||||||
|
|
||||||
val opCallGenerator = IrCallGenerator(irStatementGenerator).apply { putValue(ktLeft, lhs) }
|
if (isSimpleAssignment && irLhs is IrLValueWithAugmentedStore) {
|
||||||
|
return irLhs.augmentedStore(operatorCall, irStatementGenerator.generateExpression(expression.right!!))
|
||||||
|
}
|
||||||
|
|
||||||
|
val opCallGenerator = IrCallGenerator(irStatementGenerator).apply { putValue(ktLeft, irLhs) }
|
||||||
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 ) )
|
||||||
lhs.store(irOpCall)
|
irLhs.store(irOpCall)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Op( Get(), RHS )
|
// Op( Get(), RHS )
|
||||||
@@ -80,11 +83,22 @@ 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 = generateReferenceForAssignmentLhs(ktLeft, IrOperator.EQ)
|
val lhsReference = generateLValue(ktLeft, IrOperator.EQ)
|
||||||
return lhsReference.store(irStatementGenerator.generateExpression(ktRight))
|
return lhsReference.store(irStatementGenerator.generateExpression(ktRight))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun generateReferenceForAssignmentLhs(ktLeft: KtExpression, irOperator: IrOperator?): IrReference {
|
private fun generateLValue(ktLeft: KtExpression, irOperator: IrOperator?): IrLValue {
|
||||||
|
if (ktLeft is KtArrayAccessExpression) {
|
||||||
|
val irArrayValue = IrGenerateExpressionValue(irStatementGenerator, ktLeft.arrayExpression!!)
|
||||||
|
val indexExpressions = ktLeft.indexExpressions.map {
|
||||||
|
it to IrGenerateExpressionValue(irStatementGenerator, it)
|
||||||
|
}
|
||||||
|
val indexedGetCall = get(BindingContext.INDEXED_LVALUE_GET, ktLeft)
|
||||||
|
val indexedSetCall = get(BindingContext.INDEXED_LVALUE_SET, ktLeft)
|
||||||
|
return IrIndexedLValue(irStatementGenerator, ktLeft, irOperator,
|
||||||
|
irArrayValue, indexExpressions, indexedGetCall, indexedSetCall)
|
||||||
|
}
|
||||||
|
|
||||||
val resolvedCall = getResolvedCall(ktLeft) ?: TODO("no resolved call for LHS")
|
val resolvedCall = getResolvedCall(ktLeft) ?: TODO("no resolved call for LHS")
|
||||||
val descriptor = resolvedCall.candidateDescriptor
|
val descriptor = resolvedCall.candidateDescriptor
|
||||||
|
|
||||||
@@ -93,10 +107,10 @@ class IrOperatorExpressionGenerator(val irStatementGenerator: IrStatementGenerat
|
|||||||
if (descriptor.isDelegated)
|
if (descriptor.isDelegated)
|
||||||
TODO("Delegated local variable")
|
TODO("Delegated local variable")
|
||||||
else
|
else
|
||||||
IrVariableReferenceValue(ktLeft, irOperator, descriptor)
|
IrVariableLValueValue(ktLeft, irOperator, descriptor)
|
||||||
is PropertyDescriptor ->
|
is PropertyDescriptor ->
|
||||||
IrCallGenerator(irStatementGenerator).run {
|
IrCallGenerator(irStatementGenerator).run {
|
||||||
IrPropertyReferenceValue(
|
IrPropertyLValueValue(
|
||||||
ktLeft, irOperator, descriptor,
|
ktLeft, irOperator, descriptor,
|
||||||
generateReceiver(ktLeft, resolvedCall.dispatchReceiver, descriptor.dispatchReceiverParameter),
|
generateReceiver(ktLeft, resolvedCall.dispatchReceiver, descriptor.dispatchReceiverParameter),
|
||||||
generateReceiver(ktLeft, resolvedCall.extensionReceiver, descriptor.extensionReceiverParameter),
|
generateReceiver(ktLeft, resolvedCall.extensionReceiver, descriptor.extensionReceiverParameter),
|
||||||
@@ -107,5 +121,4 @@ class IrOperatorExpressionGenerator(val irStatementGenerator: IrStatementGenerat
|
|||||||
TODO("Other cases of LHS")
|
TODO("Other cases of LHS")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-4
@@ -24,7 +24,6 @@ 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.implicitGetExpression
|
|
||||||
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
|
||||||
@@ -73,11 +72,11 @@ class IrStatementGenerator(
|
|||||||
val irBlock = IrBlockExpressionImpl(multiDeclaration.startOffset, multiDeclaration.endOffset, null,
|
val irBlock = IrBlockExpressionImpl(multiDeclaration.startOffset, multiDeclaration.endOffset, null,
|
||||||
hasResult = false, isDesugared = true)
|
hasResult = false, isDesugared = true)
|
||||||
val ktInitializer = multiDeclaration.initializer!!
|
val ktInitializer = multiDeclaration.initializer!!
|
||||||
val irInitializerVal = declarationFactory.createTemporaryVariable(ktInitializer.genExpr())
|
val irTmpInitializer = declarationFactory.createTemporaryVariable(ktInitializer.genExpr())
|
||||||
irBlock.addStatement(irInitializerVal)
|
irBlock.addStatement(irTmpInitializer)
|
||||||
|
|
||||||
val irCallGenerator = IrCallGenerator(this)
|
val irCallGenerator = IrCallGenerator(this)
|
||||||
irCallGenerator.putValue(ktInitializer, justExpressionValue { irInitializerVal.implicitGetExpression() })
|
irCallGenerator.putValue(ktInitializer, IrTemporaryVariableValue(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)
|
||||||
|
|||||||
@@ -18,55 +18,74 @@ package org.jetbrains.kotlin.psi2ir.generators
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||||
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.*
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
|
import org.jetbrains.kotlin.psi.KtArrayAccessExpression
|
||||||
import org.jetbrains.kotlin.psi.KtElement
|
import org.jetbrains.kotlin.psi.KtElement
|
||||||
|
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.createDefaultGetExpression
|
||||||
import org.jetbrains.kotlin.psi2ir.toExpectedType
|
import org.jetbrains.kotlin.psi2ir.toExpectedType
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||||
|
|
||||||
interface IrValue {
|
interface IrValue {
|
||||||
fun load(): IrExpression
|
fun load(): IrExpression
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun justExpressionValue(crossinline makeExpression: () -> IrExpression) =
|
inline fun onDemandExpressionValue(crossinline makeExpression: () -> IrExpression) =
|
||||||
object : IrValue {
|
object : IrValue {
|
||||||
override fun load() = makeExpression()
|
override fun load() = makeExpression()
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IrReference : IrValue {
|
class IrTemporaryVariableValue(val irVariable: IrVariable) : IrValue {
|
||||||
fun store(value: IrExpression): IrExpression
|
override fun load(): IrExpression =
|
||||||
|
irVariable.createDefaultGetExpression()
|
||||||
}
|
}
|
||||||
|
|
||||||
class IrVariableReferenceValue(
|
class IrGenerateExpressionValue(val irStatementGenerator: IrStatementGenerator, val ktExpression: KtExpression) : IrValue {
|
||||||
|
override fun load(): IrExpression =
|
||||||
|
irStatementGenerator.generateExpression(ktExpression)
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IrLValue : IrValue {
|
||||||
|
fun store(irExpression: IrExpression): IrExpression
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IrLValueWithAugmentedStore : IrLValue {
|
||||||
|
fun augmentedStore(operatorCall: ResolvedCall<*>, irRhs: IrExpression): IrExpression
|
||||||
|
}
|
||||||
|
|
||||||
|
class IrVariableLValueValue(
|
||||||
val ktElement: KtElement,
|
val ktElement: KtElement,
|
||||||
val irOperator: IrOperator?,
|
val irOperator: IrOperator?,
|
||||||
val descriptor: VariableDescriptor
|
val descriptor: VariableDescriptor
|
||||||
) : IrReference {
|
) : IrLValue {
|
||||||
override fun load(): IrExpression =
|
override fun load(): IrExpression =
|
||||||
IrGetVariableExpressionImpl(
|
IrGetVariableExpressionImpl(
|
||||||
ktElement.startOffset, ktElement.endOffset,
|
ktElement.startOffset, ktElement.endOffset,
|
||||||
descriptor, irOperator
|
descriptor, irOperator
|
||||||
)
|
)
|
||||||
|
|
||||||
override fun store(value: IrExpression): IrExpression =
|
override fun store(irExpression: IrExpression): IrExpression =
|
||||||
IrSetVariableExpressionImpl(
|
IrSetVariableExpressionImpl(
|
||||||
ktElement.startOffset, ktElement.endOffset,
|
ktElement.startOffset, ktElement.endOffset,
|
||||||
descriptor, value.toExpectedType(descriptor.type), irOperator
|
descriptor, irExpression.toExpectedType(descriptor.type), irOperator
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
class IrPropertyReferenceValue(
|
class IrPropertyLValueValue(
|
||||||
val ktElement: KtElement,
|
val ktElement: KtElement,
|
||||||
val irOperator: IrOperator?,
|
val irOperator: IrOperator?,
|
||||||
val descriptor: PropertyDescriptor,
|
val descriptor: PropertyDescriptor,
|
||||||
val dispatchReceiver: IrExpression?,
|
val dispatchReceiver: IrExpression?,
|
||||||
val extensionReceiver: IrExpression?,
|
val extensionReceiver: IrExpression?,
|
||||||
val isSafe: Boolean
|
val isSafe: Boolean
|
||||||
) : IrReference {
|
) : IrLValue {
|
||||||
private fun IrPropertyAccessExpression.setReceivers() =
|
private fun IrPropertyAccessExpression.setReceivers() =
|
||||||
apply {
|
apply {
|
||||||
dispatchReceiver = this@IrPropertyReferenceValue.dispatchReceiver
|
dispatchReceiver = this@IrPropertyLValueValue.dispatchReceiver
|
||||||
extensionReceiver = this@IrPropertyReferenceValue.extensionReceiver
|
extensionReceiver = this@IrPropertyLValueValue.extensionReceiver
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun load(): IrExpression =
|
override fun load(): IrExpression =
|
||||||
@@ -75,9 +94,88 @@ class IrPropertyReferenceValue(
|
|||||||
descriptor.type, isSafe, descriptor, irOperator
|
descriptor.type, isSafe, descriptor, irOperator
|
||||||
).setReceivers()
|
).setReceivers()
|
||||||
|
|
||||||
override fun store(value: IrExpression): IrExpression =
|
override fun store(irExpression: IrExpression): IrExpression =
|
||||||
IrSetPropertyExpressionImpl(
|
IrSetPropertyExpressionImpl(
|
||||||
ktElement.startOffset, ktElement.endOffset,
|
ktElement.startOffset, ktElement.endOffset,
|
||||||
isSafe, descriptor, value.toExpectedType(descriptor.type), irOperator
|
isSafe, descriptor, irExpression.toExpectedType(descriptor.type), irOperator
|
||||||
).setReceivers()
|
).setReceivers()
|
||||||
|
}
|
||||||
|
|
||||||
|
class IrIndexedLValue(
|
||||||
|
var irStatementGenerator: IrStatementGenerator,
|
||||||
|
val ktArrayAccessExpression: KtArrayAccessExpression,
|
||||||
|
val irOperator: IrOperator?,
|
||||||
|
val arrayValue: IrValue,
|
||||||
|
val indexValues: List<Pair<KtExpression, IrValue>>,
|
||||||
|
val indexedGetCall: ResolvedCall<*>?,
|
||||||
|
val indexedSetCall: ResolvedCall<*>?
|
||||||
|
) : IrLValueWithAugmentedStore {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
val callGenerator = IrCallGenerator(irStatementGenerator)
|
||||||
|
|
||||||
|
defineContextVariables(irBlock, callGenerator)
|
||||||
|
|
||||||
|
callGenerator.putValue(indexedSetCall.resultingDescriptor.valueParameters.last(),
|
||||||
|
onDemandExpressionValue { irExpression })
|
||||||
|
|
||||||
|
irBlock.addStatement(callGenerator.generateCall(ktArrayAccessExpression, indexedSetCall, irOperator))
|
||||||
|
|
||||||
|
return irBlock
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun augmentedStore(operatorCall: ResolvedCall<*>, irRhs: 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 irBlock = IrBlockExpressionImpl(ktArrayAccessExpression.startOffset, ktArrayAccessExpression.endOffset,
|
||||||
|
indexedSetCall.resultingDescriptor.returnType,
|
||||||
|
hasResult = true, isDesugared = true)
|
||||||
|
|
||||||
|
val callGenerator = IrCallGenerator(irStatementGenerator)
|
||||||
|
|
||||||
|
defineContextVariables(irBlock, callGenerator)
|
||||||
|
|
||||||
|
callGenerator.putValue(operatorCall.resultingDescriptor.valueParameters[0], onDemandExpressionValue { irRhs })
|
||||||
|
|
||||||
|
val operatorCallReceiver = operatorCall.extensionReceiver ?: operatorCall.dispatchReceiver
|
||||||
|
callGenerator.putValue(operatorCallReceiver!!,
|
||||||
|
onDemandExpressionValue { callGenerator.generateCall(ktArrayAccessExpression, indexedGetCall, irOperator) })
|
||||||
|
|
||||||
|
callGenerator.putValue(indexedSetCall.resultingDescriptor.valueParameters.last(),
|
||||||
|
onDemandExpressionValue { callGenerator.generateCall(ktArrayAccessExpression, operatorCall, irOperator) })
|
||||||
|
|
||||||
|
irBlock.addStatement(callGenerator.generateCall(ktArrayAccessExpression, indexedSetCall, irOperator))
|
||||||
|
|
||||||
|
return irBlock
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun defineContextVariables(irBlock: IrBlockExpression, callGenerator: IrCallGenerator) {
|
||||||
|
irBlock.addStatement(callGenerator.createTemporary(ktArrayAccessExpression.arrayExpression!!, arrayValue.load()))
|
||||||
|
|
||||||
|
for ((ktIndexExpression, irIndexValue) in indexValues) {
|
||||||
|
irBlock.addStatement(callGenerator.createTemporary(ktIndexExpression, irIndexValue.load()))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -18,11 +18,7 @@ package org.jetbrains.kotlin.ir
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.codegen.CodegenTestCase
|
import org.jetbrains.kotlin.codegen.CodegenTestCase
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrModuleImpl
|
|
||||||
import org.jetbrains.kotlin.psi2ir.Psi2IrTranslator
|
import org.jetbrains.kotlin.psi2ir.Psi2IrTranslator
|
||||||
import org.jetbrains.kotlin.psi2ir.generators.IrGeneratorContext
|
|
||||||
import org.jetbrains.kotlin.psi2ir.generators.IrModuleGenerator
|
|
||||||
import org.jetbrains.kotlin.psi2ir.transformations.collapseDesugaredBlocks
|
|
||||||
import org.jetbrains.kotlin.resolve.AnalyzingUtils
|
import org.jetbrains.kotlin.resolve.AnalyzingUtils
|
||||||
import org.jetbrains.kotlin.resolve.lazy.JvmResolveUtil
|
import org.jetbrains.kotlin.resolve.lazy.JvmResolveUtil
|
||||||
import org.jetbrains.kotlin.test.ConfigurationKind
|
import org.jetbrains.kotlin.test.ConfigurationKind
|
||||||
|
|||||||
@@ -50,7 +50,8 @@ fun <T : IrElement?> T.detach(): T {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun IrElement.replaceWith(otherElement: IrElement) {
|
fun IrElement.replaceWith(otherElement: IrElement) {
|
||||||
parent?.run { replaceChild(slot, otherElement.detach()) } ?: throw AssertionError("Can't replace a non-root element $this")
|
val parent = this.parent ?: throw AssertionError("Can't replace a non-root element $this")
|
||||||
|
parent.replaceChild(slot, otherElement.detach())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun IrElement.assertChild(child: IrElement) {
|
fun IrElement.assertChild(child: IrElement) {
|
||||||
|
|||||||
@@ -48,7 +48,9 @@ class IrCallExpressionImpl(
|
|||||||
argumentsByParameterIndex[index]
|
argumentsByParameterIndex[index]
|
||||||
|
|
||||||
override fun putArgument(index: Int, valueArgument: IrExpression?) {
|
override fun putArgument(index: Int, valueArgument: IrExpression?) {
|
||||||
if (index >= argumentsByParameterIndex.size) throw AssertionError("$this: No such argument slot: $index")
|
if (index >= argumentsByParameterIndex.size) {
|
||||||
|
throw AssertionError("$this: No such argument slot: $index")
|
||||||
|
}
|
||||||
valueArgument?.assertDetached()
|
valueArgument?.assertDetached()
|
||||||
argumentsByParameterIndex[index]?.detach()
|
argumentsByParameterIndex[index]?.detach()
|
||||||
argumentsByParameterIndex[index] = valueArgument
|
argumentsByParameterIndex[index] = valueArgument
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ import org.jetbrains.kotlin.renderer.DescriptorRendererModifier
|
|||||||
import org.jetbrains.kotlin.renderer.OverrideRenderingPolicy
|
import org.jetbrains.kotlin.renderer.OverrideRenderingPolicy
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
|
||||||
|
fun IrElement.render() = accept(RenderIrElementVisitor(), null)
|
||||||
|
|
||||||
class RenderIrElementVisitor : IrElementVisitor<String, Nothing?> {
|
class RenderIrElementVisitor : IrElementVisitor<String, Nothing?> {
|
||||||
override fun visitElement(element: IrElement, data: Nothing?): String =
|
override fun visitElement(element: IrElement, data: Nothing?): String =
|
||||||
"? ${element.javaClass.simpleName}"
|
"? ${element.javaClass.simpleName}"
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2016 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.ir.util
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||||
|
|
||||||
|
inline fun IrElement.validateTree(crossinline onFailBody: (IrElement, IrElement) -> Unit) {
|
||||||
|
accept(object : IrTreeValidationVisitor() {
|
||||||
|
override fun onFail(irElement: IrElement, expectedParent: IrElement) {
|
||||||
|
onFailBody(irElement, expectedParent)
|
||||||
|
}
|
||||||
|
}, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class IrTreeValidationVisitor : IrElementVisitor<Unit, IrElement?> {
|
||||||
|
override fun visitElement(element: IrElement, data: IrElement?) {
|
||||||
|
if (data != null && element.parent != data) {
|
||||||
|
onFail(element, data)
|
||||||
|
}
|
||||||
|
element.acceptChildren(this, element)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract fun onFail(irElement: IrElement, expectedParent: IrElement)
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
// <<< arrayAssignment.txt
|
||||||
|
fun test() {
|
||||||
|
val x = intArrayOf(1, 2, 3)
|
||||||
|
x[1] = 0
|
||||||
|
}
|
||||||
+15
@@ -0,0 +1,15 @@
|
|||||||
|
IrFile /arrayAssignment.kt
|
||||||
|
IrFunction public fun test(): kotlin.Unit
|
||||||
|
IrExpressionBody
|
||||||
|
BLOCK type=<no-type> hasResult=false isDesugared=false
|
||||||
|
VAR val x: kotlin.IntArray
|
||||||
|
CALL .intArrayOf type=kotlin.IntArray operator=
|
||||||
|
elements: DUMMY vararg type=kotlin.Int
|
||||||
|
VAR val tmp0: kotlin.IntArray
|
||||||
|
GET_VAR x type=kotlin.IntArray
|
||||||
|
VAR val tmp1: kotlin.Int
|
||||||
|
LITERAL Int type=kotlin.Int value='1'
|
||||||
|
CALL .set type=kotlin.Unit operator=EQ
|
||||||
|
$this: GET_VAR tmp0 type=kotlin.IntArray
|
||||||
|
index: GET_VAR tmp1 type=kotlin.Int
|
||||||
|
value: LITERAL Int type=kotlin.Int value='0'
|
||||||
+17
-4
@@ -1,6 +1,19 @@
|
|||||||
// <<< augmentedAssignment1.txt
|
// <<< augmentedAssignment1.txt
|
||||||
fun test(): Int {
|
var p = 0
|
||||||
|
|
||||||
|
fun testVariable() {
|
||||||
var x = 0
|
var x = 0
|
||||||
x += 10
|
x += 1
|
||||||
return x
|
x -= 2
|
||||||
}
|
x *= 3
|
||||||
|
x /= 4
|
||||||
|
x %= 5
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testProperty() {
|
||||||
|
p += 1
|
||||||
|
p -= 2
|
||||||
|
p *= 3
|
||||||
|
p /= 4
|
||||||
|
p %= 5
|
||||||
|
}
|
||||||
|
|||||||
+45
-5
@@ -1,12 +1,52 @@
|
|||||||
IrFile /augmentedAssignment1.kt
|
IrFile /augmentedAssignment1.kt
|
||||||
IrFunction public fun test(): kotlin.Int
|
IrProperty public var p: kotlin.Int getter=null setter=null
|
||||||
IrExpressionBody
|
IrExpressionBody
|
||||||
BLOCK type=<no-type> hasResult=false isDesugared=false
|
LITERAL Int type=kotlin.Int value='0'
|
||||||
|
IrFunction public fun testVariable(): kotlin.Unit
|
||||||
|
IrExpressionBody
|
||||||
|
BLOCK type=kotlin.Int hasResult=true isDesugared=false
|
||||||
VAR var x: kotlin.Int
|
VAR var x: kotlin.Int
|
||||||
LITERAL Int type=kotlin.Int value='0'
|
LITERAL Int type=kotlin.Int value='0'
|
||||||
SET_VAR x type=<no-type>
|
SET_VAR x type=<no-type>
|
||||||
CALL .plus type=kotlin.Int operator=PLUSEQ
|
CALL .plus type=kotlin.Int operator=PLUSEQ
|
||||||
$this: GET_VAR x type=kotlin.Int
|
$this: GET_VAR x type=kotlin.Int
|
||||||
other: LITERAL Int type=kotlin.Int value='10'
|
other: LITERAL Int type=kotlin.Int value='1'
|
||||||
RETURN type=<no-type>
|
SET_VAR x type=<no-type>
|
||||||
GET_VAR x type=kotlin.Int
|
CALL .minus type=kotlin.Int operator=MINUSEQ
|
||||||
|
$this: GET_VAR x type=kotlin.Int
|
||||||
|
other: LITERAL Int type=kotlin.Int value='2'
|
||||||
|
SET_VAR x type=<no-type>
|
||||||
|
CALL .times type=kotlin.Int operator=MULTEQ
|
||||||
|
$this: GET_VAR x type=kotlin.Int
|
||||||
|
other: LITERAL Int type=kotlin.Int value='3'
|
||||||
|
SET_VAR x type=<no-type>
|
||||||
|
CALL .div type=kotlin.Int operator=DIVEQ
|
||||||
|
$this: GET_VAR x type=kotlin.Int
|
||||||
|
other: LITERAL Int type=kotlin.Int value='4'
|
||||||
|
SET_VAR x type=<no-type>
|
||||||
|
CALL .mod type=kotlin.Int operator=PERCEQ
|
||||||
|
$this: GET_VAR x type=kotlin.Int
|
||||||
|
other: LITERAL Int type=kotlin.Int value='5'
|
||||||
|
IrFunction public fun testProperty(): kotlin.Unit
|
||||||
|
IrExpressionBody
|
||||||
|
BLOCK type=kotlin.Int hasResult=true isDesugared=false
|
||||||
|
SET_PROPERTY .ptype=<no-type>
|
||||||
|
$value: CALL .plus type=kotlin.Int operator=PLUSEQ
|
||||||
|
$this: GET_PROPERTY .p type=kotlin.Int
|
||||||
|
other: LITERAL Int type=kotlin.Int value='1'
|
||||||
|
SET_PROPERTY .ptype=<no-type>
|
||||||
|
$value: CALL .minus type=kotlin.Int operator=MINUSEQ
|
||||||
|
$this: GET_PROPERTY .p type=kotlin.Int
|
||||||
|
other: LITERAL Int type=kotlin.Int value='2'
|
||||||
|
SET_PROPERTY .ptype=<no-type>
|
||||||
|
$value: CALL .times type=kotlin.Int operator=MULTEQ
|
||||||
|
$this: GET_PROPERTY .p type=kotlin.Int
|
||||||
|
other: LITERAL Int type=kotlin.Int value='3'
|
||||||
|
SET_PROPERTY .ptype=<no-type>
|
||||||
|
$value: CALL .div type=kotlin.Int operator=DIVEQ
|
||||||
|
$this: GET_PROPERTY .p type=kotlin.Int
|
||||||
|
other: LITERAL Int type=kotlin.Int value='4'
|
||||||
|
SET_PROPERTY .ptype=<no-type>
|
||||||
|
$value: CALL .mod type=kotlin.Int operator=PERCEQ
|
||||||
|
$this: GET_PROPERTY .p type=kotlin.Int
|
||||||
|
other: LITERAL Int type=kotlin.Int value='5'
|
||||||
|
|||||||
+22
-2
@@ -1,8 +1,28 @@
|
|||||||
|
// <<< augmentedAssignment2.txt
|
||||||
|
|
||||||
class A
|
class A
|
||||||
|
|
||||||
operator fun A.plusAssign(s: String) {}
|
operator fun A.plusAssign(s: String) {}
|
||||||
|
operator fun A.minusAssign(s: String) {}
|
||||||
|
operator fun A.timesAssign(s: String) {}
|
||||||
|
operator fun A.divAssign(s: String) {}
|
||||||
|
operator fun A.modAssign(s: String) {}
|
||||||
|
|
||||||
fun test() { // <<< augmentedAssignment2.txt
|
val p = A()
|
||||||
|
|
||||||
|
fun testVariable() {
|
||||||
val a = A()
|
val a = A()
|
||||||
a += ""
|
a += "+="
|
||||||
|
a -= "-="
|
||||||
|
a *= "*="
|
||||||
|
a /= "/="
|
||||||
|
a %= "*="
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testProperty() {
|
||||||
|
p += "+="
|
||||||
|
p -= "-="
|
||||||
|
p *= "*="
|
||||||
|
p /= "/="
|
||||||
|
p %= "*="
|
||||||
}
|
}
|
||||||
|
|||||||
+58
-8
@@ -1,8 +1,58 @@
|
|||||||
IrFunction public fun test(): kotlin.Unit
|
IrFile /augmentedAssignment2.kt
|
||||||
IrExpressionBody
|
DUMMY A
|
||||||
BLOCK type=<no-type> hasResult=false isDesugared=false
|
IrFunction public operator fun A.plusAssign(/*0*/ s: kotlin.String): kotlin.Unit
|
||||||
VAR val a: A
|
IrExpressionBody
|
||||||
CALL .<init> type=A operator=
|
BLOCK type=<no-type> hasResult=false isDesugared=false
|
||||||
CALL .plusAssign type=kotlin.Unit operator=PLUSEQ
|
IrFunction public operator fun A.minusAssign(/*0*/ s: kotlin.String): kotlin.Unit
|
||||||
$receiver: GET_VAR a type=A
|
IrExpressionBody
|
||||||
s: ? IrStringConcatenationExpressionImpl type=kotlin.String
|
BLOCK type=<no-type> hasResult=false isDesugared=false
|
||||||
|
IrFunction public operator fun A.timesAssign(/*0*/ s: kotlin.String): kotlin.Unit
|
||||||
|
IrExpressionBody
|
||||||
|
BLOCK type=<no-type> hasResult=false isDesugared=false
|
||||||
|
IrFunction public operator fun A.divAssign(/*0*/ s: kotlin.String): kotlin.Unit
|
||||||
|
IrExpressionBody
|
||||||
|
BLOCK type=<no-type> hasResult=false isDesugared=false
|
||||||
|
IrFunction public operator fun A.modAssign(/*0*/ s: kotlin.String): kotlin.Unit
|
||||||
|
IrExpressionBody
|
||||||
|
BLOCK type=<no-type> hasResult=false isDesugared=false
|
||||||
|
IrProperty public val p: A getter=null setter=null
|
||||||
|
IrExpressionBody
|
||||||
|
CALL .<init> type=A operator=
|
||||||
|
IrFunction public fun testVariable(): kotlin.Unit
|
||||||
|
IrExpressionBody
|
||||||
|
BLOCK type=<no-type> hasResult=false isDesugared=false
|
||||||
|
VAR val a: A
|
||||||
|
CALL .<init> type=A operator=
|
||||||
|
CALL .plusAssign type=kotlin.Unit operator=PLUSEQ
|
||||||
|
$receiver: GET_VAR a type=A
|
||||||
|
s: LITERAL String type=kotlin.String value='+='
|
||||||
|
CALL .minusAssign type=kotlin.Unit operator=MINUSEQ
|
||||||
|
$receiver: GET_VAR a type=A
|
||||||
|
s: LITERAL String type=kotlin.String value='-='
|
||||||
|
CALL .timesAssign type=kotlin.Unit operator=MULTEQ
|
||||||
|
$receiver: GET_VAR a type=A
|
||||||
|
s: LITERAL String type=kotlin.String value='*='
|
||||||
|
CALL .divAssign type=kotlin.Unit operator=DIVEQ
|
||||||
|
$receiver: GET_VAR a type=A
|
||||||
|
s: LITERAL String type=kotlin.String value='/='
|
||||||
|
CALL .modAssign type=kotlin.Unit operator=PERCEQ
|
||||||
|
$receiver: GET_VAR a type=A
|
||||||
|
s: LITERAL String type=kotlin.String value='*='
|
||||||
|
IrFunction public fun testProperty(): kotlin.Unit
|
||||||
|
IrExpressionBody
|
||||||
|
BLOCK type=<no-type> hasResult=false isDesugared=false
|
||||||
|
CALL .plusAssign type=kotlin.Unit operator=PLUSEQ
|
||||||
|
$receiver: GET_PROPERTY .p type=A
|
||||||
|
s: LITERAL String type=kotlin.String value='+='
|
||||||
|
CALL .minusAssign type=kotlin.Unit operator=MINUSEQ
|
||||||
|
$receiver: GET_PROPERTY .p type=A
|
||||||
|
s: LITERAL String type=kotlin.String value='-='
|
||||||
|
CALL .timesAssign type=kotlin.Unit operator=MULTEQ
|
||||||
|
$receiver: GET_PROPERTY .p type=A
|
||||||
|
s: LITERAL String type=kotlin.String value='*='
|
||||||
|
CALL .divAssign type=kotlin.Unit operator=DIVEQ
|
||||||
|
$receiver: GET_PROPERTY .p type=A
|
||||||
|
s: LITERAL String type=kotlin.String value='/='
|
||||||
|
CALL .modAssign type=kotlin.Unit operator=PERCEQ
|
||||||
|
$receiver: GET_PROPERTY .p type=A
|
||||||
|
s: LITERAL String type=kotlin.String value='*='
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
// <<< augmentedAssignmentArray.txt
|
||||||
|
fun foo(): IntArray = intArrayOf(1, 2, 3)
|
||||||
|
|
||||||
|
fun testVariable() {
|
||||||
|
var x = foo()
|
||||||
|
x[0] += 1
|
||||||
|
foo()[0] *= 2
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
IrFile /augmentedAssignmentArray.kt
|
||||||
|
IrFunction public fun foo(): kotlin.IntArray
|
||||||
|
IrExpressionBody
|
||||||
|
BLOCK type=<no-type> hasResult=false isDesugared=true
|
||||||
|
RETURN type=<no-type>
|
||||||
|
CALL .intArrayOf type=kotlin.IntArray operator=
|
||||||
|
elements: DUMMY vararg type=kotlin.Int
|
||||||
|
IrFunction public fun testVariable(): kotlin.Unit
|
||||||
|
IrExpressionBody
|
||||||
|
BLOCK type=<no-type> hasResult=false isDesugared=false
|
||||||
|
VAR var x: kotlin.IntArray
|
||||||
|
CALL .foo type=kotlin.IntArray operator=
|
||||||
|
VAR val tmp0: kotlin.IntArray
|
||||||
|
GET_VAR x type=kotlin.IntArray
|
||||||
|
VAR val tmp1: kotlin.Int
|
||||||
|
LITERAL Int type=kotlin.Int value='0'
|
||||||
|
CALL .set type=kotlin.Unit operator=PLUSEQ
|
||||||
|
$this: GET_VAR tmp0 type=kotlin.IntArray
|
||||||
|
index: GET_VAR tmp1 type=kotlin.Int
|
||||||
|
value: CALL .plus type=kotlin.Int operator=PLUSEQ
|
||||||
|
$this: CALL .get type=kotlin.Int operator=PLUSEQ
|
||||||
|
$this: GET_VAR tmp0 type=kotlin.IntArray
|
||||||
|
index: GET_VAR tmp1 type=kotlin.Int
|
||||||
|
other: LITERAL Int type=kotlin.Int value='1'
|
||||||
|
VAR val tmp2: kotlin.IntArray
|
||||||
|
CALL .foo type=kotlin.IntArray operator=
|
||||||
|
VAR val tmp3: kotlin.Int
|
||||||
|
LITERAL Int type=kotlin.Int value='0'
|
||||||
|
CALL .set type=kotlin.Unit operator=MULTEQ
|
||||||
|
$this: GET_VAR tmp2 type=kotlin.IntArray
|
||||||
|
index: GET_VAR tmp3 type=kotlin.Int
|
||||||
|
value: CALL .times type=kotlin.Int operator=MULTEQ
|
||||||
|
$this: CALL .get type=kotlin.Int operator=MULTEQ
|
||||||
|
$this: GET_VAR tmp2 type=kotlin.IntArray
|
||||||
|
index: GET_VAR tmp3 type=kotlin.Int
|
||||||
|
other: LITERAL Int type=kotlin.Int value='2'
|
||||||
@@ -35,6 +35,12 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase {
|
|||||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/ir/irText"), Pattern.compile("^(.+)\\.kt$"), true);
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/ir/irText"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("arrayAssignment.kt")
|
||||||
|
public void testArrayAssignment() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/arrayAssignment.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("assignments.kt")
|
@TestMetadata("assignments.kt")
|
||||||
public void testAssignments() throws Exception {
|
public void testAssignments() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/assignments.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/assignments.kt");
|
||||||
@@ -53,6 +59,12 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("augmentedAssignmentArray.kt")
|
||||||
|
public void testAugmentedAssignmentArray() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/augmentedAssignmentArray.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("boxOk.kt")
|
@TestMetadata("boxOk.kt")
|
||||||
public void testBoxOk() throws Exception {
|
public void testBoxOk() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/boxOk.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/boxOk.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user