From 582dd1d3c0aaec75f51ccf0ecae3c78ac453c8cd Mon Sep 17 00:00:00 2001 From: Kirill Rakhman Date: Wed, 17 Jan 2024 17:18:11 +0100 Subject: [PATCH] [FIR] Only don't approximate nested captured arguments if they have recursive supertypes This fixes a compiler crash IllegalStateException: Captured type for incorporation shouldn't escape from incorporation The crash occurs when a captured type with status FOR_INCORPORATION is two layers deep inside a captured type with status FROM_EXPRESSION. We first check if approximation is required for the most outer captured type in AbstractTypeApproximator.approximateCapturedType. Then we encounter the second captured type with status FROM_EXPRESSION in AbstractTypeApproximator.approximateParametrizedType. At this point, we stop checking and miss the third captured type with status FOR_INCORPORATION. Unfortunately, we can't check recursively if nested captured types need to be approximated because of types with recursive super types (the original reason why the extra check was introduced). That's why we restrict the second check to types with recursive super types, effectively restoring the previous behavior for all other types. #KT-65050 Fixed --- ...cCompilerTestFE10TestdataTestGenerated.java | 6 ++++++ ...osticCompilerFE10TestDataTestGenerated.java | 6 ++++++ ...reeOldFrontendDiagnosticsTestGenerated.java | 6 ++++++ ...PsiOldFrontendDiagnosticsTestGenerated.java | 6 ++++++ .../kotlin/types/AbstractTypeApproximator.kt | 7 ++++++- .../capturedForIncorporationEscapes.kt | 18 ++++++++++++++++++ .../test/runners/DiagnosticTestGenerated.java | 6 ++++++ 7 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 compiler/testData/diagnostics/tests/inference/capturedTypes/capturedForIncorporationEscapes.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 c02c59f5044..6f05c03b433 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 @@ -17899,6 +17899,12 @@ public class DiagnosticCompilerTestFE10TestdataTestGenerated extends AbstractDia runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/capturedFlexibleIntersectionTypesWithDifferentConstructors.kt"); } + @Test + @TestMetadata("capturedForIncorporationEscapes.kt") + public void testCapturedForIncorporationEscapes() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/capturedForIncorporationEscapes.kt"); + } + @Test @TestMetadata("capturedInTypeInference.kt") public void testCapturedInTypeInference() 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 d846e9f88ca..9586f0dc171 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 @@ -17899,6 +17899,12 @@ public class LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/capturedFlexibleIntersectionTypesWithDifferentConstructors.kt"); } + @Test + @TestMetadata("capturedForIncorporationEscapes.kt") + public void testCapturedForIncorporationEscapes() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/capturedForIncorporationEscapes.kt"); + } + @Test @TestMetadata("capturedInTypeInference.kt") public void testCapturedInTypeInference() 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 737366797df..5831a2c7655 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 @@ -17893,6 +17893,12 @@ public class FirLightTreeOldFrontendDiagnosticsTestGenerated extends AbstractFir runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/capturedFlexibleIntersectionTypesWithDifferentConstructors.kt"); } + @Test + @TestMetadata("capturedForIncorporationEscapes.kt") + public void testCapturedForIncorporationEscapes() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/capturedForIncorporationEscapes.kt"); + } + @Test @TestMetadata("capturedInTypeInference.kt") public void testCapturedInTypeInference() 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 68189e8378b..b607c8ab8c4 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 @@ -17899,6 +17899,12 @@ public class FirPsiOldFrontendDiagnosticsTestGenerated extends AbstractFirPsiDia runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/capturedFlexibleIntersectionTypesWithDifferentConstructors.kt"); } + @Test + @TestMetadata("capturedForIncorporationEscapes.kt") + public void testCapturedForIncorporationEscapes() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/capturedForIncorporationEscapes.kt"); + } + @Test @TestMetadata("capturedInTypeInference.kt") public void testCapturedInTypeInference() throws Exception { diff --git a/compiler/resolution.common/src/org/jetbrains/kotlin/types/AbstractTypeApproximator.kt b/compiler/resolution.common/src/org/jetbrains/kotlin/types/AbstractTypeApproximator.kt index 711bd5b8dc5..e6a51ba63af 100644 --- a/compiler/resolution.common/src/org/jetbrains/kotlin/types/AbstractTypeApproximator.kt +++ b/compiler/resolution.common/src/org/jetbrains/kotlin/types/AbstractTypeApproximator.kt @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.types import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.resolve.calls.NewCommonSuperTypeCalculator.commonSuperType +import org.jetbrains.kotlin.resolve.calls.inference.hasRecursiveTypeParametersWithGivenSelfType import org.jetbrains.kotlin.types.model.* import org.jetbrains.kotlin.utils.addToStdlib.runIf import java.util.concurrent.ConcurrentHashMap @@ -481,7 +482,11 @@ abstract class AbstractTypeApproximator( // In approximateCapturedType, we check if the super/subtypes of captured types need approximation even if captured types // themselves don't need approximation, and will land here. // To support this case, we also don't want to approximate captured types here if the configuration says so. - if (capturedType != null && isK2 && !conf.capturedType(ctx, capturedType)) { + if (capturedType != null && + isK2 && + !conf.capturedType(ctx, capturedType) && + ctx.hasRecursiveTypeParametersWithGivenSelfType(capturedType.typeConstructor()) + ) { continue@loop } diff --git a/compiler/testData/diagnostics/tests/inference/capturedTypes/capturedForIncorporationEscapes.kt b/compiler/testData/diagnostics/tests/inference/capturedTypes/capturedForIncorporationEscapes.kt new file mode 100644 index 00000000000..43a0c8ca0aa --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/capturedTypes/capturedForIncorporationEscapes.kt @@ -0,0 +1,18 @@ +// FIR_IDENTICAL +// ISSUE: KT-65050 + +interface HttpResponse + +class GitLabMergeRequestShortRestDTO + +fun loadMergeRequests(): HttpResponse> = TODO() + +inline fun loadList(): HttpResponse> = TODO() + +fun loadMergeRequests(boolean: Boolean) { + val response = if (boolean) { + loadMergeRequests() + } else { + loadList() + } +} \ No newline at end of file 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 d49ec3412d6..7c097723e45 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 @@ -17899,6 +17899,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/capturedFlexibleIntersectionTypesWithDifferentConstructors.kt"); } + @Test + @TestMetadata("capturedForIncorporationEscapes.kt") + public void testCapturedForIncorporationEscapes() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/capturedForIncorporationEscapes.kt"); + } + @Test @TestMetadata("capturedInTypeInference.kt") public void testCapturedInTypeInference() throws Exception {