diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java index d7cd6ab71f7..ba28716f054 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java @@ -13946,6 +13946,18 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag runTest("compiler/testData/diagnostics/tests/inference/inferInFunctionLiteralsWithReturn.kt"); } + @Test + @TestMetadata("inferenceForkRegression.kt") + public void testInferenceForkRegression() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/inferenceForkRegression.kt"); + } + + @Test + @TestMetadata("inferenceForkRegressionSimple.kt") + public void testInferenceForkRegressionSimple() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/inferenceForkRegressionSimple.kt"); + } + @Test @TestMetadata("intersectionTypeMultipleBoundsAsReceiver.kt") public void testIntersectionTypeMultipleBoundsAsReceiver() throws Exception { @@ -15972,6 +15984,22 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag } } + @Nested + @TestMetadata("compiler/testData/diagnostics/tests/inference/forks") + @TestDataPath("$PROJECT_ROOT") + public class Forks { + @Test + public void testAllFilesPresentInForks() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/inference/forks"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true); + } + + @Test + @TestMetadata("overloadResolutionByLambdaReturnTypeAndExpectedType.kt") + public void testOverloadResolutionByLambdaReturnTypeAndExpectedType() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/forks/overloadResolutionByLambdaReturnTypeAndExpectedType.kt"); + } + } + @Nested @TestMetadata("compiler/testData/diagnostics/tests/inference/nestedCalls") @TestDataPath("$PROJECT_ROOT") diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java index e77ab8629da..d328e1318c7 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java @@ -13946,6 +13946,18 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti runTest("compiler/testData/diagnostics/tests/inference/inferInFunctionLiteralsWithReturn.kt"); } + @Test + @TestMetadata("inferenceForkRegression.kt") + public void testInferenceForkRegression() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/inferenceForkRegression.kt"); + } + + @Test + @TestMetadata("inferenceForkRegressionSimple.kt") + public void testInferenceForkRegressionSimple() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/inferenceForkRegressionSimple.kt"); + } + @Test @TestMetadata("intersectionTypeMultipleBoundsAsReceiver.kt") public void testIntersectionTypeMultipleBoundsAsReceiver() throws Exception { @@ -15972,6 +15984,22 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti } } + @Nested + @TestMetadata("compiler/testData/diagnostics/tests/inference/forks") + @TestDataPath("$PROJECT_ROOT") + public class Forks { + @Test + public void testAllFilesPresentInForks() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/inference/forks"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true); + } + + @Test + @TestMetadata("overloadResolutionByLambdaReturnTypeAndExpectedType.kt") + public void testOverloadResolutionByLambdaReturnTypeAndExpectedType() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/forks/overloadResolutionByLambdaReturnTypeAndExpectedType.kt"); + } + } + @Nested @TestMetadata("compiler/testData/diagnostics/tests/inference/nestedCalls") @TestDataPath("$PROJECT_ROOT") diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java index d86b00ff448..4e5a779e522 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java @@ -13946,6 +13946,18 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac runTest("compiler/testData/diagnostics/tests/inference/inferInFunctionLiteralsWithReturn.kt"); } + @Test + @TestMetadata("inferenceForkRegression.kt") + public void testInferenceForkRegression() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/inferenceForkRegression.kt"); + } + + @Test + @TestMetadata("inferenceForkRegressionSimple.kt") + public void testInferenceForkRegressionSimple() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/inferenceForkRegressionSimple.kt"); + } + @Test @TestMetadata("intersectionTypeMultipleBoundsAsReceiver.kt") public void testIntersectionTypeMultipleBoundsAsReceiver() throws Exception { @@ -15972,6 +15984,22 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac } } + @Nested + @TestMetadata("compiler/testData/diagnostics/tests/inference/forks") + @TestDataPath("$PROJECT_ROOT") + public class Forks { + @Test + public void testAllFilesPresentInForks() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/inference/forks"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true); + } + + @Test + @TestMetadata("overloadResolutionByLambdaReturnTypeAndExpectedType.kt") + public void testOverloadResolutionByLambdaReturnTypeAndExpectedType() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/forks/overloadResolutionByLambdaReturnTypeAndExpectedType.kt"); + } + } + @Nested @TestMetadata("compiler/testData/diagnostics/tests/inference/nestedCalls") @TestDataPath("$PROJECT_ROOT") diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/ConstraintSystemCompleter.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/ConstraintSystemCompleter.kt index 2a7edd5682b..e8de535c77f 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/ConstraintSystemCompleter.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/ConstraintSystemCompleter.kt @@ -62,7 +62,7 @@ class ConstraintSystemCompleter(components: BodyResolveComponents, private val c ) { val topLevelTypeVariables = topLevelType.extractTypeVariables() - if (completionMode == ConstraintSystemCompletionMode.FULL) { + if (completionMode == ConstraintSystemCompletionMode.FULL || completionMode == ConstraintSystemCompletionMode.UNTIL_FIRST_LAMBDA) { resolveForkPointsConstraints() } diff --git a/compiler/testData/diagnostics/tests/inference/forks/overloadResolutionByLambdaReturnTypeAndExpectedType.fir.kt b/compiler/testData/diagnostics/tests/inference/forks/overloadResolutionByLambdaReturnTypeAndExpectedType.fir.kt new file mode 100644 index 00000000000..22aa6078530 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/forks/overloadResolutionByLambdaReturnTypeAndExpectedType.fir.kt @@ -0,0 +1,39 @@ +// SKIP_TXT +// WITH_STDLIB +import kotlin.experimental.ExperimentalTypeInference + +interface MyList +interface MySequence + +fun myListOf(e: E): MyList = TODO() + +interface C : MyList + +fun foo(m: MyList, c: C) { + if (c === m) { + val x1: MyList = m.noOverloadResolutionByLambdaReturnType { x -> + myListOf(x) + } // ok in K1 and K2 + + val x2: MyList = m.noOverloadResolutionByLambdaReturnType { x -> + myListOf(x) + } // ok in K2, error in k1 + + val y1: MyList = m.limitedFlatMap { x -> + myListOf(x) + } // ok in K1 and K2 + + val y2: MyList = m.limitedFlatMap { x -> + myListOf(x) + } // error in K1 and K2 + } +} + +fun MyList.noOverloadResolutionByLambdaReturnType(producer: (T) -> MyList): MyList = TODO() + +fun MyList.limitedFlatMap(producer: (T) -> MyList): MyList = TODO() + +@OptIn(ExperimentalTypeInference::class) +@OverloadResolutionByLambdaReturnType +@kotlin.jvm.JvmName("limitedFlatMapSeq") +fun MyList.limitedFlatMap(producer: (T) -> MySequence): MyList = TODO() diff --git a/compiler/testData/diagnostics/tests/inference/forks/overloadResolutionByLambdaReturnTypeAndExpectedType.kt b/compiler/testData/diagnostics/tests/inference/forks/overloadResolutionByLambdaReturnTypeAndExpectedType.kt new file mode 100644 index 00000000000..1e0ebbc2b61 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/forks/overloadResolutionByLambdaReturnTypeAndExpectedType.kt @@ -0,0 +1,39 @@ +// SKIP_TXT +// WITH_STDLIB +import kotlin.experimental.ExperimentalTypeInference + +interface MyList +interface MySequence + +fun myListOf(e: E): MyList = TODO() + +interface C : MyList + +fun foo(m: MyList, c: C) { + if (c === m) { + val x1: MyList = m.noOverloadResolutionByLambdaReturnType { x -> + myListOf(x) + } // ok in K1 and K2 + + val x2: MyList = m.noOverloadResolutionByLambdaReturnType { x -> + myListOf(x) + } // ok in K2, error in k1 + + val y1: MyList = m.limitedFlatMap { x -> + myListOf(x) + } // ok in K1 and K2 + + val y2: MyList = m.limitedFlatMap { x -> + myListOf(x) + } // error in K1 and K2 + } +} + +fun MyList.noOverloadResolutionByLambdaReturnType(producer: (T) -> MyList): MyList = TODO() + +fun MyList.limitedFlatMap(producer: (T) -> MyList): MyList = TODO() + +@OptIn(ExperimentalTypeInference::class) +@OverloadResolutionByLambdaReturnType +@kotlin.jvm.JvmName("limitedFlatMapSeq") +fun MyList.limitedFlatMap(producer: (T) -> MySequence): MyList = TODO() diff --git a/compiler/testData/diagnostics/tests/inference/inferenceForkRegression.kt b/compiler/testData/diagnostics/tests/inference/inferenceForkRegression.kt new file mode 100644 index 00000000000..ba20d601083 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/inferenceForkRegression.kt @@ -0,0 +1,26 @@ +// SKIP_TXT +// FIR_IDENTICAL +// FULL_JDK +// WITH_STDLIB + +import java.util.concurrent.ConcurrentHashMap + +interface ModificationData + +fun main() { + val updatedFiles = ConcurrentHashMap() + + // HashMap effectively have two Map supertypes: one like Map and one Map (through AbstractMap) + // But here, since `updatedFiles` has only a supertype Map + // `updatedFilesSnapshot` has two supertypes relevant to Map: Map and one Map + // Actually, we might collapse them, because they're equivalent, but for now we don't + val updatedFilesSnapshot = HashMap(updatedFiles) + + // Thus, it leads to constraint system fork during `flatMap` inference + // And during overload resolution between two `flatMap` versions with @OverloadResolutionByLambdaReturnType we have to run lambda analysis + // So, we have to apply forks to the system on this completion phase too, but still not for the PARTIAL completion mode + // Otherwise, OVERLOAD_RESOLUTION_AMBIGUITY happens + updatedFilesSnapshot.flatMap { _ -> + listOf("") + } +} diff --git a/compiler/testData/diagnostics/tests/inference/inferenceForkRegressionSimple.fir.kt b/compiler/testData/diagnostics/tests/inference/inferenceForkRegressionSimple.fir.kt new file mode 100644 index 00000000000..e3956c1ed8a --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/inferenceForkRegressionSimple.fir.kt @@ -0,0 +1,21 @@ +// SKIP_TXT +// FULL_JDK +// WITH_STDLIB + +interface C : MutableMap + +fun foo(m: MutableMap, c: C) { + if (c === m) { + // `m` has a type C & MutableMap + // So it has two instances of Map supertypes: Map and Map + // + // Thus, it leads to constraint system fork during `flatMap` inference + // And during overload resolution between two `flatMap` versions with @OverloadResolutionByLambdaReturnType we have to run lambda analysis + // So, we have to apply forks to the system on this completion phase too, so we would have enough information for the input types of lambda + // Otherwise, OVERLOAD_RESOLUTION_AMBIGUITY happens + // But we don't do it for PARTIAL completion mode still + c.flatMap { _ -> + listOf("") + } + } +} diff --git a/compiler/testData/diagnostics/tests/inference/inferenceForkRegressionSimple.kt b/compiler/testData/diagnostics/tests/inference/inferenceForkRegressionSimple.kt new file mode 100644 index 00000000000..aa5ec4cfd8f --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/inferenceForkRegressionSimple.kt @@ -0,0 +1,21 @@ +// SKIP_TXT +// FULL_JDK +// WITH_STDLIB + +interface C : MutableMap + +fun foo(m: MutableMap, c: C) { + if (c === m) { + // `m` has a type C & MutableMap + // So it has two instances of Map supertypes: Map and Map + // + // Thus, it leads to constraint system fork during `flatMap` inference + // And during overload resolution between two `flatMap` versions with @OverloadResolutionByLambdaReturnType we have to run lambda analysis + // So, we have to apply forks to the system on this completion phase too, so we would have enough information for the input types of lambda + // Otherwise, OVERLOAD_RESOLUTION_AMBIGUITY happens + // But we don't do it for PARTIAL completion mode still + c.flatMap { _ -> + listOf("") + } + } +} 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 64feb469317..e9075d071ac 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 @@ -13952,6 +13952,18 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { runTest("compiler/testData/diagnostics/tests/inference/inferInFunctionLiteralsWithReturn.kt"); } + @Test + @TestMetadata("inferenceForkRegression.kt") + public void testInferenceForkRegression() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/inferenceForkRegression.kt"); + } + + @Test + @TestMetadata("inferenceForkRegressionSimple.kt") + public void testInferenceForkRegressionSimple() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/inferenceForkRegressionSimple.kt"); + } + @Test @TestMetadata("intersectionTypeMultipleBoundsAsReceiver.kt") public void testIntersectionTypeMultipleBoundsAsReceiver() throws Exception { @@ -15978,6 +15990,22 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { } } + @Nested + @TestMetadata("compiler/testData/diagnostics/tests/inference/forks") + @TestDataPath("$PROJECT_ROOT") + public class Forks { + @Test + public void testAllFilesPresentInForks() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/inference/forks"), Pattern.compile("^(.*)\\.kts?$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true); + } + + @Test + @TestMetadata("overloadResolutionByLambdaReturnTypeAndExpectedType.kt") + public void testOverloadResolutionByLambdaReturnTypeAndExpectedType() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/forks/overloadResolutionByLambdaReturnTypeAndExpectedType.kt"); + } + } + @Nested @TestMetadata("compiler/testData/diagnostics/tests/inference/nestedCalls") @TestDataPath("$PROJECT_ROOT")