From 3e6b42083b88156a79a2ed4e3bc4425a2029c204 Mon Sep 17 00:00:00 2001 From: Simon Ogorodnik Date: Wed, 17 May 2023 10:50:36 +0000 Subject: [PATCH] FIR: Fix leakage of type variables in builder inference for lambdas returning Unit When BI/incomplete call is present in return argument, it will be added to the main call-tree, leading to requirement violation in `ConstraintSystemCompleter.getOrderedAllTypeVariables` as after `FirBuilderInferenceSession.inferPostponedVariables` it will be completed, and its type variables couldn't be found anymore In K1, we actually do the same, but we are able to find type variables of such calls due to architecture difference: In K2, `getOrderedAllTypeVariables` uses FIR as the main source to lookup In K1, `getOrderedAllTypeVariables` uses resolution atom tree, where candidate/CS of the call is still available after `inferPostponedVariables` In fact, all incomplete calls were analyzed in FULL mode according to the contract of `FirBuilderInferenceSession.addPartiallyResolvedCall`. Thus, it means we normally shouldn't add them to the main call-tree, but accidentally do it as incomplete calls contain non-completed candidate This particular commit addresses the problem partially, only in cases when the expected return type for the lambda is Unit and when the incomplete call is located in the last expression of the lambda In such cases, we can skip the call from the last expression completely, since all potential calls there were analyzed in FULL mode, and couldn't introduce any useful info to the CS of the main call-tree ^KT-54294 --- ...CompilerTestFE10TestdataTestGenerated.java | 6 +++ ...sticCompilerFE10TestDataTestGenerated.java | 6 +++ ...eeOldFrontendDiagnosticsTestGenerated.java | 6 +++ ...siOldFrontendDiagnosticsTestGenerated.java | 6 +++ ...LightTreeBlackBoxCodegenTestGenerated.java | 18 ++++++++ .../FirPsiBlackBoxCodegenTestGenerated.java | 18 ++++++++ .../inference/PostponedArgumentsAnalyzer.kt | 17 ++++++-- .../partiallyResolvedCallInReturnArgument.kt | 34 +++++++++++++++ ...allyResolvedCallInReturnArgumentNonLast.kt | 34 +++++++++++++++ ...allyResolvedCallInReturnArgumentNonUnit.kt | 36 ++++++++++++++++ ...llInReturnArgumentsWithProperExpectType.kt | 43 +++++++++++++++++++ .../test/runners/DiagnosticTestGenerated.java | 6 +++ .../codegen/BlackBoxCodegenTestGenerated.java | 18 ++++++++ .../IrBlackBoxCodegenTestGenerated.java | 18 ++++++++ ...kBoxCodegenWithIrInlinerTestGenerated.java | 18 ++++++++ .../LightAnalysisModeTestGenerated.java | 15 +++++++ docs/fir/builder_inference.md | 16 ++++++- 17 files changed, 310 insertions(+), 5 deletions(-) create mode 100644 compiler/testData/codegen/box/inference/builderInference/partiallyResolvedCallInReturnArgument.kt create mode 100644 compiler/testData/codegen/box/inference/builderInference/partiallyResolvedCallInReturnArgumentNonLast.kt create mode 100644 compiler/testData/codegen/box/inference/builderInference/partiallyResolvedCallInReturnArgumentNonUnit.kt create mode 100644 compiler/testData/diagnostics/tests/inference/builderInference/incompleteCallInReturnArgumentsWithProperExpectType.kt diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosticCompilerTestFE10TestdataTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosticCompilerTestFE10TestdataTestGenerated.java index c5493ac5adc..3d866b276fa 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosticCompilerTestFE10TestdataTestGenerated.java +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosticCompilerTestFE10TestdataTestGenerated.java @@ -15191,6 +15191,12 @@ public class DiagnosticCompilerTestFE10TestdataTestGenerated extends AbstractDia runTest("compiler/testData/diagnostics/tests/inference/builderInference/errorOnStubReceiver.kt"); } + @Test + @TestMetadata("incompleteCallInReturnArgumentsWithProperExpectType.kt") + public void testIncompleteCallInReturnArgumentsWithProperExpectType() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/builderInference/incompleteCallInReturnArgumentsWithProperExpectType.kt"); + } + @Test @TestMetadata("invalidateKeys.kt") public void testInvalidateKeys() throws Exception { diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated.java index 82b8a36a909..78ed908495c 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated.java +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated.java @@ -15191,6 +15191,12 @@ public class LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated runTest("compiler/testData/diagnostics/tests/inference/builderInference/errorOnStubReceiver.kt"); } + @Test + @TestMetadata("incompleteCallInReturnArgumentsWithProperExpectType.kt") + public void testIncompleteCallInReturnArgumentsWithProperExpectType() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/builderInference/incompleteCallInReturnArgumentsWithProperExpectType.kt"); + } + @Test @TestMetadata("invalidateKeys.kt") public void testInvalidateKeys() throws Exception { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeOldFrontendDiagnosticsTestGenerated.java index 2aee10868b1..a8db89a4500 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeOldFrontendDiagnosticsTestGenerated.java @@ -15191,6 +15191,12 @@ public class FirLightTreeOldFrontendDiagnosticsTestGenerated extends AbstractFir runTest("compiler/testData/diagnostics/tests/inference/builderInference/errorOnStubReceiver.kt"); } + @Test + @TestMetadata("incompleteCallInReturnArgumentsWithProperExpectType.kt") + public void testIncompleteCallInReturnArgumentsWithProperExpectType() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/builderInference/incompleteCallInReturnArgumentsWithProperExpectType.kt"); + } + @Test @TestMetadata("invalidateKeys.kt") public void testInvalidateKeys() throws Exception { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiOldFrontendDiagnosticsTestGenerated.java index 89641e4a5a0..80c20e72a96 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiOldFrontendDiagnosticsTestGenerated.java @@ -15197,6 +15197,12 @@ public class FirPsiOldFrontendDiagnosticsTestGenerated extends AbstractFirPsiDia runTest("compiler/testData/diagnostics/tests/inference/builderInference/errorOnStubReceiver.kt"); } + @Test + @TestMetadata("incompleteCallInReturnArgumentsWithProperExpectType.kt") + public void testIncompleteCallInReturnArgumentsWithProperExpectType() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/builderInference/incompleteCallInReturnArgumentsWithProperExpectType.kt"); + } + @Test @TestMetadata("invalidateKeys.kt") public void testInvalidateKeys() throws Exception { diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirLightTreeBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirLightTreeBlackBoxCodegenTestGenerated.java index ce7c2bbef1d..10cf32e55b7 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirLightTreeBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirLightTreeBlackBoxCodegenTestGenerated.java @@ -20704,6 +20704,24 @@ public class FirLightTreeBlackBoxCodegenTestGenerated extends AbstractFirLightTr runTest("compiler/testData/codegen/box/inference/builderInference/nullability.kt"); } + @Test + @TestMetadata("partiallyResolvedCallInReturnArgument.kt") + public void testPartiallyResolvedCallInReturnArgument() throws Exception { + runTest("compiler/testData/codegen/box/inference/builderInference/partiallyResolvedCallInReturnArgument.kt"); + } + + @Test + @TestMetadata("partiallyResolvedCallInReturnArgumentNonLast.kt") + public void testPartiallyResolvedCallInReturnArgumentNonLast() throws Exception { + runTest("compiler/testData/codegen/box/inference/builderInference/partiallyResolvedCallInReturnArgumentNonLast.kt"); + } + + @Test + @TestMetadata("partiallyResolvedCallInReturnArgumentNonUnit.kt") + public void testPartiallyResolvedCallInReturnArgumentNonUnit() throws Exception { + runTest("compiler/testData/codegen/box/inference/builderInference/partiallyResolvedCallInReturnArgumentNonUnit.kt"); + } + @Test @TestMetadata("propagateInferenceSessionIntoDeclarationAnalyzers.kt") public void testPropagateInferenceSessionIntoDeclarationAnalyzers() throws Exception { diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirPsiBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirPsiBlackBoxCodegenTestGenerated.java index 25210362a5e..12e95721574 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirPsiBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirPsiBlackBoxCodegenTestGenerated.java @@ -20704,6 +20704,24 @@ public class FirPsiBlackBoxCodegenTestGenerated extends AbstractFirPsiBlackBoxCo runTest("compiler/testData/codegen/box/inference/builderInference/nullability.kt"); } + @Test + @TestMetadata("partiallyResolvedCallInReturnArgument.kt") + public void testPartiallyResolvedCallInReturnArgument() throws Exception { + runTest("compiler/testData/codegen/box/inference/builderInference/partiallyResolvedCallInReturnArgument.kt"); + } + + @Test + @TestMetadata("partiallyResolvedCallInReturnArgumentNonLast.kt") + public void testPartiallyResolvedCallInReturnArgumentNonLast() throws Exception { + runTest("compiler/testData/codegen/box/inference/builderInference/partiallyResolvedCallInReturnArgumentNonLast.kt"); + } + + @Test + @TestMetadata("partiallyResolvedCallInReturnArgumentNonUnit.kt") + public void testPartiallyResolvedCallInReturnArgumentNonUnit() throws Exception { + runTest("compiler/testData/codegen/box/inference/builderInference/partiallyResolvedCallInReturnArgumentNonUnit.kt"); + } + @Test @TestMetadata("propagateInferenceSessionIntoDeclarationAnalyzers.kt") public void testPropagateInferenceSessionIntoDeclarationAnalyzers() throws Exception { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/PostponedArgumentsAnalyzer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/PostponedArgumentsAnalyzer.kt index eaa9c3501ad..24abdcf8edc 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/PostponedArgumentsAnalyzer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/PostponedArgumentsAnalyzer.kt @@ -174,9 +174,16 @@ class PostponedArgumentsAnalyzer( val returnTypeRef = lambda.atom.returnTypeRef.let { it as? FirResolvedTypeRef ?: it.resolvedTypeFromPrototype(substitute(lambda.returnType)) } + val lambdaExpectedTypeIsUnit = returnTypeRef.type.isUnitOrFlexibleUnit returnArguments.forEach { - val haveSubsystem = c.addSubsystemFromExpression(it) // If the lambda returns Unit, the last expression is not returned and should not be constrained. + val isLastExpression = it == lastExpression + + // Don't add last call for builder-inference + // Note, that we don't use the same condition "(returnTypeRef.type.isUnitOrFlexibleUnit || lambda.atom.shouldReturnUnit(returnArguments))" + // as in the if below, because "lambda.atom.shouldReturnUnit(returnArguments)" might mean that the last statement is not completed + if (isLastExpression && lambdaExpectedTypeIsUnit && inferenceSession is FirBuilderInferenceSession) return@forEach + // TODO (KT-55837) questionable moment inherited from FE1.0 (the `haveSubsystem` case): // fun foo(): T // run { @@ -184,8 +191,10 @@ class PostponedArgumentsAnalyzer( // foo() // T = Unit, even though there is no implicit return // } // Things get even weirder if T has an upper bound incompatible with Unit. - if (it == lastExpression && !haveSubsystem && - (returnTypeRef.type.isUnitOrFlexibleUnit || lambda.atom.shouldReturnUnit(returnArguments)) + // Not calling `addSubsystemFromExpression` for builder-inference is crucial + val haveSubsystem = c.addSubsystemFromExpression(it) + if (isLastExpression && !haveSubsystem && + (lambdaExpectedTypeIsUnit || lambda.atom.shouldReturnUnit(returnArguments)) ) return@forEach hasExpressionInReturnArguments = true @@ -202,7 +211,7 @@ class PostponedArgumentsAnalyzer( } } - if (!hasExpressionInReturnArguments && !returnTypeRef.type.isUnitOrFlexibleUnit) { + if (!hasExpressionInReturnArguments && !lambdaExpectedTypeIsUnit) { builder.addSubtypeConstraint( components.session.builtinTypes.unitType.type, returnTypeRef.type, diff --git a/compiler/testData/codegen/box/inference/builderInference/partiallyResolvedCallInReturnArgument.kt b/compiler/testData/codegen/box/inference/builderInference/partiallyResolvedCallInReturnArgument.kt new file mode 100644 index 00000000000..19901218d4c --- /dev/null +++ b/compiler/testData/codegen/box/inference/builderInference/partiallyResolvedCallInReturnArgument.kt @@ -0,0 +1,34 @@ +// WITH_STDLIB +// TARGET_BACKEND: JVM +class Out(val v: V) +class Box { + var boxed: R? = null + + fun set(newValue: R) { + boxed = newValue + } +} + +fun buildBox(fill: Box.() -> Unit): Box { + return Box().also { + it.fill() + } +} + +fun foo() = + buildBox { + set(select(Out("OK"), makeOut())) // problem is here + // we keep set in PARTIALLY analyzed state, while we're also trying to incorporate it both into return-type constraining + // and builder inference, which introduces non-trivial loop of codependency between those two steps + // Due to that, we leak type variables from set call-graph to the system of buildBox, while those variables are already + // fixed + } + +fun select(a: S, b: S): S = a + +fun makeOut(): Out? = null + +fun box(): String { + if (foo().boxed!!.v != "OK") return "FAIL" + return "OK" +} diff --git a/compiler/testData/codegen/box/inference/builderInference/partiallyResolvedCallInReturnArgumentNonLast.kt b/compiler/testData/codegen/box/inference/builderInference/partiallyResolvedCallInReturnArgumentNonLast.kt new file mode 100644 index 00000000000..676b6d592f6 --- /dev/null +++ b/compiler/testData/codegen/box/inference/builderInference/partiallyResolvedCallInReturnArgumentNonLast.kt @@ -0,0 +1,34 @@ +// WITH_STDLIB +// TARGET_BACKEND: JVM +// IGNORE_BACKEND_K2: JVM_IR +// FIR status: KT-58742 + +class Out(val v: V) +class Box { + var boxed: R? = null + + fun set(newValue: R) { + boxed = newValue + } +} + +fun buildBox(fill: Box.() -> Unit): Box { + return Box().also { + it.fill() + } +} + +fun foo() = + buildBox { + if (true) return@buildBox set(select(Out("OK"), makeOut())) // problem is here + Unit + } + +fun select(a: S, b: S): S = a + +fun makeOut(): Out? = null + +fun box(): String { + if (foo().boxed!!.v != "OK") return "FAIL" + return "OK" +} diff --git a/compiler/testData/codegen/box/inference/builderInference/partiallyResolvedCallInReturnArgumentNonUnit.kt b/compiler/testData/codegen/box/inference/builderInference/partiallyResolvedCallInReturnArgumentNonUnit.kt new file mode 100644 index 00000000000..952269d8280 --- /dev/null +++ b/compiler/testData/codegen/box/inference/builderInference/partiallyResolvedCallInReturnArgumentNonUnit.kt @@ -0,0 +1,36 @@ +// WITH_STDLIB +// TARGET_BACKEND: JVM +// IGNORE_BACKEND_K2: JVM_IR +// FIR status: KT-58741 + +fun foo() = + buildBox { + set(select(Out("OK"), makeOut())) + } + + +class Out(val v: V) +class Box { + var boxed: R? = null + + fun set(newValue: R): String { + boxed = newValue + return "set" + } +} + +fun buildBox(fill: Box.() -> String): Box { + return Box().also { + require(it.fill() == "set") + } +} + +fun select(a: S, b: S): S = a + +fun makeOut(): Out? = null + + +fun box(): String { + if (foo().boxed!!.v != "OK") return "FAIL" + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/inference/builderInference/incompleteCallInReturnArgumentsWithProperExpectType.kt b/compiler/testData/diagnostics/tests/inference/builderInference/incompleteCallInReturnArgumentsWithProperExpectType.kt new file mode 100644 index 00000000000..fa2fcfe248f --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/builderInference/incompleteCallInReturnArgumentsWithProperExpectType.kt @@ -0,0 +1,43 @@ +// FIR_IDENTICAL +// WITH_STDLIB +// SKIP_TXT + +fun test1() = + buildBoxUnit { + set(select(Out(""), makeOut())) + mat() // Should be able to infer Unit here + } + +fun test2() = + buildBoxProperType { + set(select(Out(""), makeOut())) + mat() // Should be able to infer String here + } + + +class Out(val v: V) +class Box { + var boxed: R? = null + + fun set(newValue: R) { + boxed = newValue + } +} + +fun buildBoxUnit(fill: Box.() -> Unit): Box { + return Box().also { + it.fill() + } +} + +fun buildBoxProperType(fill: Box.() -> String): Box { + return Box().also { + it.fill() + } +} + +fun select(a: S, b: S): S = a + +fun makeOut(): Out? = null + +fun mat(): M = null!! diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java index cba89e3c2e0..ac50f0a312d 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java @@ -15197,6 +15197,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { runTest("compiler/testData/diagnostics/tests/inference/builderInference/errorOnStubReceiver.kt"); } + @Test + @TestMetadata("incompleteCallInReturnArgumentsWithProperExpectType.kt") + public void testIncompleteCallInReturnArgumentsWithProperExpectType() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/builderInference/incompleteCallInReturnArgumentsWithProperExpectType.kt"); + } + @Test @TestMetadata("invalidateKeys.kt") public void testInvalidateKeys() throws Exception { diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java index 39616663a4c..cd85b3bd884 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java @@ -19780,6 +19780,24 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/inference/builderInference/nullability.kt"); } + @Test + @TestMetadata("partiallyResolvedCallInReturnArgument.kt") + public void testPartiallyResolvedCallInReturnArgument() throws Exception { + runTest("compiler/testData/codegen/box/inference/builderInference/partiallyResolvedCallInReturnArgument.kt"); + } + + @Test + @TestMetadata("partiallyResolvedCallInReturnArgumentNonLast.kt") + public void testPartiallyResolvedCallInReturnArgumentNonLast() throws Exception { + runTest("compiler/testData/codegen/box/inference/builderInference/partiallyResolvedCallInReturnArgumentNonLast.kt"); + } + + @Test + @TestMetadata("partiallyResolvedCallInReturnArgumentNonUnit.kt") + public void testPartiallyResolvedCallInReturnArgumentNonUnit() throws Exception { + runTest("compiler/testData/codegen/box/inference/builderInference/partiallyResolvedCallInReturnArgumentNonUnit.kt"); + } + @Test @TestMetadata("propagateInferenceSessionIntoDeclarationAnalyzers.kt") public void testPropagateInferenceSessionIntoDeclarationAnalyzers() throws Exception { diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java index f202e23daa4..5f75c4cb5a8 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java @@ -20704,6 +20704,24 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/inference/builderInference/nullability.kt"); } + @Test + @TestMetadata("partiallyResolvedCallInReturnArgument.kt") + public void testPartiallyResolvedCallInReturnArgument() throws Exception { + runTest("compiler/testData/codegen/box/inference/builderInference/partiallyResolvedCallInReturnArgument.kt"); + } + + @Test + @TestMetadata("partiallyResolvedCallInReturnArgumentNonLast.kt") + public void testPartiallyResolvedCallInReturnArgumentNonLast() throws Exception { + runTest("compiler/testData/codegen/box/inference/builderInference/partiallyResolvedCallInReturnArgumentNonLast.kt"); + } + + @Test + @TestMetadata("partiallyResolvedCallInReturnArgumentNonUnit.kt") + public void testPartiallyResolvedCallInReturnArgumentNonUnit() throws Exception { + runTest("compiler/testData/codegen/box/inference/builderInference/partiallyResolvedCallInReturnArgumentNonUnit.kt"); + } + @Test @TestMetadata("propagateInferenceSessionIntoDeclarationAnalyzers.kt") public void testPropagateInferenceSessionIntoDeclarationAnalyzers() throws Exception { diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenWithIrInlinerTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenWithIrInlinerTestGenerated.java index c1592e96aa6..e3eeba41c2d 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenWithIrInlinerTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenWithIrInlinerTestGenerated.java @@ -20704,6 +20704,24 @@ public class IrBlackBoxCodegenWithIrInlinerTestGenerated extends AbstractIrBlack runTest("compiler/testData/codegen/box/inference/builderInference/nullability.kt"); } + @Test + @TestMetadata("partiallyResolvedCallInReturnArgument.kt") + public void testPartiallyResolvedCallInReturnArgument() throws Exception { + runTest("compiler/testData/codegen/box/inference/builderInference/partiallyResolvedCallInReturnArgument.kt"); + } + + @Test + @TestMetadata("partiallyResolvedCallInReturnArgumentNonLast.kt") + public void testPartiallyResolvedCallInReturnArgumentNonLast() throws Exception { + runTest("compiler/testData/codegen/box/inference/builderInference/partiallyResolvedCallInReturnArgumentNonLast.kt"); + } + + @Test + @TestMetadata("partiallyResolvedCallInReturnArgumentNonUnit.kt") + public void testPartiallyResolvedCallInReturnArgumentNonUnit() throws Exception { + runTest("compiler/testData/codegen/box/inference/builderInference/partiallyResolvedCallInReturnArgumentNonUnit.kt"); + } + @Test @TestMetadata("propagateInferenceSessionIntoDeclarationAnalyzers.kt") public void testPropagateInferenceSessionIntoDeclarationAnalyzers() throws Exception { diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index ec4d43aeac4..6ab9702b2ad 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -16484,6 +16484,21 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/inference/builderInference/nullability.kt"); } + @TestMetadata("partiallyResolvedCallInReturnArgument.kt") + public void testPartiallyResolvedCallInReturnArgument() throws Exception { + runTest("compiler/testData/codegen/box/inference/builderInference/partiallyResolvedCallInReturnArgument.kt"); + } + + @TestMetadata("partiallyResolvedCallInReturnArgumentNonLast.kt") + public void testPartiallyResolvedCallInReturnArgumentNonLast() throws Exception { + runTest("compiler/testData/codegen/box/inference/builderInference/partiallyResolvedCallInReturnArgumentNonLast.kt"); + } + + @TestMetadata("partiallyResolvedCallInReturnArgumentNonUnit.kt") + public void testPartiallyResolvedCallInReturnArgumentNonUnit() throws Exception { + runTest("compiler/testData/codegen/box/inference/builderInference/partiallyResolvedCallInReturnArgumentNonUnit.kt"); + } + @TestMetadata("propagateInferenceSessionIntoDeclarationAnalyzers.kt") public void testPropagateInferenceSessionIntoDeclarationAnalyzers() throws Exception { runTest("compiler/testData/codegen/box/inference/builderInference/propagateInferenceSessionIntoDeclarationAnalyzers.kt"); diff --git a/docs/fir/builder_inference.md b/docs/fir/builder_inference.md index 5ca20114e87..b90593e900e 100644 --- a/docs/fir/builder_inference.md +++ b/docs/fir/builder_inference.md @@ -99,6 +99,10 @@ See `org.jetbrains.kotlin.fir.resolve.inference.PostponedArgumentsAnalyzer.apply Once the lambda body was analyzed return arguments are added into the call-tree +> ##### Note: Incomplete calls in return arguments +> We don't add last expression of lambda to the call-tree as a return argument if its functional-type has Unit return-type, to +> avoid situations when last expression contains incomplete call, see [Incomplete call in return arguments](#incomplete-call-in-return-arguments) + Then, we perform inference of postponed type variables See `org.jetbrains.kotlin.fir.resolve.inference.FirBuilderInferenceSession.inferPostponedVariables` @@ -207,4 +211,14 @@ type variable from the call-tree and solution from integration CS, loosing infor It causes unsound solutions in the call-tree CS #### Resulting substitution is unclear Its unclear why we mix stub type substitutor with type-variable-type substitutor, and why we need to manually handle substitution to error -types \ No newline at end of file +types +#### Incomplete call in return arguments +If incomplete call is present among return arguments during [Lambda analysis finalization](#lambda-analysis-finalization) we add it to the +main call-tree, but then complete it as part of [result writing](#result-write). + +It leads to violation of contract in `org.jetbrains.kotlin.fir.resolve.inference.ConstraintSystemCompleter.getOrderedAllTypeVariables` as type variables for completed call couldn't be found anymore + +To avoid such problem, we have [workaround for lambdas with Unit return-type](#Note-Incomplete-calls-in-return-arguments), but problem still +occurs: +- When we have [lambdas with non-Unit return-type](https://youtrack.jetbrains.com/issue/KT-58741) +- When the [incomplete call is present in a return argument that isn't last expression](https://youtrack.jetbrains.com/issue/KT-58742) \ No newline at end of file