Variable as function calls.
This commit is contained in:
committed by
Dmitry Petrov
parent
b3407de1e6
commit
3f256fab67
@@ -109,8 +109,10 @@ fun StatementGenerator.pregenerateCall(resolvedCall: ResolvedCall<*>): CallBuild
|
|||||||
fun StatementGenerator.pregenerateCallReceivers(resolvedCall: ResolvedCall<*>): CallBuilder {
|
fun StatementGenerator.pregenerateCallReceivers(resolvedCall: ResolvedCall<*>): CallBuilder {
|
||||||
val call = CallBuilder(resolvedCall)
|
val call = CallBuilder(resolvedCall)
|
||||||
|
|
||||||
val ktDefaultCallElement = resolvedCall.call.callElement
|
call.callReceiver = generateCallReceiver(resolvedCall.call.callElement,
|
||||||
call.callReceiver = generateCallReceiver(ktDefaultCallElement, resolvedCall.dispatchReceiver, resolvedCall.extensionReceiver, resolvedCall.call.isSafeCall())
|
resolvedCall.dispatchReceiver,
|
||||||
|
resolvedCall.extensionReceiver,
|
||||||
|
resolvedCall.call.isSafeCall())
|
||||||
|
|
||||||
return call
|
return call
|
||||||
}
|
}
|
||||||
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.psi2ir.generators
|
|||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.VariableDescriptor
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
import org.jetbrains.kotlin.psi.KtElement
|
import org.jetbrains.kotlin.psi.KtElement
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
||||||
@@ -50,6 +51,10 @@ class CallGenerator(
|
|||||||
return when (descriptor) {
|
return when (descriptor) {
|
||||||
is PropertyDescriptor ->
|
is PropertyDescriptor ->
|
||||||
generatePropertyGetterCall(descriptor, startOffset, endOffset, call)
|
generatePropertyGetterCall(descriptor, startOffset, endOffset, call)
|
||||||
|
is VariableDescriptor ->
|
||||||
|
call.callReceiver.call { dispatchReceiverValue, extensionReceiverValue ->
|
||||||
|
IrGetVariableImpl(startOffset, endOffset, descriptor, operator)
|
||||||
|
}
|
||||||
is FunctionDescriptor ->
|
is FunctionDescriptor ->
|
||||||
generateFunctionCall(descriptor, startOffset, endOffset, operator, call)
|
generateFunctionCall(descriptor, startOffset, endOffset, operator, call)
|
||||||
else ->
|
else ->
|
||||||
|
|||||||
+5
-5
@@ -26,9 +26,7 @@ import org.jetbrains.kotlin.psi.*
|
|||||||
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
||||||
import org.jetbrains.kotlin.psi2ir.deparenthesize
|
import org.jetbrains.kotlin.psi2ir.deparenthesize
|
||||||
import org.jetbrains.kotlin.psi2ir.intermediate.Value
|
import org.jetbrains.kotlin.psi2ir.intermediate.*
|
||||||
import org.jetbrains.kotlin.psi2ir.intermediate.createRematerializableOrTemporary
|
|
||||||
import org.jetbrains.kotlin.psi2ir.intermediate.setExplicitReceiverValue
|
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.BindingContextUtils
|
import org.jetbrains.kotlin.resolve.BindingContextUtils
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
@@ -183,7 +181,8 @@ class StatementGenerator(
|
|||||||
val resolvedCall = getResolvedCall(expression) ?: throw AssertionError("No resolved call for ${expression.text}")
|
val resolvedCall = getResolvedCall(expression) ?: throw AssertionError("No resolved call for ${expression.text}")
|
||||||
|
|
||||||
if (resolvedCall is VariableAsFunctionResolvedCall) {
|
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
|
val descriptor = resolvedCall.resultingDescriptor
|
||||||
@@ -222,7 +221,8 @@ class StatementGenerator(
|
|||||||
val resolvedCall = getResolvedCall(expression) ?: TODO("No resolved call for call expression")
|
val resolvedCall = getResolvedCall(expression) ?: TODO("No resolved call for call expression")
|
||||||
|
|
||||||
if (resolvedCall is VariableAsFunctionResolvedCall) {
|
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))
|
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
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
|
||||||
class OnceCallValue(
|
class OnceCallValue(
|
||||||
val statementGenerator: StatementGenerator,
|
|
||||||
val call: CallBuilder,
|
|
||||||
val startOffset: Int,
|
val startOffset: Int,
|
||||||
val endOffset: Int,
|
val endOffset: Int,
|
||||||
|
val statementGenerator: StatementGenerator,
|
||||||
|
val call: CallBuilder,
|
||||||
val operator: IrOperator? = null
|
val operator: IrOperator? = null
|
||||||
): Value {
|
): Value {
|
||||||
private var instantiated = false
|
private var instantiated = false
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ interface IrOperator {
|
|||||||
object RANGE : IrOperatorImpl("RANGE")
|
object RANGE : IrOperatorImpl("RANGE")
|
||||||
|
|
||||||
object INVOKE : IrOperatorImpl("INVOKE")
|
object INVOKE : IrOperatorImpl("INVOKE")
|
||||||
|
object VARIABLE_AS_FUNCTION : IrOperatorImpl("VARIABLE_AS_FUNCTION")
|
||||||
object GET_ARRAY_ELEMENT : IrOperatorImpl("GET_ARRAY_ELEMENT")
|
object GET_ARRAY_ELEMENT : IrOperatorImpl("GET_ARRAY_ELEMENT")
|
||||||
|
|
||||||
object PREFIX_INCR : IrOperatorImpl("PREFIX_INCR")
|
object PREFIX_INCR : IrOperatorImpl("PREFIX_INCR")
|
||||||
|
|||||||
@@ -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()
|
||||||
@@ -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);
|
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")
|
@TestMetadata("when.kt")
|
||||||
public void testWhen() throws Exception {
|
public void testWhen() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/when.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/when.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user