From c2601c947ff3db6b5a02b0432707d0e2cdefce43 Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Thu, 4 May 2017 12:29:38 +0300 Subject: [PATCH] Postpone call arguments generation in compound assignment expressions Otherwise RHS is generated twice, causing ISE in symbol binding --- .../generators/ArgumentsGenerationUtils.kt | 4 +- .../psi2ir/generators/AssignmentGenerator.kt | 6 +- .../ir/irText/expressions/lambdaInCAO.kt | 16 +++++ .../ir/irText/expressions/lambdaInCAO.txt | 72 +++++++++++++++++++ .../kotlin/ir/IrTextTestCaseGenerated.java | 6 ++ 5 files changed, 99 insertions(+), 5 deletions(-) create mode 100644 compiler/testData/ir/irText/expressions/lambdaInCAO.kt create mode 100644 compiler/testData/ir/irText/expressions/lambdaInCAO.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 37a3e5991a1..a43ffcb78c2 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 @@ -232,7 +232,7 @@ fun StatementGenerator.pregenerateCall(resolvedCall: ResolvedCall<*>): CallBuild return pregenerateExtensionInvokeCall(resolvedCall) } - val call = pregenerateCallWithReceivers(resolvedCall) + val call = pregenerateCallReceivers(resolvedCall) pregenerateValueArguments(call, resolvedCall) return call } @@ -310,7 +310,7 @@ private fun StatementGenerator.pregenerateValueArguments(call: CallBuilder, reso } } -fun StatementGenerator.pregenerateCallWithReceivers(resolvedCall: ResolvedCall<*>): CallBuilder { +fun StatementGenerator.pregenerateCallReceivers(resolvedCall: ResolvedCall<*>): CallBuilder { val call = CallBuilder(resolvedCall, unwrapCallableDescriptor(resolvedCall.resultingDescriptor)) call.callReceiver = generateCallReceiver(resolvedCall.call.callElement, 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 82f70443e78..6197ac38115 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 @@ -50,7 +50,7 @@ class AssignmentGenerator(statementGenerator: StatementGenerator) : StatementGen val irAssignmentReceiver = generateAssignmentReceiver(ktLeft, origin) return irAssignmentReceiver.assign { irLValue -> - val opCall = statementGenerator.pregenerateCall(opResolvedCall) + val opCall = statementGenerator.pregenerateCallReceivers(opResolvedCall) opCall.setExplicitReceiverValue(irLValue) opCall.irValueArgumentsByIndex[0] = statementGenerator.generateExpression(ktRight) val irOpCall = CallGenerator(statementGenerator).generateCall(expression, opCall, origin) @@ -239,10 +239,10 @@ class AssignmentGenerator(statementGenerator: StatementGenerator) : StatementGen val irIndexExpressions = ktLeft.indexExpressions.map { statementGenerator.generateExpression(it) } val indexedGetResolvedCall = get(BindingContext.INDEXED_LVALUE_GET, ktLeft) - val indexedGetCall = indexedGetResolvedCall?.let { statementGenerator.pregenerateCallWithReceivers(it) } + val indexedGetCall = indexedGetResolvedCall?.let { statementGenerator.pregenerateCallReceivers(it) } val indexedSetResolvedCall = get(BindingContext.INDEXED_LVALUE_SET, ktLeft) - val indexedSetCall = indexedSetResolvedCall?.let { statementGenerator.pregenerateCallWithReceivers(it) } + val indexedSetCall = indexedSetResolvedCall?.let { statementGenerator.pregenerateCallReceivers(it) } return ArrayAccessAssignmentReceiver(irArray, irIndexExpressions, indexedGetCall, indexedSetCall, CallGenerator(statementGenerator), diff --git a/compiler/testData/ir/irText/expressions/lambdaInCAO.kt b/compiler/testData/ir/irText/expressions/lambdaInCAO.kt new file mode 100644 index 00000000000..d9194fe8727 --- /dev/null +++ b/compiler/testData/ir/irText/expressions/lambdaInCAO.kt @@ -0,0 +1,16 @@ +operator fun Any.plusAssign(lambda: () -> Unit) {} + +operator fun Any.get(index: () -> Unit): Int = 42 +operator fun Any.set(index: () -> Unit, value: Int) {} + +fun test1(a: Any) { + a += { } +} + +fun test2(a: Any) { + a[{}] += 42 +} + +fun test3(a: Any) { + a[{}]++ +} \ No newline at end of file diff --git a/compiler/testData/ir/irText/expressions/lambdaInCAO.txt b/compiler/testData/ir/irText/expressions/lambdaInCAO.txt new file mode 100644 index 00000000000..4e2722bda3b --- /dev/null +++ b/compiler/testData/ir/irText/expressions/lambdaInCAO.txt @@ -0,0 +1,72 @@ +FILE /lambdaInCAO.kt + FUN public operator fun kotlin.Any.plusAssign(lambda: () -> kotlin.Unit): kotlin.Unit + $receiver: VALUE_PARAMETER this@plusAssign: Any + VALUE_PARAMETER value-parameter lambda: () -> kotlin.Unit + BLOCK_BODY + FUN public operator fun kotlin.Any.get(index: () -> kotlin.Unit): kotlin.Int + $receiver: VALUE_PARAMETER this@get: Any + VALUE_PARAMETER value-parameter index: () -> kotlin.Unit + BLOCK_BODY + RETURN type=kotlin.Nothing from='get(() -> Unit) on Any: Int' + CONST Int type=kotlin.Int value='42' + FUN public operator fun kotlin.Any.set(index: () -> kotlin.Unit, value: kotlin.Int): kotlin.Unit + $receiver: VALUE_PARAMETER this@set: Any + VALUE_PARAMETER value-parameter index: () -> kotlin.Unit + VALUE_PARAMETER value-parameter value: kotlin.Int + BLOCK_BODY + FUN public fun test1(a: kotlin.Any): kotlin.Unit + VALUE_PARAMETER value-parameter a: kotlin.Any + BLOCK_BODY + CALL 'plusAssign(() -> Unit) on Any: Unit' type=kotlin.Unit origin=PLUSEQ + $receiver: GET_VAR 'value-parameter a: Any' type=kotlin.Any origin=PLUSEQ + lambda: BLOCK type=() -> kotlin.Unit origin=LAMBDA + FUN LOCAL_FUNCTION_FOR_LAMBDA local final fun (): kotlin.Unit + BLOCK_BODY + RETURN type=kotlin.Nothing from='(): Unit' + GET_OBJECT 'Unit' type=kotlin.Unit + FUNCTION_REFERENCE '(): Unit' type=() -> kotlin.Unit origin=LAMBDA + FUN public fun test2(a: kotlin.Any): kotlin.Unit + VALUE_PARAMETER value-parameter a: kotlin.Any + BLOCK_BODY + BLOCK type=kotlin.Unit origin=PLUSEQ + VAR IR_TEMPORARY_VARIABLE val tmp0_array: kotlin.Any + GET_VAR 'value-parameter a: Any' type=kotlin.Any origin=null + VAR IR_TEMPORARY_VARIABLE val tmp1_index0: () -> kotlin.Unit + BLOCK type=() -> kotlin.Unit origin=LAMBDA + FUN LOCAL_FUNCTION_FOR_LAMBDA local final fun (): kotlin.Unit + BLOCK_BODY + RETURN type=kotlin.Nothing from='(): Unit' + GET_OBJECT 'Unit' type=kotlin.Unit + FUNCTION_REFERENCE '(): Unit' type=() -> kotlin.Unit origin=LAMBDA + CALL 'set(() -> Unit, Int) on Any: Unit' type=kotlin.Unit origin=PLUSEQ + $receiver: GET_VAR 'tmp0_array: Any' type=kotlin.Any origin=null + index: GET_VAR 'tmp1_index0: () -> Unit' type=() -> kotlin.Unit origin=null + value: CALL 'plus(Int): Int' type=kotlin.Int origin=PLUSEQ + $this: CALL 'get(() -> Unit) on Any: Int' type=kotlin.Int origin=PLUSEQ + $receiver: GET_VAR 'tmp0_array: Any' type=kotlin.Any origin=null + index: GET_VAR 'tmp1_index0: () -> Unit' type=() -> kotlin.Unit origin=null + other: CONST Int type=kotlin.Int value='42' + FUN public fun test3(a: kotlin.Any): kotlin.Unit + VALUE_PARAMETER value-parameter a: kotlin.Any + BLOCK_BODY + TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit + BLOCK type=kotlin.Int origin=POSTFIX_INCR + VAR IR_TEMPORARY_VARIABLE val tmp0_array: kotlin.Any + GET_VAR 'value-parameter a: Any' type=kotlin.Any origin=null + VAR IR_TEMPORARY_VARIABLE val tmp1_index0: () -> kotlin.Unit + BLOCK type=() -> kotlin.Unit origin=LAMBDA + FUN LOCAL_FUNCTION_FOR_LAMBDA local final fun (): kotlin.Unit + BLOCK_BODY + RETURN type=kotlin.Nothing from='(): Unit' + GET_OBJECT 'Unit' type=kotlin.Unit + FUNCTION_REFERENCE '(): Unit' type=() -> kotlin.Unit origin=LAMBDA + VAR IR_TEMPORARY_VARIABLE val tmp2: kotlin.Int + CALL 'get(() -> Unit) on Any: Int' type=kotlin.Int origin=POSTFIX_INCR + $receiver: GET_VAR 'tmp0_array: Any' type=kotlin.Any origin=null + index: GET_VAR 'tmp1_index0: () -> Unit' type=() -> kotlin.Unit origin=null + CALL 'set(() -> Unit, Int) on Any: Unit' type=kotlin.Unit origin=POSTFIX_INCR + $receiver: GET_VAR 'tmp0_array: Any' type=kotlin.Any origin=null + index: GET_VAR 'tmp1_index0: () -> Unit' type=() -> kotlin.Unit origin=null + value: 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 diff --git a/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java b/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java index df7544039bb..cb9afd83e44 100644 --- a/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java @@ -737,6 +737,12 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase { doTest(fileName); } + @TestMetadata("lambdaInCAO.kt") + public void testLambdaInCAO() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/expressions/lambdaInCAO.kt"); + doTest(fileName); + } + @TestMetadata("literals.kt") public void testLiterals() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/expressions/literals.kt");