Anonymous function expressions ('fun(...) { ... }') and local functions (no closures yet).
This commit is contained in:
committed by
Dmitry Petrov
parent
83c3bdd788
commit
ac80195597
+26
@@ -18,11 +18,13 @@ package org.jetbrains.kotlin.psi2ir.generators
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.ir.IrStatement
|
import org.jetbrains.kotlin.ir.IrStatement
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
|
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFunctionImpl
|
import org.jetbrains.kotlin.ir.declarations.IrFunctionImpl
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrBlockImpl
|
import org.jetbrains.kotlin.ir.expressions.IrBlockImpl
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrCallableReferenceImpl
|
import org.jetbrains.kotlin.ir.expressions.IrCallableReferenceImpl
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrOperator
|
import org.jetbrains.kotlin.ir.expressions.IrOperator
|
||||||
import org.jetbrains.kotlin.psi.KtLambdaExpression
|
import org.jetbrains.kotlin.psi.KtLambdaExpression
|
||||||
|
import org.jetbrains.kotlin.psi.KtNamedFunction
|
||||||
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.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
@@ -46,4 +48,28 @@ class LocalFunctionGenerator(val statementGenerator: StatementGenerator) : Gener
|
|||||||
return irBlock
|
return irBlock
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun generateFunction(ktFun: KtNamedFunction): IrStatement =
|
||||||
|
if (ktFun.name != null) {
|
||||||
|
generateFunctionDeclaration(ktFun)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// anonymous function expression
|
||||||
|
val funExpressionType = getInferredTypeWithSmartcastsOrFail(ktFun)
|
||||||
|
val irBlock = IrBlockImpl(ktFun.startOffset, ktFun.endOffset, funExpressionType, IrOperator.ANONYMOUS_FUNCTION)
|
||||||
|
|
||||||
|
val irFun = generateFunctionDeclaration(ktFun)
|
||||||
|
irBlock.addStatement(irFun)
|
||||||
|
|
||||||
|
irBlock.addStatement(IrCallableReferenceImpl(ktFun.startOffset, ktFun.endOffset, funExpressionType, irFun.descriptor))
|
||||||
|
|
||||||
|
irBlock
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun generateFunctionDeclaration(ktFun: KtNamedFunction): IrFunction {
|
||||||
|
val funDescriptor = getOrFail(BindingContext.FUNCTION, ktFun)
|
||||||
|
val irFun = IrFunctionImpl(ktFun.startOffset, ktFun.endOffset, IrDeclarationOrigin.DEFINED, funDescriptor)
|
||||||
|
irFun.body = BodyGenerator(funDescriptor, statementGenerator.context).generateFunctionBody(ktFun.bodyExpression!!)
|
||||||
|
return irFun
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
+5
-2
@@ -127,7 +127,7 @@ class StatementGenerator(
|
|||||||
|
|
||||||
private fun getReturnExpressionTarget(expression: KtReturnExpression): CallableDescriptor =
|
private fun getReturnExpressionTarget(expression: KtReturnExpression): CallableDescriptor =
|
||||||
if (!ExpressionTypingUtils.isFunctionLiteral(scopeOwner) && !ExpressionTypingUtils.isFunctionExpression(scopeOwner)) {
|
if (!ExpressionTypingUtils.isFunctionLiteral(scopeOwner) && !ExpressionTypingUtils.isFunctionExpression(scopeOwner)) {
|
||||||
scopeOwner as? CallableDescriptor ?: throw AssertionError("Return not in a callable: $scopeOwner")
|
scopeOwner ?: throw AssertionError("Return not in a callable: $scopeOwner")
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
val label = expression.getTargetLabel()
|
val label = expression.getTargetLabel()
|
||||||
@@ -140,7 +140,7 @@ class StatementGenerator(
|
|||||||
BindingContextUtils.getContainingFunctionSkipFunctionLiterals(scopeOwner, true).first
|
BindingContextUtils.getContainingFunctionSkipFunctionLiterals(scopeOwner, true).first
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
scopeOwner as? CallableDescriptor ?: throw AssertionError("Return not in a callable: $scopeOwner")
|
scopeOwner ?: throw AssertionError("Return not in a callable: $scopeOwner")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -321,5 +321,8 @@ class StatementGenerator(
|
|||||||
|
|
||||||
override fun visitLambdaExpression(expression: KtLambdaExpression, data: Nothing?): IrStatement =
|
override fun visitLambdaExpression(expression: KtLambdaExpression, data: Nothing?): IrStatement =
|
||||||
LocalFunctionGenerator(this).generateLambda(expression)
|
LocalFunctionGenerator(this).generateLambda(expression)
|
||||||
|
|
||||||
|
override fun visitNamedFunction(function: KtNamedFunction, data: Nothing?): IrStatement =
|
||||||
|
LocalFunctionGenerator(this).generateFunction(function)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ interface IrOperator {
|
|||||||
object FOR_LOOP_NEXT : IrOperatorImpl("FOR_LOOP_NEXT")
|
object FOR_LOOP_NEXT : IrOperatorImpl("FOR_LOOP_NEXT")
|
||||||
|
|
||||||
object LAMBDA : IrOperatorImpl("LAMBDA")
|
object LAMBDA : IrOperatorImpl("LAMBDA")
|
||||||
|
object ANONYMOUS_FUNCTION : IrOperatorImpl("ANONYMOUS_FUNCTION")
|
||||||
|
|
||||||
data class COMPONENT_N private constructor(val index: Int) : IrOperatorImpl("COMPONENT_$index") {
|
data class COMPONENT_N private constructor(val index: Int) : IrOperatorImpl("COMPONENT_$index") {
|
||||||
companion object {
|
companion object {
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
val anonymous = fun() { println() }
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
FILE /anonymousFunction.kt
|
||||||
|
PROPERTY public val anonymous: () -> kotlin.Unit getter=null setter=null
|
||||||
|
EXPRESSION_BODY
|
||||||
|
BLOCK type=() -> kotlin.Unit operator=ANONYMOUS_FUNCTION
|
||||||
|
FUN local final fun <no name provided>(): kotlin.Unit
|
||||||
|
BLOCK_BODY
|
||||||
|
CALL .println type=kotlin.Unit operator=null
|
||||||
|
CALLABLE_REFERENCE local final fun <no name provided>(): kotlin.Unit type=() -> kotlin.Unit
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
fun outer() {
|
||||||
|
var x = 0
|
||||||
|
fun local() { x++ }
|
||||||
|
local()
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
FILE /localFunction.kt
|
||||||
|
FUN public fun outer(): kotlin.Unit
|
||||||
|
BLOCK_BODY
|
||||||
|
VAR var x: kotlin.Int
|
||||||
|
CONST Int type=kotlin.Int value='0'
|
||||||
|
FUN local final fun local(): kotlin.Unit
|
||||||
|
BLOCK_BODY
|
||||||
|
BLOCK type=kotlin.Int operator=POSTFIX_INCR
|
||||||
|
VAR val tmp0: kotlin.Int
|
||||||
|
GET_VAR x type=kotlin.Int operator=POSTFIX_INCR
|
||||||
|
SET_VAR x type=kotlin.Unit operator=POSTFIX_INCR
|
||||||
|
CALL .inc type=kotlin.Int operator=POSTFIX_INCR
|
||||||
|
$this: GET_VAR tmp0 type=kotlin.Int operator=null
|
||||||
|
GET_VAR tmp0 type=kotlin.Int operator=null
|
||||||
|
CALL .local type=kotlin.Unit operator=null
|
||||||
@@ -361,6 +361,12 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase {
|
|||||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/ir/irText/lambdas"), Pattern.compile("^(.+)\\.kt$"), true);
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/ir/irText/lambdas"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("anonymousFunction.kt")
|
||||||
|
public void testAnonymousFunction() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/lambdas/anonymousFunction.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("extensionLambda.kt")
|
@TestMetadata("extensionLambda.kt")
|
||||||
public void testExtensionLambda() throws Exception {
|
public void testExtensionLambda() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/lambdas/extensionLambda.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/lambdas/extensionLambda.kt");
|
||||||
@@ -373,6 +379,12 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("localFunction.kt")
|
||||||
|
public void testLocalFunction() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/lambdas/localFunction.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("multipleImplicitReceivers.kt")
|
@TestMetadata("multipleImplicitReceivers.kt")
|
||||||
public void testMultipleImplicitReceivers() throws Exception {
|
public void testMultipleImplicitReceivers() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/lambdas/multipleImplicitReceivers.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/lambdas/multipleImplicitReceivers.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user