[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:
committed by
Space Team
parent
eaa93b2582
commit
476a0b6783
+6
@@ -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 {
|
||||
|
||||
+6
@@ -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 {
|
||||
|
||||
+6
@@ -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 {
|
||||
|
||||
+6
@@ -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
|
||||
}
|
||||
}
|
||||
Generated
+6
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user