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 082846cd748..73e7ff696fe 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 @@ -16430,6 +16430,12 @@ public class DiagnosticCompilerTestFE10TestdataTestGenerated extends AbstractDia runTest("compiler/testData/diagnostics/tests/inference/kt62609.kt"); } + @Test + @TestMetadata("kt63982.kt") + public void testKt63982() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/kt63982.kt"); + } + @Test @TestMetadata("lambdaArgumentWithLabel.kt") public void testLambdaArgumentWithLabel() 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 f71a88f4a7f..2c487edb790 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 @@ -16430,6 +16430,12 @@ public class LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated runTest("compiler/testData/diagnostics/tests/inference/kt62609.kt"); } + @Test + @TestMetadata("kt63982.kt") + public void testKt63982() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/kt63982.kt"); + } + @Test @TestMetadata("lambdaArgumentWithLabel.kt") public void testLambdaArgumentWithLabel() 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 602a71eb843..da18c5148cc 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 @@ -16424,6 +16424,12 @@ public class FirLightTreeOldFrontendDiagnosticsTestGenerated extends AbstractFir runTest("compiler/testData/diagnostics/tests/inference/kt62609.kt"); } + @Test + @TestMetadata("kt63982.kt") + public void testKt63982() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/kt63982.kt"); + } + @Test @TestMetadata("lambdaArgumentWithLabel.kt") public void testLambdaArgumentWithLabel() 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 4dce4f36449..f8fc8fd2522 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 @@ -16430,6 +16430,12 @@ public class FirPsiOldFrontendDiagnosticsTestGenerated extends AbstractFirPsiDia runTest("compiler/testData/diagnostics/tests/inference/kt62609.kt"); } + @Test + @TestMetadata("kt63982.kt") + public void testKt63982() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/kt63982.kt"); + } + @Test @TestMetadata("lambdaArgumentWithLabel.kt") public void testLambdaArgumentWithLabel() throws Exception { diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/TypeUtils.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/TypeUtils.kt index 6a96e9c2435..8dd21ac939d 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/TypeUtils.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/TypeUtils.kt @@ -533,32 +533,43 @@ internal fun ConeTypeContext.captureFromExpressionInternal(type: ConeKotlinType) fun findCorrespondingCapturedArgumentsForType(type: ConeKotlinType) = capturedArgumentsByComponents.find { typeToCapture -> typeToCapture.isSuitableForType(type, this) }?.capturedArguments - fun replaceArgumentsWithCapturedArgumentsByIntersectionComponents(typeToReplace: ConeSimpleKotlinType): List { + fun replaceArgumentsWithCapturedArgumentsByIntersectionComponents(typeToReplace: ConeSimpleKotlinType): List? { return if (typeToReplace is ConeIntersectionType) { typeToReplace.intersectedTypes.map { componentType -> val capturedArguments = findCorrespondingCapturedArgumentsForType(componentType) ?: return@map componentType componentType.withArguments(capturedArguments) - } + }.takeUnless { it == typeToReplace.intersectedTypes } } else { val capturedArguments = findCorrespondingCapturedArgumentsForType(typeToReplace) - ?: return listOf(typeToReplace) + ?: return null listOf(typeToReplace.withArguments(capturedArguments)) } } return when (type) { is ConeFlexibleType -> { - val lowerIntersectedType = intersectTypes(replaceArgumentsWithCapturedArgumentsByIntersectionComponents(type.lowerBound)) - .withNullability(ConeNullability.create(type.lowerBound.isMarkedNullable), this) - val upperIntersectedType = intersectTypes(replaceArgumentsWithCapturedArgumentsByIntersectionComponents(type.upperBound)) - .withNullability(ConeNullability.create(type.upperBound.isMarkedNullable), this) + // Flexible types can either have projections in both bounds or just the upper bound (raw types and arrays). + // Since the scope of flexible types is built from the lower bound, we don't gain any safety from only capturing the + // upper bound. + // At the same time, capturing of raw(-like) types leads to issues like KT-63982 or breaks tests like + // testData/codegen/box/reflection/typeOf/rawTypes_after.kt. + // Therefore, we return null if nothing was captured for either bound. + + val lowerIntersectedType = + intersectTypes(replaceArgumentsWithCapturedArgumentsByIntersectionComponents(type.lowerBound) ?: return null) + .withNullability(ConeNullability.create(type.lowerBound.isMarkedNullable), this) + val upperIntersectedType = + intersectTypes(replaceArgumentsWithCapturedArgumentsByIntersectionComponents(type.upperBound) ?: return null) + .withNullability(ConeNullability.create(type.upperBound.isMarkedNullable), this) ConeFlexibleType(lowerIntersectedType.coneLowerBoundIfFlexible(), upperIntersectedType.coneUpperBoundIfFlexible()) } is ConeSimpleKotlinType -> { - intersectTypes(replaceArgumentsWithCapturedArgumentsByIntersectionComponents(type)).withNullability(type.isMarkedNullable) as ConeKotlinType + intersectTypes( + replaceArgumentsWithCapturedArgumentsByIntersectionComponents(type) ?: return null + ).withNullability(type.isMarkedNullable) as ConeKotlinType } } } diff --git a/compiler/testData/diagnostics/tests/inference/kt63982.kt b/compiler/testData/diagnostics/tests/inference/kt63982.kt new file mode 100644 index 00000000000..b3ca165946f --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/kt63982.kt @@ -0,0 +1,19 @@ +// ISSUE: KT-63982 +// FIR_IDENTICAL +// DIAGNOSTICS: -DEBUG_INFO_SMARTCAST + +// FILE: StubBasedPsiElement.java +public interface StubBasedPsiElement extends PsiElement { + Stub getStub(); +} + +// FILE: test.kt +interface PsiElement +interface JSCallExpression: PsiElement +interface StubElement + +fun test(child: PsiElement) { + if (child is JSCallExpression) { + val callStub = if (child is StubBasedPsiElement<*>) child.stub else 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 1d92411c752..421e5e29f0b 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 @@ -16430,6 +16430,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { runTest("compiler/testData/diagnostics/tests/inference/kt62609.kt"); } + @Test + @TestMetadata("kt63982.kt") + public void testKt63982() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/kt63982.kt"); + } + @Test @TestMetadata("lambdaArgumentWithLabel.kt") public void testLambdaArgumentWithLabel() throws Exception {