From 42e253b5ff68e91ec3c730b56c0fda0690e28388 Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Tue, 27 Nov 2018 12:03:22 +0300 Subject: [PATCH] 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) ) } ``` --- .../generators/ArgumentsGenerationUtils.kt | 37 ++++++-- .../psi2ir/generators/AssignmentGenerator.kt | 1 + .../ArrayAccessAssignmentReceiver.kt | 32 ++++--- .../testData/ir/irText/expressions/kt28456.kt | 15 ++++ .../ir/irText/expressions/kt28456.txt | 85 ++++++++++++++++++ .../ir/irText/expressions/kt28456a.kt | 7 ++ .../ir/irText/expressions/kt28456a.txt | 35 ++++++++ .../ir/irText/expressions/kt28456b.kt | 15 ++++ .../ir/irText/expressions/kt28456b.txt | 88 +++++++++++++++++++ .../kotlin/ir/IrTextTestCaseGenerated.java | 15 ++++ 10 files changed, 311 insertions(+), 19 deletions(-) create mode 100644 compiler/testData/ir/irText/expressions/kt28456.kt create mode 100644 compiler/testData/ir/irText/expressions/kt28456.txt create mode 100644 compiler/testData/ir/irText/expressions/kt28456a.kt create mode 100644 compiler/testData/ir/irText/expressions/kt28456a.txt create mode 100644 compiler/testData/ir/irText/expressions/kt28456b.kt create mode 100644 compiler/testData/ir/irText/expressions/kt28456b.txt diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ArgumentsGenerationUtils.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ArgumentsGenerationUtils.kt index a560be0e40f..e634b387b34 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ArgumentsGenerationUtils.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ArgumentsGenerationUtils.kt @@ -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) } } diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/AssignmentGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/AssignmentGenerator.kt index c8dc94713b6..cc2816be11d 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/AssignmentGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/AssignmentGenerator.kt @@ -268,6 +268,7 @@ class AssignmentGenerator(statementGenerator: StatementGenerator) : StatementGen return ArrayAccessAssignmentReceiver( ktLeft.arrayExpression!!.genExpr(), + ktLeft.indexExpressions, ktLeft.indexExpressions.map { it.genExpr() }, indexedGetResolvedCall, indexedSetResolvedCall, diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/ArrayAccessAssignmentReceiver.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/ArrayAccessAssignmentReceiver.kt index 3584794a03e..6ddf96d6176 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/ArrayAccessAssignmentReceiver.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/ArrayAccessAssignmentReceiver.kt @@ -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, + private val ktIndexExpressions: List, + private val irIndexExpressions: List, private val indexedGetResolvedCall: ResolvedCall?, private val indexedSetResolvedCall: ResolvedCall?, 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() + + 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) = apply { + private fun CallBuilder.fillArrayAndIndexArguments( + arrayValue: IntermediateValue, + resolvedCall: ResolvedCall, + ktExpressionToIrIndexValue: Map + ) = apply { setExplicitReceiverValue(arrayValue) - indexValues.forEachIndexed { i, irIndexValue -> - irValueArgumentsByIndex[i] = irIndexValue.load() + + callGenerator.statementGenerator.pregenerateValueArgumentsUsing(this, resolvedCall) { ktExpression -> + ktExpressionToIrIndexValue[ktExpression]?.load() } } } diff --git a/compiler/testData/ir/irText/expressions/kt28456.kt b/compiler/testData/ir/irText/expressions/kt28456.kt new file mode 100644 index 00000000000..8d9dd0e7c56 --- /dev/null +++ b/compiler/testData/ir/irText/expressions/kt28456.kt @@ -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 +} \ No newline at end of file diff --git a/compiler/testData/ir/irText/expressions/kt28456.txt b/compiler/testData/ir/irText/expressions/kt28456.txt new file mode 100644 index 00000000000..0afa82b3e6d --- /dev/null +++ b/compiler/testData/ir/irText/expressions/kt28456.txt @@ -0,0 +1,85 @@ +FILE fqName: fileName:/kt28456.kt + CLASS CLASS name:A modality:FINAL visibility:public flags: superTypes:[kotlin.Any] + $this: VALUE_PARAMETER INSTANCE_RECEIVER name: 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: 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: 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: type:kotlin.Any flags: + FUN name:get visibility:public modality:FINAL <> ($receiver:A, xs:kotlin.IntArray) returnType:kotlin.Int flags: + $receiver: VALUE_PARAMETER name: 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: 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 diff --git a/compiler/testData/ir/irText/expressions/kt28456a.kt b/compiler/testData/ir/irText/expressions/kt28456a.kt new file mode 100644 index 00000000000..10ab906a1eb --- /dev/null +++ b/compiler/testData/ir/irText/expressions/kt28456a.kt @@ -0,0 +1,7 @@ +class A + +operator fun A.set(vararg i: Int, v: Int) {} + +fun testSimpleAssignment(a: A) { + a[1, 2, 3] = 0 +} diff --git a/compiler/testData/ir/irText/expressions/kt28456a.txt b/compiler/testData/ir/irText/expressions/kt28456a.txt new file mode 100644 index 00000000000..c8c32ca8473 --- /dev/null +++ b/compiler/testData/ir/irText/expressions/kt28456a.txt @@ -0,0 +1,35 @@ +FILE fqName: fileName:/kt28456a.kt + CLASS CLASS name:A modality:FINAL visibility:public flags: superTypes:[kotlin.Any] + $this: VALUE_PARAMETER INSTANCE_RECEIVER name: 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: 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: 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: 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: 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 diff --git a/compiler/testData/ir/irText/expressions/kt28456b.kt b/compiler/testData/ir/irText/expressions/kt28456b.kt new file mode 100644 index 00000000000..376d7b9a068 --- /dev/null +++ b/compiler/testData/ir/irText/expressions/kt28456b.kt @@ -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 +} \ No newline at end of file diff --git a/compiler/testData/ir/irText/expressions/kt28456b.txt b/compiler/testData/ir/irText/expressions/kt28456b.txt new file mode 100644 index 00000000000..866afec1c93 --- /dev/null +++ b/compiler/testData/ir/irText/expressions/kt28456b.txt @@ -0,0 +1,88 @@ +FILE fqName: fileName:/kt28456b.kt + CLASS CLASS name:A modality:FINAL visibility:public flags: superTypes:[kotlin.Any] + $this: VALUE_PARAMETER INSTANCE_RECEIVER name: 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: 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: 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: 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: 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: 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 diff --git a/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java b/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java index aca606da7c2..4bafd1ed6b8 100644 --- a/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java @@ -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");