From 35dd1cf75a8c91ce26c3e78e1387ccbebcf75f20 Mon Sep 17 00:00:00 2001 From: Dmitriy Novozhilov Date: Mon, 18 Nov 2019 11:51:09 +0300 Subject: [PATCH] [FIR] Fix binding return expression to function --- .../converter/DeclarationsConverter.kt | 2 +- .../converter/ExpressionsConverter.kt | 2 +- .../kotlin/fir/builder/BaseFirBuilder.kt | 2 +- .../kotlin/fir/builder/RawFirBuilder.kt | 4 +- .../expressions/lambdaAndAnonymousFunction.kt | 10 ++++ .../lambdaAndAnonymousFunction.txt | 20 +++++++ .../RawFirBuilderTestCaseGenerated.java | 5 ++ .../src/org/jetbrains/kotlin/fir/CopyUtils.kt | 2 +- .../resolve/cfg/returnValuesFromLambda.dot | 24 ++++---- .../resolve/cfg/returnValuesFromLambda.txt | 4 +- .../testData/resolve/smartcasts/safeCalls.dot | 55 ++++++++++--------- .../testData/resolve/smartcasts/safeCalls.txt | 4 +- .../fir/declarations/FirAnonymousFunction.kt | 1 + .../impl/FirAnonymousFunctionImpl.kt | 3 +- .../fir/tree/generator/NodeConfigurator.kt | 1 + .../ir/irText/lambdas/nonLocalReturn.fir.txt | 2 +- .../FirVisualizerForRawFirDataGenerated.java | 5 ++ .../PsiVisualizerForRawFirDataGenerated.java | 5 ++ 18 files changed, 101 insertions(+), 50 deletions(-) create mode 100644 compiler/fir/psi2fir/testData/rawBuilder/expressions/lambdaAndAnonymousFunction.kt create mode 100644 compiler/fir/psi2fir/testData/rawBuilder/expressions/lambdaAndAnonymousFunction.txt diff --git a/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/converter/DeclarationsConverter.kt b/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/converter/DeclarationsConverter.kt index 3788b997e1a..0f0927c7f13 100644 --- a/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/converter/DeclarationsConverter.kt +++ b/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/converter/DeclarationsConverter.kt @@ -1037,7 +1037,7 @@ class DeclarationsConverter( val parentNode = functionDeclaration.getParent() val isLocal = !(parentNode?.tokenType == KT_FILE || parentNode?.tokenType == CLASS_BODY) val firFunction = if (identifier == null) { - FirAnonymousFunctionImpl(null, session, returnType!!, receiverType, FirAnonymousFunctionSymbol()) + FirAnonymousFunctionImpl(null, session, returnType!!, receiverType, FirAnonymousFunctionSymbol(), isLambda = false) } else { val functionName = identifier.nameAsSafeName() val status = FirDeclarationStatusImpl( diff --git a/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/converter/ExpressionsConverter.kt b/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/converter/ExpressionsConverter.kt index b0d10e48996..3c3f304e392 100644 --- a/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/converter/ExpressionsConverter.kt +++ b/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/converter/ExpressionsConverter.kt @@ -127,7 +127,7 @@ class ExpressionsConverter( } } - return FirAnonymousFunctionImpl(null, session, implicitType, implicitType, FirAnonymousFunctionSymbol()).apply { + return FirAnonymousFunctionImpl(null, session, implicitType, implicitType, FirAnonymousFunctionSymbol(), isLambda = true).apply { context.firFunctions += this var destructuringBlock: FirExpression? = null for (valueParameter in valueParameterList) { diff --git a/compiler/fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/BaseFirBuilder.kt b/compiler/fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/BaseFirBuilder.kt index a904ad4935b..fedddfea3ca 100644 --- a/compiler/fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/BaseFirBuilder.kt +++ b/compiler/fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/BaseFirBuilder.kt @@ -105,8 +105,8 @@ abstract class BaseFirBuilder(val session: FirSession, val context: Context = this ).apply { target = FirFunctionTarget(labelName) - val lastFunction = context.firFunctions.lastOrNull() if (labelName == null) { + val lastFunction = context.firFunctions.lastOrNull { !(it is FirAnonymousFunction && it.isLambda) } if (lastFunction != null) { target.bind(lastFunction) } else { diff --git a/compiler/fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/RawFirBuilder.kt b/compiler/fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/RawFirBuilder.kt index 85c0647ed4b..629f7b45aad 100644 --- a/compiler/fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/RawFirBuilder.kt +++ b/compiler/fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/RawFirBuilder.kt @@ -592,7 +592,7 @@ class RawFirBuilder(session: FirSession, val stubMode: Boolean) : BaseFirBuilder } val receiverType = function.receiverTypeReference.convertSafe() val firFunction = if (function.name == null) { - FirAnonymousFunctionImpl(function.toFirSourceElement(), session, returnType, receiverType, FirAnonymousFunctionSymbol()) + FirAnonymousFunctionImpl(function.toFirSourceElement(), session, returnType, receiverType, FirAnonymousFunctionSymbol(), isLambda = false) } else { val status = FirDeclarationStatusImpl( if (function.isLocal) Visibilities.LOCAL else function.visibility, @@ -636,7 +636,7 @@ class RawFirBuilder(session: FirSession, val stubMode: Boolean) : BaseFirBuilder val literalSource = literal.toFirSourceElement() val returnType = FirImplicitTypeRefImpl(literalSource) val receiverType = FirImplicitTypeRefImpl(literalSource) - return FirAnonymousFunctionImpl(literalSource, session, returnType, receiverType, FirAnonymousFunctionSymbol()).apply { + return FirAnonymousFunctionImpl(literalSource, session, returnType, receiverType, FirAnonymousFunctionSymbol(), isLambda = true).apply { context.firFunctions += this var destructuringBlock: FirExpression? = null for (valueParameter in literal.valueParameters) { diff --git a/compiler/fir/psi2fir/testData/rawBuilder/expressions/lambdaAndAnonymousFunction.kt b/compiler/fir/psi2fir/testData/rawBuilder/expressions/lambdaAndAnonymousFunction.kt new file mode 100644 index 00000000000..8b0a3bc7e06 --- /dev/null +++ b/compiler/fir/psi2fir/testData/rawBuilder/expressions/lambdaAndAnonymousFunction.kt @@ -0,0 +1,10 @@ +fun run(block: () -> T): T = block() + +fun test_1() { + run { return@run } + run { return } +} + +fun test_2() { + run(fun (): Int { return 1 }) +} \ No newline at end of file diff --git a/compiler/fir/psi2fir/testData/rawBuilder/expressions/lambdaAndAnonymousFunction.txt b/compiler/fir/psi2fir/testData/rawBuilder/expressions/lambdaAndAnonymousFunction.txt new file mode 100644 index 00000000000..aa0b3eea139 --- /dev/null +++ b/compiler/fir/psi2fir/testData/rawBuilder/expressions/lambdaAndAnonymousFunction.txt @@ -0,0 +1,20 @@ +FILE: lambdaAndAnonymousFunction.kt + public? final? fun run(block: ( () -> T )): T { + ^run block#() + } + public? final? fun test_1(): R|kotlin/Unit| { + run#( = run@fun .(): { + ^@run Unit + } + ) + run#( = run@fun .(): { + ^test_1 Unit + } + ) + } + public? final? fun test_2(): R|kotlin/Unit| { + run#(fun (): Int { + ^ Int(1) + } + ) + } diff --git a/compiler/fir/psi2fir/tests/org/jetbrains/kotlin/fir/builder/RawFirBuilderTestCaseGenerated.java b/compiler/fir/psi2fir/tests/org/jetbrains/kotlin/fir/builder/RawFirBuilderTestCaseGenerated.java index ef4eb5cdda7..a5f1c040141 100644 --- a/compiler/fir/psi2fir/tests/org/jetbrains/kotlin/fir/builder/RawFirBuilderTestCaseGenerated.java +++ b/compiler/fir/psi2fir/tests/org/jetbrains/kotlin/fir/builder/RawFirBuilderTestCaseGenerated.java @@ -223,6 +223,11 @@ public class RawFirBuilderTestCaseGenerated extends AbstractRawFirBuilderTestCas runTest("compiler/fir/psi2fir/testData/rawBuilder/expressions/lambda.kt"); } + @TestMetadata("lambdaAndAnonymousFunction.kt") + public void testLambdaAndAnonymousFunction() throws Exception { + runTest("compiler/fir/psi2fir/testData/rawBuilder/expressions/lambdaAndAnonymousFunction.kt"); + } + @TestMetadata("locals.kt") public void testLocals() throws Exception { runTest("compiler/fir/psi2fir/testData/rawBuilder/expressions/locals.kt"); diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/CopyUtils.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/CopyUtils.kt index 86101adc05e..6ac29485dee 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/CopyUtils.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/CopyUtils.kt @@ -62,7 +62,7 @@ fun FirAnonymousFunction.copy( controlFlowGraphReference: FirControlFlowGraphReference = this.controlFlowGraphReference, invocationKind: InvocationKind? = this.invocationKind ): FirAnonymousFunction { - return FirAnonymousFunctionImpl(source, session, returnTypeRef, receiverTypeRef, symbol).apply { + return FirAnonymousFunctionImpl(source, session, returnTypeRef, receiverTypeRef, symbol, isLambda).apply { this.valueParameters.addAll(valueParameters) this.body = body this.annotations.addAll(annotations) diff --git a/compiler/fir/resolve/testData/resolve/cfg/returnValuesFromLambda.dot b/compiler/fir/resolve/testData/resolve/cfg/returnValuesFromLambda.dot index 488da1e02d7..92bd357e2f9 100644 --- a/compiler/fir/resolve/testData/resolve/cfg/returnValuesFromLambda.dot +++ b/compiler/fir/resolve/testData/resolve/cfg/returnValuesFromLambda.dot @@ -120,25 +120,27 @@ digraph returnValuesFromLambda_kt { subgraph cluster_10 { color=blue 34 [label="Enter function anonymousFunction"]; - 35 [label="Jump: ^ Unit"]; + 35 [label="Jump: ^test_3 Unit"]; 36 [label="Stub" style="filled" fillcolor=gray]; - 37 [label="Exit function anonymousFunction"]; + 37 [label="Exit function anonymousFunction" style="filled" fillcolor=gray]; } - 38 [label="Function call: R|kotlin/run|( = run@fun (): R|kotlin/Unit| { - ^ Unit + 38 [label="Function call: R|kotlin/run|( = run@fun (): R|kotlin/Unit| { + ^test_3 Unit } -)"]; - 39 [label="Variable declaration: lval x: R|kotlin/Unit|"]; - 40 [label="Exit function test_3" style="filled" fillcolor=red]; +)" style="filled" fillcolor=gray]; + 39 [label="Stub" style="filled" fillcolor=gray]; + 40 [label="Variable declaration: lval x: R|kotlin/Nothing|" style="filled" fillcolor=gray]; + 41 [label="Exit function test_3" style="filled" fillcolor=red]; } 33 -> {34}; 34 -> {35}; - 35 -> {37}; + 35 -> {41}; 35 -> {36} [style=dotted]; 36 -> {37} [style=dotted]; - 37 -> {38}; - 38 -> {39}; - 39 -> {40}; + 37 -> {38} [style=dotted]; + 38 -> {41 39} [style=dotted]; + 39 -> {40} [style=dotted]; + 40 -> {41} [style=dotted]; } diff --git a/compiler/fir/resolve/testData/resolve/cfg/returnValuesFromLambda.txt b/compiler/fir/resolve/testData/resolve/cfg/returnValuesFromLambda.txt index 683db32877b..cbb5a51225c 100644 --- a/compiler/fir/resolve/testData/resolve/cfg/returnValuesFromLambda.txt +++ b/compiler/fir/resolve/testData/resolve/cfg/returnValuesFromLambda.txt @@ -32,8 +32,8 @@ FILE: returnValuesFromLambda.kt ) } public final fun test_3(): R|kotlin/Unit| { - lval x: R|kotlin/Unit| = R|kotlin/run|( = run@fun (): R|kotlin/Unit| { - ^ Unit + lval x: R|kotlin/Nothing| = R|kotlin/run|( = run@fun (): R|kotlin/Unit| { + ^test_3 Unit } ) } diff --git a/compiler/fir/resolve/testData/resolve/smartcasts/safeCalls.dot b/compiler/fir/resolve/testData/resolve/smartcasts/safeCalls.dot index f25698cef23..99190369ed8 100644 --- a/compiler/fir/resolve/testData/resolve/smartcasts/safeCalls.dot +++ b/compiler/fir/resolve/testData/resolve/smartcasts/safeCalls.dot @@ -195,44 +195,45 @@ digraph safeCalls_kt { subgraph cluster_12 { color=blue 71 [label="Enter function anonymousFunction"]; - 72 [label="Jump: ^ Unit"]; + 72 [label="Jump: ^test_5 Unit"]; 73 [label="Stub" style="filled" fillcolor=gray]; - 74 [label="Exit function anonymousFunction"]; + 74 [label="Exit function anonymousFunction" style="filled" fillcolor=gray]; } - 75 [label="Function call: R|/x|?.R|kotlin/let|( = let@fun (it: R|A|): R|kotlin/Unit| { - ^ Unit + 75 [label="Function call: R|/x|?.R|kotlin/let|( = let@fun (it: R|A|): R|kotlin/Unit| { + ^test_5 Unit } -)"]; - 76 [label="Exit safe call"]; - 77 [label="Enter safe call"]; - 78 [label="Access variable R|/x|"]; - 79 [label="Function call: R|/x|.R|/A.bool|()"]; - 80 [label="Function call: R|/x|?.R|kotlin/let|( = let@fun (it: R|A|): R|kotlin/Unit| { - ^ Unit +)" style="filled" fillcolor=gray]; + 76 [label="Exit safe call" style="filled" fillcolor=gray]; + 77 [label="Enter safe call" style="filled" fillcolor=gray]; + 78 [label="Access variable R|/x|" style="filled" fillcolor=gray]; + 79 [label="Function call: R|/x|.R|/A.bool|()" style="filled" fillcolor=gray]; + 80 [label="Function call: R|/x|?.R|kotlin/let|( = let@fun (it: R|A|): R|kotlin/Unit| { + ^test_5 Unit } -)?.R|/boo|(R|/x|.R|/A.bool|())"]; - 81 [label="Exit safe call"]; - 82 [label="Access variable R|/x|"]; - 83 [label="Function call: R|/x|.#()"]; +)?.R|/boo|(R|/x|.R|/A.bool|())" style="filled" fillcolor=gray]; + 81 [label="Exit safe call" style="filled" fillcolor=gray]; + 82 [label="Access variable R|/x|" style="filled" fillcolor=gray]; + 83 [label="Function call: R|/x|.#()" style="filled" fillcolor=gray]; 84 [label="Exit function test_5" style="filled" fillcolor=red]; } 68 -> {69}; - 69 -> {70 76}; + 69 -> {70}; + 69 -> {76} [style=dotted]; 70 -> {71}; 71 -> {72}; - 72 -> {74}; + 72 -> {84}; 72 -> {73} [style=dotted]; 73 -> {74} [style=dotted]; - 74 -> {75}; - 75 -> {76}; - 76 -> {77 81}; - 77 -> {78}; - 78 -> {79}; - 79 -> {80}; - 80 -> {81}; - 81 -> {82}; - 82 -> {83}; - 83 -> {84}; + 74 -> {75} [style=dotted]; + 75 -> {76} [style=dotted]; + 76 -> {77 81} [style=dotted]; + 77 -> {78} [style=dotted]; + 78 -> {79} [style=dotted]; + 79 -> {80} [style=dotted]; + 80 -> {81} [style=dotted]; + 81 -> {82} [style=dotted]; + 82 -> {83} [style=dotted]; + 83 -> {84} [style=dotted]; } diff --git a/compiler/fir/resolve/testData/resolve/smartcasts/safeCalls.txt b/compiler/fir/resolve/testData/resolve/smartcasts/safeCalls.txt index 62b8f3926b4..76d250e6eb2 100644 --- a/compiler/fir/resolve/testData/resolve/smartcasts/safeCalls.txt +++ b/compiler/fir/resolve/testData/resolve/smartcasts/safeCalls.txt @@ -32,8 +32,8 @@ FILE: safeCalls.kt } public final fun R|kotlin/Any?|.boo(b: R|kotlin/Boolean|): R|kotlin/Unit| public final fun test_5(x: R|A?|): R|kotlin/Unit| { - R|/x|?.R|kotlin/let|( = let@fun (it: R|A|): R|kotlin/Unit| { - ^ Unit + R|/x|?.R|kotlin/let|( = let@fun (it: R|A|): R|kotlin/Unit| { + ^test_5 Unit } )?.R|/boo|(R|/x|.R|/A.bool|()) R|/x|.#() diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/FirAnonymousFunction.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/FirAnonymousFunction.kt index cdbe4fd69c0..8efa6b2a56c 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/FirAnonymousFunction.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/FirAnonymousFunction.kt @@ -38,6 +38,7 @@ abstract class FirAnonymousFunction : FirPureAbstractElement(), FirFunction accept(visitor: FirVisitor, data: D): R = visitor.visitAnonymousFunction(this, data) diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/impl/FirAnonymousFunctionImpl.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/impl/FirAnonymousFunctionImpl.kt index 2fdade43409..205626a7666 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/impl/FirAnonymousFunctionImpl.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/impl/FirAnonymousFunctionImpl.kt @@ -33,7 +33,8 @@ class FirAnonymousFunctionImpl( override val session: FirSession, override var returnTypeRef: FirTypeRef, override var receiverTypeRef: FirTypeRef?, - override val symbol: FirAnonymousFunctionSymbol + override val symbol: FirAnonymousFunctionSymbol, + override val isLambda: Boolean ) : FirAnonymousFunction(), FirModifiableFunction, FirAbstractAnnotatedElement { override var resolvePhase: FirResolvePhase = FirResolvePhase.DECLARATIONS override val annotations: MutableList = mutableListOf() diff --git a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/NodeConfigurator.kt b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/NodeConfigurator.kt index 1055313bdcc..5eb03bede60 100644 --- a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/NodeConfigurator.kt +++ b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/NodeConfigurator.kt @@ -253,6 +253,7 @@ object NodeConfigurator : AbstractFieldConfigurator() { +field(invocationKindType, nullable = true, withReplace = true).apply { isMutable = true } + +booleanField("isLambda") } typeParameter.configure { diff --git a/compiler/testData/ir/irText/lambdas/nonLocalReturn.fir.txt b/compiler/testData/ir/irText/lambdas/nonLocalReturn.fir.txt index 40cf61d9c90..825f7c55e6c 100644 --- a/compiler/testData/ir/irText/lambdas/nonLocalReturn.fir.txt +++ b/compiler/testData/ir/irText/lambdas/nonLocalReturn.fir.txt @@ -5,7 +5,7 @@ FILE fqName: fileName:/nonLocalReturn.kt block: FUN_EXPR type=kotlin.Function0 origin=LAMBDA FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> () returnType:kotlin.Unit BLOCK_BODY - RETURN type=kotlin.Nothing from='local final fun (): kotlin.Unit declared in .test0' + RETURN type=kotlin.Nothing from='public final fun test0 (): kotlin.Unit declared in ' GET_OBJECT 'CLASS IR_EXTERNAL_DECLARATION_STUB OBJECT name:Unit modality:FINAL visibility:public superTypes:[kotlin.Any]' type=kotlin.Unit FUN name:test1 visibility:public modality:FINAL <> () returnType:kotlin.Unit BLOCK_BODY diff --git a/compiler/visualizer/tests/org/jetbrains/kotlin/visualizer/fir/FirVisualizerForRawFirDataGenerated.java b/compiler/visualizer/tests/org/jetbrains/kotlin/visualizer/fir/FirVisualizerForRawFirDataGenerated.java index b1f9d8659b8..5bf1a0a75a6 100644 --- a/compiler/visualizer/tests/org/jetbrains/kotlin/visualizer/fir/FirVisualizerForRawFirDataGenerated.java +++ b/compiler/visualizer/tests/org/jetbrains/kotlin/visualizer/fir/FirVisualizerForRawFirDataGenerated.java @@ -223,6 +223,11 @@ public class FirVisualizerForRawFirDataGenerated extends AbstractFirVisualizer { runTest("compiler/fir/psi2fir/testData/rawBuilder/expressions/lambda.kt"); } + @TestMetadata("lambdaAndAnonymousFunction.kt") + public void testLambdaAndAnonymousFunction() throws Exception { + runTest("compiler/fir/psi2fir/testData/rawBuilder/expressions/lambdaAndAnonymousFunction.kt"); + } + @TestMetadata("locals.kt") public void testLocals() throws Exception { runTest("compiler/fir/psi2fir/testData/rawBuilder/expressions/locals.kt"); diff --git a/compiler/visualizer/tests/org/jetbrains/kotlin/visualizer/psi/PsiVisualizerForRawFirDataGenerated.java b/compiler/visualizer/tests/org/jetbrains/kotlin/visualizer/psi/PsiVisualizerForRawFirDataGenerated.java index ec4ed5f55a4..ec13a3b7c52 100644 --- a/compiler/visualizer/tests/org/jetbrains/kotlin/visualizer/psi/PsiVisualizerForRawFirDataGenerated.java +++ b/compiler/visualizer/tests/org/jetbrains/kotlin/visualizer/psi/PsiVisualizerForRawFirDataGenerated.java @@ -223,6 +223,11 @@ public class PsiVisualizerForRawFirDataGenerated extends AbstractPsiVisualizer { runTest("compiler/fir/psi2fir/testData/rawBuilder/expressions/lambda.kt"); } + @TestMetadata("lambdaAndAnonymousFunction.kt") + public void testLambdaAndAnonymousFunction() throws Exception { + runTest("compiler/fir/psi2fir/testData/rawBuilder/expressions/lambdaAndAnonymousFunction.kt"); + } + @TestMetadata("locals.kt") public void testLocals() throws Exception { runTest("compiler/fir/psi2fir/testData/rawBuilder/expressions/locals.kt");