Variable as function calls.

This commit is contained in:
Dmitry Petrov
2016-08-25 10:11:38 +03:00
committed by Dmitry Petrov
parent b3407de1e6
commit 3f256fab67
8 changed files with 78 additions and 9 deletions
@@ -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
}
@@ -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 ->
@@ -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))
@@ -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
@@ -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")
+6
View File
@@ -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()
+49
View File
@@ -0,0 +1,49 @@
IrFile /variableAsFunctionCall.kt
IrFunction public fun kotlin.String.k(): () -> kotlin.String
IrExpressionBody
BLOCK type=<no-type> hasResult=false operator=null
RETURN type=<no-type>
DUMMY KtLambdaExpression type=() -> kotlin.String
IrFunction public fun test1(/*0*/ f: () -> kotlin.Unit): kotlin.Unit
IrExpressionBody
BLOCK type=<no-type> hasResult=false operator=null
RETURN type=<no-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=<no-type> hasResult=false operator=null
RETURN type=<no-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=<no-type> hasResult=false operator=null
RETURN type=<no-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=<no-type> hasResult=false operator=null
RETURN type=<no-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
@@ -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");