From 9493e685843c53544f3f3dc71bd88d69192e5e90 Mon Sep 17 00:00:00 2001 From: "Denis.Zharkov" Date: Fri, 15 Jan 2021 18:54:36 +0300 Subject: [PATCH] FIR: Do not run completion for lambda's explicit return too early See the test case Completion for synthetic call: x ?: return@myRun materialize() makes `materialize()` while it's obviously too early for that --- ...TouchedTilContractsPhaseTestGenerated.java | 5 ++++ .../resolve/inference/lambdasReturns.fir.txt | 15 +++++++++++ .../resolve/inference/lambdasReturns.kt | 15 +++++++++++ .../runners/FirDiagnosticTestGenerated.java | 6 +++++ ...DiagnosticsWithLightTreeTestGenerated.java | 6 +++++ .../fir/resolve/inference/FirCallCompleter.kt | 4 ++- ...rCallCompletionResultsWriterTransformer.kt | 25 ++++++++++++++++--- .../FirDeclarationsResolveTransformer.kt | 1 + 8 files changed, 72 insertions(+), 5 deletions(-) create mode 100644 compiler/fir/analysis-tests/testData/resolve/inference/lambdasReturns.fir.txt create mode 100644 compiler/fir/analysis-tests/testData/resolve/inference/lambdasReturns.kt diff --git a/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java b/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java index cf7e0629eb3..633632c5704 100644 --- a/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java +++ b/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java @@ -2223,6 +2223,11 @@ public class LazyBodyIsNotTouchedTilContractsPhaseTestGenerated extends Abstract runTest("compiler/fir/analysis-tests/testData/resolve/inference/lambdaInElvis.kt"); } + @TestMetadata("lambdasReturns.kt") + public void testLambdasReturns() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/inference/lambdasReturns.kt"); + } + @TestMetadata("nestedExtensionFunctionType.kt") public void testNestedExtensionFunctionType() throws Exception { runTest("compiler/fir/analysis-tests/testData/resolve/inference/nestedExtensionFunctionType.kt"); diff --git a/compiler/fir/analysis-tests/testData/resolve/inference/lambdasReturns.fir.txt b/compiler/fir/analysis-tests/testData/resolve/inference/lambdasReturns.fir.txt new file mode 100644 index 00000000000..41ca1d4fa2d --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/inference/lambdasReturns.fir.txt @@ -0,0 +1,15 @@ +FILE: lambdasReturns.kt + public final fun myRun(b: R|() -> R|): R|R| { + ^myRun R|/b|.R|SubstitutionOverride|() + } + public final fun materialize(): R|T| { + ^materialize R|kotlin/TODO|() + } + public final fun foo(x: R|kotlin/String?|): R|kotlin/Unit| { + lval r: R|kotlin/Int| = R|/myRun|( = myRun@fun (): R|kotlin/Int| { + lval y: R|kotlin/String| = R|/x| ?: ^@myRun R?C|/materialize|() + ^ R|/y|.R|kotlin/String.length| + } + ) + R|/r|.R|kotlin/Int.minus|(Int(1)) + } diff --git a/compiler/fir/analysis-tests/testData/resolve/inference/lambdasReturns.kt b/compiler/fir/analysis-tests/testData/resolve/inference/lambdasReturns.kt new file mode 100644 index 00000000000..665e02bed0b --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/inference/lambdasReturns.kt @@ -0,0 +1,15 @@ +// !DIAGNOSTICS: -UNUSED_VARIABLE +// !WITH_NEW_INFERENCE + +fun myRun(b: () -> R): R = b() + +fun materialize(): T = TODO() + +fun foo(x: String?) { + val r = myRun { + val y = x ?: return@myRun materialize() + y.length + } + + r.minus(1) +} diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticTestGenerated.java index 64a33e4f967..be352eaf06c 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticTestGenerated.java @@ -2547,6 +2547,12 @@ public class FirDiagnosticTestGenerated extends AbstractFirDiagnosticTest { runTest("compiler/fir/analysis-tests/testData/resolve/inference/lambdaInElvis.kt"); } + @Test + @TestMetadata("lambdasReturns.kt") + public void testLambdasReturns() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/inference/lambdasReturns.kt"); + } + @Test @TestMetadata("nestedExtensionFunctionType.kt") public void testNestedExtensionFunctionType() throws Exception { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticsWithLightTreeTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticsWithLightTreeTestGenerated.java index a53aadfc92c..d89ea750310 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticsWithLightTreeTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticsWithLightTreeTestGenerated.java @@ -2568,6 +2568,12 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos runTest("compiler/fir/analysis-tests/testData/resolve/inference/lambdaInElvis.kt"); } + @Test + @TestMetadata("lambdasReturns.kt") + public void testLambdasReturns() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/inference/lambdasReturns.kt"); + } + @Test @TestMetadata("nestedExtensionFunctionType.kt") public void testNestedExtensionFunctionType() throws Exception { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirCallCompleter.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirCallCompleter.kt index f3dc5091520..d6a37a5f596 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirCallCompleter.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirCallCompleter.kt @@ -83,7 +83,8 @@ class FirCallCompleter( val completedCall = call.transformSingle( FirCallCompletionResultsWriterTransformer( session, finalSubstitutor, components.returnTypeCalculator, - session.inferenceComponents.approximator + session.inferenceComponents.approximator, + components.dataFlowAnalyzer, ), null ) @@ -153,6 +154,7 @@ class FirCallCompleter( return FirCallCompletionResultsWriterTransformer( session, substitutor, components.returnTypeCalculator, session.inferenceComponents.approximator, + components.dataFlowAnalyzer, mode ) } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirCallCompletionResultsWriterTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirCallCompletionResultsWriterTransformer.kt index e801a3062b0..07350b79d33 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirCallCompletionResultsWriterTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirCallCompletionResultsWriterTransformer.kt @@ -13,18 +13,16 @@ import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.references.builder.buildErrorNamedReference import org.jetbrains.kotlin.fir.references.builder.buildResolvedCallableReference import org.jetbrains.kotlin.fir.references.builder.buildResolvedNamedReference +import org.jetbrains.kotlin.fir.resolve.* import org.jetbrains.kotlin.fir.resolve.calls.Candidate import org.jetbrains.kotlin.fir.resolve.calls.FirErrorReferenceWithCandidate import org.jetbrains.kotlin.fir.resolve.calls.FirNamedReferenceWithCandidate import org.jetbrains.kotlin.fir.resolve.calls.varargElementType -import org.jetbrains.kotlin.fir.resolve.constructFunctionalTypeRef -import org.jetbrains.kotlin.fir.resolve.createFunctionalType -import org.jetbrains.kotlin.fir.resolve.firProvider +import org.jetbrains.kotlin.fir.resolve.dfa.FirDataFlowAnalyzer import org.jetbrains.kotlin.fir.resolve.inference.inferenceComponents import org.jetbrains.kotlin.fir.resolve.inference.isBuiltinFunctionalType import org.jetbrains.kotlin.fir.resolve.inference.isSuspendFunctionType import org.jetbrains.kotlin.fir.resolve.inference.returnType -import org.jetbrains.kotlin.fir.resolve.propagateTypeFromQualifiedAccessAfterNullCheck import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirArrayOfCallTransformer import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.remapArgumentsWithVararg @@ -48,6 +46,7 @@ class FirCallCompletionResultsWriterTransformer( private val finalSubstitutor: ConeSubstitutor, private val typeCalculator: ReturnTypeCalculator, private val typeApproximator: AbstractTypeApproximator, + private val dataFlowAnalyzer: FirDataFlowAnalyzer<*>, private val mode: Mode = Mode.Normal ) : FirAbstractTreeTransformer(phase = FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE) { @@ -472,6 +471,7 @@ class FirCallCompletionResultsWriterTransformer( } val result = transformElement(anonymousFunction, null) + val resultFunction = result.single if (resultFunction.returnTypeRef.coneTypeSafe() != null) { val blockType = resultFunction.body?.typeRef?.coneTypeSafe() @@ -480,9 +480,26 @@ class FirCallCompletionResultsWriterTransformer( resultFunction.constructFunctionalTypeRef(isSuspend = expectedType?.isSuspendFunctionType(session) == true) ) } + + for (expression in dataFlowAnalyzer.returnExpressionsOfAnonymousFunction(anonymousFunction)) { + expression.transform(this, null) + } + return result } + override fun transformReturnExpression( + returnExpression: FirReturnExpression, + data: ExpectedArgumentType? + ): CompositeTransformResult { + val labeledElement = returnExpression.target.labeledElement + if (labeledElement is FirAnonymousFunction) { + return returnExpression.compose() + } + + return super.transformReturnExpression(returnExpression, data) + } + override fun transformBlock(block: FirBlock, data: ExpectedArgumentType?): CompositeTransformResult { val initialType = block.resultType.coneTypeSafe() if (initialType != null) { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt index 557eff9e2a3..0d59e01234a 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt @@ -759,6 +759,7 @@ open class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransfor ConeSubstitutor.Empty, components.returnTypeCalculator, inferenceComponents.approximator, + dataFlowAnalyzer, ) lambda.transformSingle(writer, expectedTypeRef.coneTypeSafe()?.toExpectedType()) val returnTypes = dataFlowAnalyzer.returnExpressionsOfAnonymousFunction(lambda)