KT-28456 generate index arguments per expression
In the desugaring for compound assignment to a collection element,
argument expression 'i' is mapped to value parameters 'iG' and 'iS' of
corresponding 'get' and 'set' operators.
In general, these value parameters can have different indices.
This requires extra machinery in argument generation - that is, to be
able to generate a particular expression argument using an arbitrary
callback. In the vast majority of the cases this callback will just use
the corresponding StatementGenerator to generate IR subtree for the
provided expression. In case of 'get' and 'set' operator calls for an
augmented assignment expression this will map corresponding argument
expressions to pregenerated temporary variables.
Thus, in the following context:
```
class A
operator fun A.get(vararg xs: Int) = 0
operator fun A.set(i: Int, j: Int, v: Int) {}
```
statement `a[1, 2] += 3` will be desugared as (in a really pseudo
Kotlin):
```
{
val tmp_array = a
val tmp_index0 = 1
val tmp_index1 = 2
tmp_array.set(
i = tmp_index0,
j = tmp_index1,
v = tmp_array.get(xs = [tmp_index0, tmp_index1]).plus(3)
)
}
```
This commit is contained in:
+28
-9
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpressionWithCopy
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||
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.startOffsetSkippingComments
|
||||
import org.jetbrains.kotlin.psi2ir.intermediate.*
|
||||
@@ -38,7 +39,6 @@ import org.jetbrains.kotlin.resolve.calls.model.*
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.*
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeSubstitutor
|
||||
import java.lang.AssertionError
|
||||
|
||||
fun StatementGenerator.generateReceiverOrNull(ktDefaultElement: KtElement, receiver: ReceiverValue?): IntermediateValue? =
|
||||
receiver?.let { generateReceiver(ktDefaultElement, receiver) }
|
||||
@@ -209,9 +209,10 @@ private fun StatementGenerator.generateReceiverForCalleeImportedFromObject(
|
||||
}
|
||||
}
|
||||
|
||||
fun StatementGenerator.generateVarargExpression(
|
||||
fun StatementGenerator.generateVarargExpressionUsing(
|
||||
varargArgument: VarargValueArgument,
|
||||
valueParameter: ValueParameterDescriptor
|
||||
valueParameter: ValueParameterDescriptor,
|
||||
generateArgumentExpression: (KtExpression) -> IrExpression?
|
||||
): IrExpression? {
|
||||
if (varargArgument.arguments.isEmpty()) {
|
||||
return null
|
||||
@@ -232,14 +233,16 @@ fun StatementGenerator.generateVarargExpression(
|
||||
for (argument in varargArgument.arguments) {
|
||||
val ktArgumentExpression = argument.getArgumentExpression()
|
||||
?: throw AssertionError("No argument expression for vararg element ${argument.asElement().text}")
|
||||
val irArgumentExpression = generateArgumentExpression(ktArgumentExpression)
|
||||
?: throw AssertionError("'generateArgumentExpression' should return non-null for vararg element ${ktArgumentExpression.text}")
|
||||
val irVarargElement =
|
||||
if (argument.getSpreadElement() != null)
|
||||
IrSpreadElementImpl(
|
||||
ktArgumentExpression.startOffsetSkippingComments, ktArgumentExpression.endOffset,
|
||||
generateExpression(ktArgumentExpression)
|
||||
irArgumentExpression
|
||||
)
|
||||
else
|
||||
generateExpression(ktArgumentExpression)
|
||||
irArgumentExpression
|
||||
|
||||
irVararg.addElement(irVarargElement)
|
||||
}
|
||||
@@ -247,17 +250,23 @@ fun StatementGenerator.generateVarargExpression(
|
||||
return irVararg
|
||||
}
|
||||
|
||||
fun StatementGenerator.generateValueArgument(
|
||||
private fun StatementGenerator.generateValueArgument(
|
||||
valueArgument: ResolvedValueArgument,
|
||||
valueParameter: ValueParameterDescriptor
|
||||
) = generateValueArgumentUsing(valueArgument, valueParameter) { generateExpression(it) }
|
||||
|
||||
fun StatementGenerator.generateValueArgumentUsing(
|
||||
valueArgument: ResolvedValueArgument,
|
||||
valueParameter: ValueParameterDescriptor,
|
||||
generateArgumentExpression: (KtExpression) -> IrExpression?
|
||||
): IrExpression? =
|
||||
when (valueArgument) {
|
||||
is DefaultValueArgument ->
|
||||
null
|
||||
is ExpressionValueArgument ->
|
||||
generateExpression(valueArgument.valueArgument!!.getArgumentExpression()!!)
|
||||
generateArgumentExpression(valueArgument.valueArgument!!.getArgumentExpression()!!)
|
||||
is VarargValueArgument ->
|
||||
generateVarargExpression(valueArgument, valueParameter)
|
||||
generateVarargExpressionUsing(valueArgument, valueParameter, generateArgumentExpression)
|
||||
else ->
|
||||
TODO("Unexpected valueArgument: ${valueArgument::class.java.simpleName}")
|
||||
}
|
||||
@@ -357,9 +366,19 @@ private fun ResolvedCall<*>.isExtensionInvokeCall(): Boolean {
|
||||
}
|
||||
|
||||
private fun StatementGenerator.pregenerateValueArguments(call: CallBuilder, resolvedCall: ResolvedCall<*>) {
|
||||
pregenerateValueArgumentsUsing(call, resolvedCall) {
|
||||
generateExpression(it)
|
||||
}
|
||||
}
|
||||
|
||||
fun StatementGenerator.pregenerateValueArgumentsUsing(
|
||||
call: CallBuilder,
|
||||
resolvedCall: ResolvedCall<*>,
|
||||
generateArgumentExpression: (KtExpression) -> IrExpression?
|
||||
) {
|
||||
resolvedCall.valueArgumentsByIndex!!.forEachIndexed { index, valueArgument ->
|
||||
val valueParameter = call.descriptor.valueParameters[index]
|
||||
call.irValueArgumentsByIndex[index] = generateValueArgument(valueArgument, valueParameter)
|
||||
call.irValueArgumentsByIndex[index] = generateValueArgumentUsing(valueArgument, valueParameter, generateArgumentExpression)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
@@ -268,6 +268,7 @@ class AssignmentGenerator(statementGenerator: StatementGenerator) : StatementGen
|
||||
|
||||
return ArrayAccessAssignmentReceiver(
|
||||
ktLeft.arrayExpression!!.genExpr(),
|
||||
ktLeft.indexExpressions,
|
||||
ktLeft.indexExpressions.map { it.genExpr() },
|
||||
indexedGetResolvedCall,
|
||||
indexedSetResolvedCall,
|
||||
|
||||
+22
-10
@@ -22,13 +22,16 @@ import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrBlockImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.inlineStatement
|
||||
import org.jetbrains.kotlin.ir.expressions.isAssignmentOperatorWithResult
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
import org.jetbrains.kotlin.psi2ir.generators.CallGenerator
|
||||
import org.jetbrains.kotlin.psi2ir.generators.pregenerateValueArgumentsUsing
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
|
||||
class ArrayAccessAssignmentReceiver(
|
||||
private val irArray: IrExpression,
|
||||
private val irIndices: List<IrExpression>,
|
||||
private val ktIndexExpressions: List<KtExpression>,
|
||||
private val irIndexExpressions: List<IrExpression>,
|
||||
private val indexedGetResolvedCall: ResolvedCall<FunctionDescriptor>?,
|
||||
private val indexedSetResolvedCall: ResolvedCall<FunctionDescriptor>?,
|
||||
private val indexedGetCall: () -> CallBuilder?,
|
||||
@@ -57,15 +60,18 @@ class ArrayAccessAssignmentReceiver(
|
||||
|
||||
val irArrayValue = callGenerator.scope.createTemporaryVariableInBlock(callGenerator.context, irArray, irBlock, "array")
|
||||
|
||||
val irIndexValues = irIndices.mapIndexed { i, irIndex ->
|
||||
callGenerator.scope.createTemporaryVariableInBlock(callGenerator.context, irIndex, irBlock, "index$i")
|
||||
val ktExpressionToIrIndexValue = HashMap<KtExpression, IntermediateValue>()
|
||||
|
||||
for ((i, irIndex) in irIndexExpressions.withIndex()) {
|
||||
ktExpressionToIrIndexValue[ktIndexExpressions[i]] =
|
||||
callGenerator.scope.createTemporaryVariableInBlock(callGenerator.context, irIndex, irBlock, "index$i")
|
||||
}
|
||||
|
||||
val irLValue = LValueWithGetterAndSetterCalls(
|
||||
callGenerator,
|
||||
descriptor,
|
||||
{ indexedGetCall()?.fillArrayAndIndexArguments(irArrayValue, irIndexValues) },
|
||||
{ indexedSetCall()?.fillArrayAndIndexArguments(irArrayValue, irIndexValues) },
|
||||
{ indexedGetCall()?.fillArrayAndIndexArguments(irArrayValue, indexedGetResolvedCall!!, ktExpressionToIrIndexValue) },
|
||||
{ indexedSetCall()?.fillArrayAndIndexArguments(irArrayValue, indexedSetResolvedCall!!, ktExpressionToIrIndexValue) },
|
||||
callGenerator.translateType(kotlinType),
|
||||
startOffset, endOffset, origin
|
||||
)
|
||||
@@ -76,18 +82,24 @@ class ArrayAccessAssignmentReceiver(
|
||||
|
||||
override fun assign(value: IrExpression): IrExpression {
|
||||
val call = indexedSetCall() ?: throw AssertionError("Array access without indexed-get call")
|
||||
val ktExpressionToIrIndexExpression = ktIndexExpressions.zip(irIndexExpressions).toMap()
|
||||
call.setExplicitReceiverValue(OnceExpressionValue(irArray))
|
||||
irIndices.forEachIndexed { i, irIndex ->
|
||||
call.irValueArgumentsByIndex[i] = irIndex
|
||||
callGenerator.statementGenerator.pregenerateValueArgumentsUsing(call, indexedSetResolvedCall!!) {
|
||||
ktExpressionToIrIndexExpression[it]
|
||||
}
|
||||
call.lastArgument = value
|
||||
return callGenerator.generateCall(startOffset, endOffset, call, IrStatementOrigin.EQ)
|
||||
}
|
||||
|
||||
private fun CallBuilder.fillArrayAndIndexArguments(arrayValue: IntermediateValue, indexValues: List<IntermediateValue>) = apply {
|
||||
private fun CallBuilder.fillArrayAndIndexArguments(
|
||||
arrayValue: IntermediateValue,
|
||||
resolvedCall: ResolvedCall<FunctionDescriptor>,
|
||||
ktExpressionToIrIndexValue: Map<KtExpression, IntermediateValue>
|
||||
) = apply {
|
||||
setExplicitReceiverValue(arrayValue)
|
||||
indexValues.forEachIndexed { i, irIndexValue ->
|
||||
irValueArgumentsByIndex[i] = irIndexValue.load()
|
||||
|
||||
callGenerator.statementGenerator.pregenerateValueArgumentsUsing(this, resolvedCall) { ktExpression ->
|
||||
ktExpressionToIrIndexValue[ktExpression]?.load()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
class A
|
||||
|
||||
operator fun A.get(vararg xs: Int) = 0
|
||||
|
||||
operator fun A.set(i: Int, j: Int, v: Int) {}
|
||||
|
||||
fun testSimpleAssignment(a: A) {
|
||||
a[1, 2] = 0
|
||||
}
|
||||
|
||||
fun testPostfixIncrement(a: A) = a[1, 2]++
|
||||
|
||||
fun testCompoundAssignment(a: A) {
|
||||
a[1, 2] += 10
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
FILE fqName:<root> fileName:/kt28456.kt
|
||||
CLASS CLASS name:A modality:FINAL visibility:public flags: superTypes:[kotlin.Any]
|
||||
$this: VALUE_PARAMETER INSTANCE_RECEIVER name:<this> type:A flags:
|
||||
CONSTRUCTOR visibility:public <> () returnType:A flags:primary
|
||||
BLOCK_BODY
|
||||
DELEGATING_CONSTRUCTOR_CALL 'constructor Any()'
|
||||
INSTANCE_INITIALIZER_CALL classDescriptor='A'
|
||||
FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean flags:
|
||||
overridden:
|
||||
FUN IR_EXTERNAL_DECLARATION_STUB name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean flags:
|
||||
$this: VALUE_PARAMETER name:<this> type:kotlin.Any flags:
|
||||
VALUE_PARAMETER name:other index:0 type:kotlin.Any? flags:
|
||||
FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.Int flags:
|
||||
overridden:
|
||||
FUN IR_EXTERNAL_DECLARATION_STUB name:hashCode visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.Int flags:
|
||||
$this: VALUE_PARAMETER name:<this> type:kotlin.Any flags:
|
||||
FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.String flags:
|
||||
overridden:
|
||||
FUN IR_EXTERNAL_DECLARATION_STUB name:toString visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.String flags:
|
||||
$this: VALUE_PARAMETER name:<this> type:kotlin.Any flags:
|
||||
FUN name:get visibility:public modality:FINAL <> ($receiver:A, xs:kotlin.IntArray) returnType:kotlin.Int flags:
|
||||
$receiver: VALUE_PARAMETER name:<this> type:A flags:
|
||||
VALUE_PARAMETER name:xs index:0 type:kotlin.IntArray varargElementType:kotlin.Int flags:vararg
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='get(vararg Int) on A: Int'
|
||||
CONST Int type=kotlin.Int value=0
|
||||
FUN name:set visibility:public modality:FINAL <> ($receiver:A, i:kotlin.Int, j:kotlin.Int, v:kotlin.Int) returnType:kotlin.Unit flags:
|
||||
$receiver: VALUE_PARAMETER name:<this> type:A flags:
|
||||
VALUE_PARAMETER name:i index:0 type:kotlin.Int flags:
|
||||
VALUE_PARAMETER name:j index:1 type:kotlin.Int flags:
|
||||
VALUE_PARAMETER name:v index:2 type:kotlin.Int flags:
|
||||
BLOCK_BODY
|
||||
FUN name:testSimpleAssignment visibility:public modality:FINAL <> (a:A) returnType:kotlin.Unit flags:
|
||||
VALUE_PARAMETER name:a index:0 type:A flags:
|
||||
BLOCK_BODY
|
||||
CALL 'set(Int, Int, Int) on A: Unit' type=kotlin.Unit origin=EQ
|
||||
$receiver: GET_VAR 'value-parameter a: A' type=A origin=null
|
||||
i: CONST Int type=kotlin.Int value=1
|
||||
j: CONST Int type=kotlin.Int value=2
|
||||
v: CONST Int type=kotlin.Int value=0
|
||||
FUN name:testPostfixIncrement visibility:public modality:FINAL <> (a:A) returnType:kotlin.Int flags:
|
||||
VALUE_PARAMETER name:a index:0 type:A flags:
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='testPostfixIncrement(A): Int'
|
||||
BLOCK type=kotlin.Int origin=POSTFIX_INCR
|
||||
VAR IR_TEMPORARY_VARIABLE name:tmp0_array type:A flags:val
|
||||
GET_VAR 'value-parameter a: A' type=A origin=null
|
||||
VAR IR_TEMPORARY_VARIABLE name:tmp1_index0 type:kotlin.Int flags:val
|
||||
CONST Int type=kotlin.Int value=1
|
||||
VAR IR_TEMPORARY_VARIABLE name:tmp2_index1 type:kotlin.Int flags:val
|
||||
CONST Int type=kotlin.Int value=2
|
||||
VAR IR_TEMPORARY_VARIABLE name:tmp3 type:kotlin.Int flags:val
|
||||
CALL 'get(vararg Int) on A: Int' type=kotlin.Int origin=POSTFIX_INCR
|
||||
$receiver: GET_VAR 'tmp0_array: A' type=A origin=null
|
||||
xs: VARARG type=kotlin.IntArray varargElementType=kotlin.Int
|
||||
GET_VAR 'tmp1_index0: Int' type=kotlin.Int origin=null
|
||||
GET_VAR 'tmp2_index1: Int' type=kotlin.Int origin=null
|
||||
CALL 'set(Int, Int, Int) on A: Unit' type=kotlin.Unit origin=POSTFIX_INCR
|
||||
$receiver: GET_VAR 'tmp0_array: A' type=A origin=null
|
||||
i: GET_VAR 'tmp1_index0: Int' type=kotlin.Int origin=null
|
||||
j: GET_VAR 'tmp2_index1: Int' type=kotlin.Int origin=null
|
||||
v: CALL 'inc(): Int' type=kotlin.Int origin=POSTFIX_INCR
|
||||
$this: GET_VAR 'tmp3: Int' type=kotlin.Int origin=null
|
||||
GET_VAR 'tmp3: Int' type=kotlin.Int origin=null
|
||||
FUN name:testCompoundAssignment visibility:public modality:FINAL <> (a:A) returnType:kotlin.Unit flags:
|
||||
VALUE_PARAMETER name:a index:0 type:A flags:
|
||||
BLOCK_BODY
|
||||
BLOCK type=kotlin.Unit origin=PLUSEQ
|
||||
VAR IR_TEMPORARY_VARIABLE name:tmp0_array type:A flags:val
|
||||
GET_VAR 'value-parameter a: A' type=A origin=null
|
||||
VAR IR_TEMPORARY_VARIABLE name:tmp1_index0 type:kotlin.Int flags:val
|
||||
CONST Int type=kotlin.Int value=1
|
||||
VAR IR_TEMPORARY_VARIABLE name:tmp2_index1 type:kotlin.Int flags:val
|
||||
CONST Int type=kotlin.Int value=2
|
||||
CALL 'set(Int, Int, Int) on A: Unit' type=kotlin.Unit origin=PLUSEQ
|
||||
$receiver: GET_VAR 'tmp0_array: A' type=A origin=null
|
||||
i: GET_VAR 'tmp1_index0: Int' type=kotlin.Int origin=null
|
||||
j: GET_VAR 'tmp2_index1: Int' type=kotlin.Int origin=null
|
||||
v: CALL 'plus(Int): Int' type=kotlin.Int origin=PLUSEQ
|
||||
$this: CALL 'get(vararg Int) on A: Int' type=kotlin.Int origin=PLUSEQ
|
||||
$receiver: GET_VAR 'tmp0_array: A' type=A origin=null
|
||||
xs: VARARG type=kotlin.IntArray varargElementType=kotlin.Int
|
||||
GET_VAR 'tmp1_index0: Int' type=kotlin.Int origin=null
|
||||
GET_VAR 'tmp2_index1: Int' type=kotlin.Int origin=null
|
||||
other: CONST Int type=kotlin.Int value=10
|
||||
@@ -0,0 +1,7 @@
|
||||
class A
|
||||
|
||||
operator fun A.set(vararg i: Int, v: Int) {}
|
||||
|
||||
fun testSimpleAssignment(a: A) {
|
||||
a[1, 2, 3] = 0
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
FILE fqName:<root> fileName:/kt28456a.kt
|
||||
CLASS CLASS name:A modality:FINAL visibility:public flags: superTypes:[kotlin.Any]
|
||||
$this: VALUE_PARAMETER INSTANCE_RECEIVER name:<this> type:A flags:
|
||||
CONSTRUCTOR visibility:public <> () returnType:A flags:primary
|
||||
BLOCK_BODY
|
||||
DELEGATING_CONSTRUCTOR_CALL 'constructor Any()'
|
||||
INSTANCE_INITIALIZER_CALL classDescriptor='A'
|
||||
FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean flags:
|
||||
overridden:
|
||||
FUN IR_EXTERNAL_DECLARATION_STUB name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean flags:
|
||||
$this: VALUE_PARAMETER name:<this> type:kotlin.Any flags:
|
||||
VALUE_PARAMETER name:other index:0 type:kotlin.Any? flags:
|
||||
FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.Int flags:
|
||||
overridden:
|
||||
FUN IR_EXTERNAL_DECLARATION_STUB name:hashCode visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.Int flags:
|
||||
$this: VALUE_PARAMETER name:<this> type:kotlin.Any flags:
|
||||
FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.String flags:
|
||||
overridden:
|
||||
FUN IR_EXTERNAL_DECLARATION_STUB name:toString visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.String flags:
|
||||
$this: VALUE_PARAMETER name:<this> type:kotlin.Any flags:
|
||||
FUN name:set visibility:public modality:FINAL <> ($receiver:A, i:kotlin.IntArray, v:kotlin.Int) returnType:kotlin.Unit flags:
|
||||
$receiver: VALUE_PARAMETER name:<this> type:A flags:
|
||||
VALUE_PARAMETER name:i index:0 type:kotlin.IntArray varargElementType:kotlin.Int flags:vararg
|
||||
VALUE_PARAMETER name:v index:1 type:kotlin.Int flags:
|
||||
BLOCK_BODY
|
||||
FUN name:testSimpleAssignment visibility:public modality:FINAL <> (a:A) returnType:kotlin.Unit flags:
|
||||
VALUE_PARAMETER name:a index:0 type:A flags:
|
||||
BLOCK_BODY
|
||||
CALL 'set(vararg Int, Int) on A: Unit' type=kotlin.Unit origin=EQ
|
||||
$receiver: GET_VAR 'value-parameter a: A' type=A origin=null
|
||||
i: VARARG type=kotlin.IntArray varargElementType=kotlin.Int
|
||||
CONST Int type=kotlin.Int value=1
|
||||
CONST Int type=kotlin.Int value=2
|
||||
CONST Int type=kotlin.Int value=3
|
||||
v: CONST Int type=kotlin.Int value=0
|
||||
@@ -0,0 +1,15 @@
|
||||
class A
|
||||
|
||||
operator fun A.get(i: Int, a: Int = 1, b: Int = 2, c: Int = 3, d: Int = 4) = 0
|
||||
|
||||
operator fun A.set(i: Int, j: Int = 42, v: Int) {}
|
||||
|
||||
fun testSimpleAssignment(a: A) {
|
||||
a[1] = 0
|
||||
}
|
||||
|
||||
fun testPostfixIncrement(a: A) = a[1]++
|
||||
|
||||
fun testCompoundAssignment(a: A) {
|
||||
a[1] += 10
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
FILE fqName:<root> fileName:/kt28456b.kt
|
||||
CLASS CLASS name:A modality:FINAL visibility:public flags: superTypes:[kotlin.Any]
|
||||
$this: VALUE_PARAMETER INSTANCE_RECEIVER name:<this> type:A flags:
|
||||
CONSTRUCTOR visibility:public <> () returnType:A flags:primary
|
||||
BLOCK_BODY
|
||||
DELEGATING_CONSTRUCTOR_CALL 'constructor Any()'
|
||||
INSTANCE_INITIALIZER_CALL classDescriptor='A'
|
||||
FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean flags:
|
||||
overridden:
|
||||
FUN IR_EXTERNAL_DECLARATION_STUB name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean flags:
|
||||
$this: VALUE_PARAMETER name:<this> type:kotlin.Any flags:
|
||||
VALUE_PARAMETER name:other index:0 type:kotlin.Any? flags:
|
||||
FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.Int flags:
|
||||
overridden:
|
||||
FUN IR_EXTERNAL_DECLARATION_STUB name:hashCode visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.Int flags:
|
||||
$this: VALUE_PARAMETER name:<this> type:kotlin.Any flags:
|
||||
FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.String flags:
|
||||
overridden:
|
||||
FUN IR_EXTERNAL_DECLARATION_STUB name:toString visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.String flags:
|
||||
$this: VALUE_PARAMETER name:<this> type:kotlin.Any flags:
|
||||
FUN name:get visibility:public modality:FINAL <> ($receiver:A, i:kotlin.Int, a:kotlin.Int, b:kotlin.Int, c:kotlin.Int, d:kotlin.Int) returnType:kotlin.Int flags:
|
||||
$receiver: VALUE_PARAMETER name:<this> type:A flags:
|
||||
VALUE_PARAMETER name:i index:0 type:kotlin.Int flags:
|
||||
VALUE_PARAMETER name:a index:1 type:kotlin.Int flags:
|
||||
EXPRESSION_BODY
|
||||
CONST Int type=kotlin.Int value=1
|
||||
VALUE_PARAMETER name:b index:2 type:kotlin.Int flags:
|
||||
EXPRESSION_BODY
|
||||
CONST Int type=kotlin.Int value=2
|
||||
VALUE_PARAMETER name:c index:3 type:kotlin.Int flags:
|
||||
EXPRESSION_BODY
|
||||
CONST Int type=kotlin.Int value=3
|
||||
VALUE_PARAMETER name:d index:4 type:kotlin.Int flags:
|
||||
EXPRESSION_BODY
|
||||
CONST Int type=kotlin.Int value=4
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='get(Int, Int = ..., Int = ..., Int = ..., Int = ...) on A: Int'
|
||||
CONST Int type=kotlin.Int value=0
|
||||
FUN name:set visibility:public modality:FINAL <> ($receiver:A, i:kotlin.Int, j:kotlin.Int, v:kotlin.Int) returnType:kotlin.Unit flags:
|
||||
$receiver: VALUE_PARAMETER name:<this> type:A flags:
|
||||
VALUE_PARAMETER name:i index:0 type:kotlin.Int flags:
|
||||
VALUE_PARAMETER name:j index:1 type:kotlin.Int flags:
|
||||
EXPRESSION_BODY
|
||||
CONST Int type=kotlin.Int value=42
|
||||
VALUE_PARAMETER name:v index:2 type:kotlin.Int flags:
|
||||
BLOCK_BODY
|
||||
FUN name:testSimpleAssignment visibility:public modality:FINAL <> (a:A) returnType:kotlin.Unit flags:
|
||||
VALUE_PARAMETER name:a index:0 type:A flags:
|
||||
BLOCK_BODY
|
||||
CALL 'set(Int, Int = ..., Int) on A: Unit' type=kotlin.Unit origin=EQ
|
||||
$receiver: GET_VAR 'value-parameter a: A' type=A origin=null
|
||||
i: CONST Int type=kotlin.Int value=1
|
||||
v: CONST Int type=kotlin.Int value=0
|
||||
FUN name:testPostfixIncrement visibility:public modality:FINAL <> (a:A) returnType:kotlin.Int flags:
|
||||
VALUE_PARAMETER name:a index:0 type:A flags:
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='testPostfixIncrement(A): Int'
|
||||
BLOCK type=kotlin.Int origin=POSTFIX_INCR
|
||||
VAR IR_TEMPORARY_VARIABLE name:tmp0_array type:A flags:val
|
||||
GET_VAR 'value-parameter a: A' type=A origin=null
|
||||
VAR IR_TEMPORARY_VARIABLE name:tmp1_index0 type:kotlin.Int flags:val
|
||||
CONST Int type=kotlin.Int value=1
|
||||
VAR IR_TEMPORARY_VARIABLE name:tmp2 type:kotlin.Int flags:val
|
||||
CALL 'get(Int, Int = ..., Int = ..., Int = ..., Int = ...) on A: Int' type=kotlin.Int origin=POSTFIX_INCR
|
||||
$receiver: GET_VAR 'tmp0_array: A' type=A origin=null
|
||||
i: GET_VAR 'tmp1_index0: Int' type=kotlin.Int origin=null
|
||||
CALL 'set(Int, Int = ..., Int) on A: Unit' type=kotlin.Unit origin=POSTFIX_INCR
|
||||
$receiver: GET_VAR 'tmp0_array: A' type=A origin=null
|
||||
i: GET_VAR 'tmp1_index0: Int' type=kotlin.Int origin=null
|
||||
v: CALL 'inc(): Int' type=kotlin.Int origin=POSTFIX_INCR
|
||||
$this: GET_VAR 'tmp2: Int' type=kotlin.Int origin=null
|
||||
GET_VAR 'tmp2: Int' type=kotlin.Int origin=null
|
||||
FUN name:testCompoundAssignment visibility:public modality:FINAL <> (a:A) returnType:kotlin.Unit flags:
|
||||
VALUE_PARAMETER name:a index:0 type:A flags:
|
||||
BLOCK_BODY
|
||||
BLOCK type=kotlin.Unit origin=PLUSEQ
|
||||
VAR IR_TEMPORARY_VARIABLE name:tmp0_array type:A flags:val
|
||||
GET_VAR 'value-parameter a: A' type=A origin=null
|
||||
VAR IR_TEMPORARY_VARIABLE name:tmp1_index0 type:kotlin.Int flags:val
|
||||
CONST Int type=kotlin.Int value=1
|
||||
CALL 'set(Int, Int = ..., Int) on A: Unit' type=kotlin.Unit origin=PLUSEQ
|
||||
$receiver: GET_VAR 'tmp0_array: A' type=A origin=null
|
||||
i: GET_VAR 'tmp1_index0: Int' type=kotlin.Int origin=null
|
||||
v: CALL 'plus(Int): Int' type=kotlin.Int origin=PLUSEQ
|
||||
$this: CALL 'get(Int, Int = ..., Int = ..., Int = ..., Int = ...) on A: Int' type=kotlin.Int origin=PLUSEQ
|
||||
$receiver: GET_VAR 'tmp0_array: A' type=A origin=null
|
||||
i: GET_VAR 'tmp1_index0: Int' type=kotlin.Int origin=null
|
||||
other: CONST Int type=kotlin.Int value=10
|
||||
@@ -957,6 +957,21 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase {
|
||||
runTest("compiler/testData/ir/irText/expressions/kt28006.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt28456.kt")
|
||||
public void testKt28456() throws Exception {
|
||||
runTest("compiler/testData/ir/irText/expressions/kt28456.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt28456a.kt")
|
||||
public void testKt28456a() throws Exception {
|
||||
runTest("compiler/testData/ir/irText/expressions/kt28456a.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt28456b.kt")
|
||||
public void testKt28456b() throws Exception {
|
||||
runTest("compiler/testData/ir/irText/expressions/kt28456b.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("lambdaInCAO.kt")
|
||||
public void testLambdaInCAO() throws Exception {
|
||||
runTest("compiler/testData/ir/irText/expressions/lambdaInCAO.kt");
|
||||
|
||||
Reference in New Issue
Block a user