[FIR] Fix binding return expression to function

This commit is contained in:
Dmitriy Novozhilov
2019-11-18 11:51:09 +03:00
parent 98378d8973
commit 35dd1cf75a
18 changed files with 101 additions and 50 deletions
@@ -1037,7 +1037,7 @@ class DeclarationsConverter(
val parentNode = functionDeclaration.getParent() val parentNode = functionDeclaration.getParent()
val isLocal = !(parentNode?.tokenType == KT_FILE || parentNode?.tokenType == CLASS_BODY) val isLocal = !(parentNode?.tokenType == KT_FILE || parentNode?.tokenType == CLASS_BODY)
val firFunction = if (identifier == null) { val firFunction = if (identifier == null) {
FirAnonymousFunctionImpl(null, session, returnType!!, receiverType, FirAnonymousFunctionSymbol()) FirAnonymousFunctionImpl(null, session, returnType!!, receiverType, FirAnonymousFunctionSymbol(), isLambda = false)
} else { } else {
val functionName = identifier.nameAsSafeName() val functionName = identifier.nameAsSafeName()
val status = FirDeclarationStatusImpl( val status = FirDeclarationStatusImpl(
@@ -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 context.firFunctions += this
var destructuringBlock: FirExpression? = null var destructuringBlock: FirExpression? = null
for (valueParameter in valueParameterList) { for (valueParameter in valueParameterList) {
@@ -105,8 +105,8 @@ abstract class BaseFirBuilder<T>(val session: FirSession, val context: Context =
this this
).apply { ).apply {
target = FirFunctionTarget(labelName) target = FirFunctionTarget(labelName)
val lastFunction = context.firFunctions.lastOrNull()
if (labelName == null) { if (labelName == null) {
val lastFunction = context.firFunctions.lastOrNull { !(it is FirAnonymousFunction && it.isLambda) }
if (lastFunction != null) { if (lastFunction != null) {
target.bind(lastFunction) target.bind(lastFunction)
} else { } else {
@@ -592,7 +592,7 @@ class RawFirBuilder(session: FirSession, val stubMode: Boolean) : BaseFirBuilder
} }
val receiverType = function.receiverTypeReference.convertSafe<FirTypeRef>() val receiverType = function.receiverTypeReference.convertSafe<FirTypeRef>()
val firFunction = if (function.name == null) { val firFunction = if (function.name == null) {
FirAnonymousFunctionImpl(function.toFirSourceElement(), session, returnType, receiverType, FirAnonymousFunctionSymbol()) FirAnonymousFunctionImpl(function.toFirSourceElement(), session, returnType, receiverType, FirAnonymousFunctionSymbol(), isLambda = false)
} else { } else {
val status = FirDeclarationStatusImpl( val status = FirDeclarationStatusImpl(
if (function.isLocal) Visibilities.LOCAL else function.visibility, 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 literalSource = literal.toFirSourceElement()
val returnType = FirImplicitTypeRefImpl(literalSource) val returnType = FirImplicitTypeRefImpl(literalSource)
val receiverType = 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 context.firFunctions += this
var destructuringBlock: FirExpression? = null var destructuringBlock: FirExpression? = null
for (valueParameter in literal.valueParameters) { for (valueParameter in literal.valueParameters) {
@@ -0,0 +1,10 @@
fun <T> run(block: () -> T): T = block()
fun test_1() {
run { return@run }
run { return }
}
fun test_2() {
run(fun (): Int { return 1 })
}
@@ -0,0 +1,20 @@
FILE: lambdaAndAnonymousFunction.kt
public? final? fun <T> run(block: ( () -> T )): T {
^run block#()
}
public? final? fun test_1(): R|kotlin/Unit| {
run#(<L> = run@fun <implicit>.<anonymous>(): <implicit> {
^@run Unit
}
)
run#(<L> = run@fun <implicit>.<anonymous>(): <implicit> {
^test_1 Unit
}
)
}
public? final? fun test_2(): R|kotlin/Unit| {
run#(fun <anonymous>(): Int {
^ Int(1)
}
)
}
@@ -223,6 +223,11 @@ public class RawFirBuilderTestCaseGenerated extends AbstractRawFirBuilderTestCas
runTest("compiler/fir/psi2fir/testData/rawBuilder/expressions/lambda.kt"); 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") @TestMetadata("locals.kt")
public void testLocals() throws Exception { public void testLocals() throws Exception {
runTest("compiler/fir/psi2fir/testData/rawBuilder/expressions/locals.kt"); runTest("compiler/fir/psi2fir/testData/rawBuilder/expressions/locals.kt");
@@ -62,7 +62,7 @@ fun FirAnonymousFunction.copy(
controlFlowGraphReference: FirControlFlowGraphReference = this.controlFlowGraphReference, controlFlowGraphReference: FirControlFlowGraphReference = this.controlFlowGraphReference,
invocationKind: InvocationKind? = this.invocationKind invocationKind: InvocationKind? = this.invocationKind
): FirAnonymousFunction { ): FirAnonymousFunction {
return FirAnonymousFunctionImpl(source, session, returnTypeRef, receiverTypeRef, symbol).apply { return FirAnonymousFunctionImpl(source, session, returnTypeRef, receiverTypeRef, symbol, isLambda).apply {
this.valueParameters.addAll(valueParameters) this.valueParameters.addAll(valueParameters)
this.body = body this.body = body
this.annotations.addAll(annotations) this.annotations.addAll(annotations)
@@ -120,25 +120,27 @@ digraph returnValuesFromLambda_kt {
subgraph cluster_10 { subgraph cluster_10 {
color=blue color=blue
34 [label="Enter function anonymousFunction"]; 34 [label="Enter function anonymousFunction"];
35 [label="Jump: ^ Unit"]; 35 [label="Jump: ^test_3 Unit"];
36 [label="Stub" style="filled" fillcolor=gray]; 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|<R|kotlin/Unit|>(<L> = run@fun <anonymous>(): R|kotlin/Unit| <kind=EXACTLY_ONCE> { 38 [label="Function call: R|kotlin/run|<R|kotlin/Nothing|>(<L> = run@fun <anonymous>(): R|kotlin/Unit| <kind=EXACTLY_ONCE> {
^ Unit ^test_3 Unit
} }
)"]; )" style="filled" fillcolor=gray];
39 [label="Variable declaration: lval x: R|kotlin/Unit|"]; 39 [label="Stub" style="filled" fillcolor=gray];
40 [label="Exit function test_3" style="filled" fillcolor=red]; 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}; 33 -> {34};
34 -> {35}; 34 -> {35};
35 -> {37}; 35 -> {41};
35 -> {36} [style=dotted]; 35 -> {36} [style=dotted];
36 -> {37} [style=dotted]; 36 -> {37} [style=dotted];
37 -> {38}; 37 -> {38} [style=dotted];
38 -> {39}; 38 -> {41 39} [style=dotted];
39 -> {40}; 39 -> {40} [style=dotted];
40 -> {41} [style=dotted];
} }
@@ -32,8 +32,8 @@ FILE: returnValuesFromLambda.kt
) )
} }
public final fun test_3(): R|kotlin/Unit| { public final fun test_3(): R|kotlin/Unit| {
lval x: R|kotlin/Unit| = R|kotlin/run|<R|kotlin/Unit|>(<L> = run@fun <anonymous>(): R|kotlin/Unit| <kind=EXACTLY_ONCE> { lval x: R|kotlin/Nothing| = R|kotlin/run|<R|kotlin/Nothing|>(<L> = run@fun <anonymous>(): R|kotlin/Unit| <kind=EXACTLY_ONCE> {
^ Unit ^test_3 Unit
} }
) )
} }
@@ -195,44 +195,45 @@ digraph safeCalls_kt {
subgraph cluster_12 { subgraph cluster_12 {
color=blue color=blue
71 [label="Enter function anonymousFunction"]; 71 [label="Enter function anonymousFunction"];
72 [label="Jump: ^ Unit"]; 72 [label="Jump: ^test_5 Unit"];
73 [label="Stub" style="filled" fillcolor=gray]; 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|<local>/x|?.R|kotlin/let|<R|A|, R|kotlin/Unit|>(<L> = let@fun <anonymous>(it: R|A|): R|kotlin/Unit| <kind=EXACTLY_ONCE> { 75 [label="Function call: R|<local>/x|?.R|kotlin/let|<R|A|, R|kotlin/Nothing|>(<L> = let@fun <anonymous>(it: R|A|): R|kotlin/Unit| <kind=EXACTLY_ONCE> {
^ Unit ^test_5 Unit
} }
)"]; )" style="filled" fillcolor=gray];
76 [label="Exit safe call"]; 76 [label="Exit safe call" style="filled" fillcolor=gray];
77 [label="Enter safe call"]; 77 [label="Enter safe call" style="filled" fillcolor=gray];
78 [label="Access variable R|<local>/x|"]; 78 [label="Access variable R|<local>/x|" style="filled" fillcolor=gray];
79 [label="Function call: R|<local>/x|.R|/A.bool|()"]; 79 [label="Function call: R|<local>/x|.R|/A.bool|()" style="filled" fillcolor=gray];
80 [label="Function call: R|<local>/x|?.R|kotlin/let|<R|A|, R|kotlin/Unit|>(<L> = let@fun <anonymous>(it: R|A|): R|kotlin/Unit| <kind=EXACTLY_ONCE> { 80 [label="Function call: R|<local>/x|?.R|kotlin/let|<R|A|, R|kotlin/Nothing|>(<L> = let@fun <anonymous>(it: R|A|): R|kotlin/Unit| <kind=EXACTLY_ONCE> {
^ Unit ^test_5 Unit
} }
)?.R|/boo|(R|<local>/x|.R|/A.bool|())"]; )?.R|/boo|(R|<local>/x|.R|/A.bool|())" style="filled" fillcolor=gray];
81 [label="Exit safe call"]; 81 [label="Exit safe call" style="filled" fillcolor=gray];
82 [label="Access variable R|<local>/x|"]; 82 [label="Access variable R|<local>/x|" style="filled" fillcolor=gray];
83 [label="Function call: R|<local>/x|.<Inapplicable(WRONG_RECEIVER): [/A.id]>#()"]; 83 [label="Function call: R|<local>/x|.<Inapplicable(WRONG_RECEIVER): [/A.id]>#()" style="filled" fillcolor=gray];
84 [label="Exit function test_5" style="filled" fillcolor=red]; 84 [label="Exit function test_5" style="filled" fillcolor=red];
} }
68 -> {69}; 68 -> {69};
69 -> {70 76}; 69 -> {70};
69 -> {76} [style=dotted];
70 -> {71}; 70 -> {71};
71 -> {72}; 71 -> {72};
72 -> {74}; 72 -> {84};
72 -> {73} [style=dotted]; 72 -> {73} [style=dotted];
73 -> {74} [style=dotted]; 73 -> {74} [style=dotted];
74 -> {75}; 74 -> {75} [style=dotted];
75 -> {76}; 75 -> {76} [style=dotted];
76 -> {77 81}; 76 -> {77 81} [style=dotted];
77 -> {78}; 77 -> {78} [style=dotted];
78 -> {79}; 78 -> {79} [style=dotted];
79 -> {80}; 79 -> {80} [style=dotted];
80 -> {81}; 80 -> {81} [style=dotted];
81 -> {82}; 81 -> {82} [style=dotted];
82 -> {83}; 82 -> {83} [style=dotted];
83 -> {84}; 83 -> {84} [style=dotted];
} }
@@ -32,8 +32,8 @@ FILE: safeCalls.kt
} }
public final fun R|kotlin/Any?|.boo(b: R|kotlin/Boolean|): R|kotlin/Unit| 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| { public final fun test_5(x: R|A?|): R|kotlin/Unit| {
R|<local>/x|?.R|kotlin/let|<R|A|, R|kotlin/Unit|>(<L> = let@fun <anonymous>(it: R|A|): R|kotlin/Unit| <kind=EXACTLY_ONCE> { R|<local>/x|?.R|kotlin/let|<R|A|, R|kotlin/Nothing|>(<L> = let@fun <anonymous>(it: R|A|): R|kotlin/Unit| <kind=EXACTLY_ONCE> {
^ Unit ^test_5 Unit
} }
)?.R|/boo|(R|<local>/x|.R|/A.bool|()) )?.R|/boo|(R|<local>/x|.R|/A.bool|())
R|<local>/x|.<Inapplicable(WRONG_RECEIVER): [/A.id]>#() R|<local>/x|.<Inapplicable(WRONG_RECEIVER): [/A.id]>#()
@@ -38,6 +38,7 @@ abstract class FirAnonymousFunction : FirPureAbstractElement(), FirFunction<FirA
abstract override val symbol: FirAnonymousFunctionSymbol abstract override val symbol: FirAnonymousFunctionSymbol
abstract val label: FirLabel? abstract val label: FirLabel?
abstract val invocationKind: InvocationKind? abstract val invocationKind: InvocationKind?
abstract val isLambda: Boolean
override fun <R, D> accept(visitor: FirVisitor<R, D>, data: D): R = visitor.visitAnonymousFunction(this, data) override fun <R, D> accept(visitor: FirVisitor<R, D>, data: D): R = visitor.visitAnonymousFunction(this, data)
@@ -33,7 +33,8 @@ class FirAnonymousFunctionImpl(
override val session: FirSession, override val session: FirSession,
override var returnTypeRef: FirTypeRef, override var returnTypeRef: FirTypeRef,
override var receiverTypeRef: FirTypeRef?, override var receiverTypeRef: FirTypeRef?,
override val symbol: FirAnonymousFunctionSymbol override val symbol: FirAnonymousFunctionSymbol,
override val isLambda: Boolean
) : FirAnonymousFunction(), FirModifiableFunction<FirAnonymousFunction>, FirAbstractAnnotatedElement { ) : FirAnonymousFunction(), FirModifiableFunction<FirAnonymousFunction>, FirAbstractAnnotatedElement {
override var resolvePhase: FirResolvePhase = FirResolvePhase.DECLARATIONS override var resolvePhase: FirResolvePhase = FirResolvePhase.DECLARATIONS
override val annotations: MutableList<FirAnnotationCall> = mutableListOf() override val annotations: MutableList<FirAnnotationCall> = mutableListOf()
@@ -253,6 +253,7 @@ object NodeConfigurator : AbstractFieldConfigurator() {
+field(invocationKindType, nullable = true, withReplace = true).apply { +field(invocationKindType, nullable = true, withReplace = true).apply {
isMutable = true isMutable = true
} }
+booleanField("isLambda")
} }
typeParameter.configure { typeParameter.configure {
+1 -1
View File
@@ -5,7 +5,7 @@ FILE fqName:<root> fileName:/nonLocalReturn.kt
block: FUN_EXPR type=kotlin.Function0<kotlin.Unit> origin=LAMBDA block: FUN_EXPR type=kotlin.Function0<kotlin.Unit> origin=LAMBDA
FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> () returnType:kotlin.Unit FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> () returnType:kotlin.Unit
BLOCK_BODY BLOCK_BODY
RETURN type=kotlin.Nothing from='local final fun <anonymous> (): kotlin.Unit declared in <root>.test0' RETURN type=kotlin.Nothing from='public final fun test0 (): kotlin.Unit declared in <root>'
GET_OBJECT 'CLASS IR_EXTERNAL_DECLARATION_STUB OBJECT name:Unit modality:FINAL visibility:public superTypes:[kotlin.Any]' type=kotlin.Unit 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 FUN name:test1 visibility:public modality:FINAL <> () returnType:kotlin.Unit
BLOCK_BODY BLOCK_BODY
@@ -223,6 +223,11 @@ public class FirVisualizerForRawFirDataGenerated extends AbstractFirVisualizer {
runTest("compiler/fir/psi2fir/testData/rawBuilder/expressions/lambda.kt"); 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") @TestMetadata("locals.kt")
public void testLocals() throws Exception { public void testLocals() throws Exception {
runTest("compiler/fir/psi2fir/testData/rawBuilder/expressions/locals.kt"); runTest("compiler/fir/psi2fir/testData/rawBuilder/expressions/locals.kt");
@@ -223,6 +223,11 @@ public class PsiVisualizerForRawFirDataGenerated extends AbstractPsiVisualizer {
runTest("compiler/fir/psi2fir/testData/rawBuilder/expressions/lambda.kt"); 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") @TestMetadata("locals.kt")
public void testLocals() throws Exception { public void testLocals() throws Exception {
runTest("compiler/fir/psi2fir/testData/rawBuilder/expressions/locals.kt"); runTest("compiler/fir/psi2fir/testData/rawBuilder/expressions/locals.kt");