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.declarations.IrDeclarationOrigin
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunctionImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.IrBlockImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.IrCallableReferenceImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.IrOperator
|
||||
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.startOffset
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
@@ -46,4 +48,28 @@ class LocalFunctionGenerator(val statementGenerator: StatementGenerator) : Gener
|
||||
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 =
|
||||
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 {
|
||||
val label = expression.getTargetLabel()
|
||||
@@ -140,7 +140,7 @@ class StatementGenerator(
|
||||
BindingContextUtils.getContainingFunctionSkipFunctionLiterals(scopeOwner, true).first
|
||||
}
|
||||
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 =
|
||||
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 LAMBDA : IrOperatorImpl("LAMBDA")
|
||||
|
||||
object ANONYMOUS_FUNCTION : IrOperatorImpl("ANONYMOUS_FUNCTION")
|
||||
|
||||
data class COMPONENT_N private constructor(val index: Int) : IrOperatorImpl("COMPONENT_$index") {
|
||||
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);
|
||||
}
|
||||
|
||||
@TestMetadata("anonymousFunction.kt")
|
||||
public void testAnonymousFunction() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/lambdas/anonymousFunction.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("extensionLambda.kt")
|
||||
public void testExtensionLambda() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/lambdas/extensionLambda.kt");
|
||||
@@ -373,6 +379,12 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase {
|
||||
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")
|
||||
public void testMultipleImplicitReceivers() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/lambdas/multipleImplicitReceivers.kt");
|
||||
|
||||
Reference in New Issue
Block a user