[FIR] Don't capture flexible types that only have projections in one bound

This fixes a false positive NEW_INFERENCE_ERROR.
See the code comment for the rationale.

#KT-63982 Fixed
This commit is contained in:
Kirill Rakhman
2023-12-01 17:03:43 +01:00
committed by Space Team
parent eaa93b2582
commit 476a0b6783
7 changed files with 68 additions and 8 deletions
@@ -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 {
@@ -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 {
@@ -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 {
@@ -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 {
@@ -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<ConeKotlinType> {
fun replaceArgumentsWithCapturedArgumentsByIntersectionComponents(typeToReplace: ConeSimpleKotlinType): List<ConeKotlinType>? {
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
}
}
}
@@ -0,0 +1,19 @@
// ISSUE: KT-63982
// FIR_IDENTICAL
// DIAGNOSTICS: -DEBUG_INFO_SMARTCAST
// FILE: StubBasedPsiElement.java
public interface StubBasedPsiElement<Stub extends StubElement> extends PsiElement {
Stub getStub();
}
// FILE: test.kt
interface PsiElement
interface JSCallExpression: PsiElement
interface StubElement<T : PsiElement>
fun test(child: PsiElement) {
if (child is JSCallExpression) {
val callStub = if (child is StubBasedPsiElement<*>) child.stub else null
}
}
@@ -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 {