From 3f256fab6733d6c482a61a4a1c46bf243d48e9d2 Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Thu, 25 Aug 2016 10:11:38 +0300 Subject: [PATCH] Variable as function calls. --- .../psi2ir/generators/CallGeneration.kt | 6 ++- .../kotlin/psi2ir/generators/CallGenerator.kt | 5 ++ .../psi2ir/generators/StatementGenerator.kt | 10 ++-- .../psi2ir/intermediate/OnceCallValue.kt | 4 +- .../kotlin/ir/expressions/IrOperator.kt | 1 + .../ir/irText/variableAsFunctionCall.kt | 6 +++ .../ir/irText/variableAsFunctionCall.txt | 49 +++++++++++++++++++ .../kotlin/ir/IrTextTestCaseGenerated.java | 6 +++ 8 files changed, 78 insertions(+), 9 deletions(-) create mode 100644 compiler/testData/ir/irText/variableAsFunctionCall.kt create mode 100644 compiler/testData/ir/irText/variableAsFunctionCall.txt diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/CallGeneration.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/CallGeneration.kt index 419bfb25450..4fcaf305c46 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/CallGeneration.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/CallGeneration.kt @@ -109,8 +109,10 @@ fun StatementGenerator.pregenerateCall(resolvedCall: ResolvedCall<*>): CallBuild fun StatementGenerator.pregenerateCallReceivers(resolvedCall: ResolvedCall<*>): CallBuilder { val call = CallBuilder(resolvedCall) - val ktDefaultCallElement = resolvedCall.call.callElement - call.callReceiver = generateCallReceiver(ktDefaultCallElement, resolvedCall.dispatchReceiver, resolvedCall.extensionReceiver, resolvedCall.call.isSafeCall()) + call.callReceiver = generateCallReceiver(resolvedCall.call.callElement, + resolvedCall.dispatchReceiver, + resolvedCall.extensionReceiver, + resolvedCall.call.isSafeCall()) return call } \ No newline at end of file diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/CallGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/CallGenerator.kt index 0dd7b4afe1d..2de32662b53 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/CallGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/CallGenerator.kt @@ -19,6 +19,7 @@ package org.jetbrains.kotlin.psi2ir.generators import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor +import org.jetbrains.kotlin.descriptors.VariableDescriptor import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.psiUtil.endOffset @@ -50,6 +51,10 @@ class CallGenerator( return when (descriptor) { is PropertyDescriptor -> generatePropertyGetterCall(descriptor, startOffset, endOffset, call) + is VariableDescriptor -> + call.callReceiver.call { dispatchReceiverValue, extensionReceiverValue -> + IrGetVariableImpl(startOffset, endOffset, descriptor, operator) + } is FunctionDescriptor -> generateFunctionCall(descriptor, startOffset, endOffset, operator, call) else -> diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/StatementGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/StatementGenerator.kt index 479f8d0f47a..4f9f4baf8b9 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/StatementGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/StatementGenerator.kt @@ -26,9 +26,7 @@ import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.endOffset import org.jetbrains.kotlin.psi.psiUtil.startOffset import org.jetbrains.kotlin.psi2ir.deparenthesize -import org.jetbrains.kotlin.psi2ir.intermediate.Value -import org.jetbrains.kotlin.psi2ir.intermediate.createRematerializableOrTemporary -import org.jetbrains.kotlin.psi2ir.intermediate.setExplicitReceiverValue +import org.jetbrains.kotlin.psi2ir.intermediate.* import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContextUtils import org.jetbrains.kotlin.resolve.DescriptorUtils @@ -183,7 +181,8 @@ class StatementGenerator( val resolvedCall = getResolvedCall(expression) ?: throw AssertionError("No resolved call for ${expression.text}") if (resolvedCall is VariableAsFunctionResolvedCall) { - TODO("Unexpected VariableAsFunctionResolvedCall") + val variableCall = pregenerateCall(resolvedCall.variableCall) + return CallGenerator(this).generateCall(expression, variableCall, IrOperator.VARIABLE_AS_FUNCTION) } val descriptor = resolvedCall.resultingDescriptor @@ -222,7 +221,8 @@ class StatementGenerator( val resolvedCall = getResolvedCall(expression) ?: TODO("No resolved call for call expression") if (resolvedCall is VariableAsFunctionResolvedCall) { - TODO("VariableAsFunctionResolvedCall = variable call + invoke call") + val functionCall = pregenerateCall(resolvedCall.functionCall) + return CallGenerator(this).generateCall(expression, functionCall, IrOperator.INVOKE) } return CallGenerator(this).generateCall(expression.startOffset, expression.endOffset, pregenerateCall(resolvedCall)) diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/OnceCallValue.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/OnceCallValue.kt index 1830b66b69a..d63b089535e 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/OnceCallValue.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/OnceCallValue.kt @@ -24,10 +24,10 @@ import org.jetbrains.kotlin.psi2ir.intermediate.CallBuilder import org.jetbrains.kotlin.types.KotlinType class OnceCallValue( - val statementGenerator: StatementGenerator, - val call: CallBuilder, val startOffset: Int, val endOffset: Int, + val statementGenerator: StatementGenerator, + val call: CallBuilder, val operator: IrOperator? = null ): Value { private var instantiated = false diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrOperator.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrOperator.kt index 60d35eeea21..c941bb70a9f 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrOperator.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrOperator.kt @@ -53,6 +53,7 @@ interface IrOperator { object RANGE : IrOperatorImpl("RANGE") object INVOKE : IrOperatorImpl("INVOKE") + object VARIABLE_AS_FUNCTION : IrOperatorImpl("VARIABLE_AS_FUNCTION") object GET_ARRAY_ELEMENT : IrOperatorImpl("GET_ARRAY_ELEMENT") object PREFIX_INCR : IrOperatorImpl("PREFIX_INCR") diff --git a/compiler/testData/ir/irText/variableAsFunctionCall.kt b/compiler/testData/ir/irText/variableAsFunctionCall.kt new file mode 100644 index 00000000000..1ce66654894 --- /dev/null +++ b/compiler/testData/ir/irText/variableAsFunctionCall.kt @@ -0,0 +1,6 @@ +fun String.k(): () -> String = { -> this } + +fun test1(f: () -> Unit) = f() +fun test2(f: String.() -> Unit) = "hello".f() +fun test3() = "hello".k()() +fun test4(ns: String?) = ns?.k()?.invoke() \ No newline at end of file diff --git a/compiler/testData/ir/irText/variableAsFunctionCall.txt b/compiler/testData/ir/irText/variableAsFunctionCall.txt new file mode 100644 index 00000000000..d7b51bd9680 --- /dev/null +++ b/compiler/testData/ir/irText/variableAsFunctionCall.txt @@ -0,0 +1,49 @@ +IrFile /variableAsFunctionCall.kt + IrFunction public fun kotlin.String.k(): () -> kotlin.String + IrExpressionBody + BLOCK type= hasResult=false operator=null + RETURN type= + DUMMY KtLambdaExpression type=() -> kotlin.String + IrFunction public fun test1(/*0*/ f: () -> kotlin.Unit): kotlin.Unit + IrExpressionBody + BLOCK type= hasResult=false operator=null + RETURN type= + CALL .invoke type=kotlin.Unit operator=INVOKE + $this: GET_VAR f type=() -> kotlin.Unit operator=VARIABLE_AS_FUNCTION + IrFunction public fun test2(/*0*/ f: kotlin.String.() -> kotlin.Unit): kotlin.Unit + IrExpressionBody + BLOCK type= hasResult=false operator=null + RETURN type= + CALL .invoke type=kotlin.Unit operator=INVOKE + $this: GET_VAR f type=kotlin.String.() -> kotlin.Unit operator=VARIABLE_AS_FUNCTION + $receiver: CONST String type=kotlin.String value='hello' + IrFunction public fun test3(): kotlin.String + IrExpressionBody + BLOCK type= hasResult=false operator=null + RETURN type= + CALL .invoke type=kotlin.String operator=null + $this: CALL .k type=() -> kotlin.String operator=null + $receiver: CONST String type=kotlin.String value='hello' + IrFunction public fun test4(/*0*/ ns: kotlin.String?): kotlin.String? + IrExpressionBody + BLOCK type= hasResult=false operator=null + RETURN type= + BLOCK type=kotlin.String? hasResult=true operator=SAFE_CALL + VAR val tmp1_safe_receiver: (() -> kotlin.String)? + BLOCK type=(() -> kotlin.String)? hasResult=true operator=SAFE_CALL + VAR val tmp0_safe_receiver: kotlin.String? + GET_VAR ns type=kotlin.String? operator=null + WHEN type=(() -> kotlin.String)? operator=SAFE_CALL + if: CALL .EQEQ type=kotlin.Boolean operator=EQEQ + arg0: GET_VAR tmp0_safe_receiver type=kotlin.String? operator=null + arg1: CONST Null type=kotlin.Nothing? value='null' + then: CONST Null type=kotlin.Nothing? value='null' + else: CALL .k type=() -> kotlin.String operator=null + $this: GET_VAR tmp0_safe_receiver type=kotlin.String? operator=null + WHEN type=kotlin.String? operator=SAFE_CALL + if: CALL .EQEQ type=kotlin.Boolean operator=EQEQ + arg0: GET_VAR tmp1_safe_receiver type=(() -> kotlin.String)? operator=null + arg1: CONST Null type=kotlin.Nothing? value='null' + then: CONST Null type=kotlin.Nothing? value='null' + else: CALL .invoke type=kotlin.String operator=null + $this: GET_VAR tmp1_safe_receiver type=(() -> kotlin.String)? operator=null diff --git a/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java b/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java index 1d5e0842dfa..81c3d22a45f 100644 --- a/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java @@ -287,6 +287,12 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase { doTest(fileName); } + @TestMetadata("variableAsFunctionCall.kt") + public void testVariableAsFunctionCall() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/variableAsFunctionCall.kt"); + doTest(fileName); + } + @TestMetadata("when.kt") public void testWhen() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/when.kt");