[FIR] Fix inference based on recursive upper bound
#KT-59012 Fixed
This commit is contained in:
committed by
Space Team
parent
251827c9aa
commit
9d91eb2510
+6
@@ -17875,6 +17875,12 @@ public class DiagnosticCompilerTestFE10TestdataTestGenerated extends AbstractDia
|
||||
runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/capturedFlexibleIntersectionTypesWithDifferentConstructors.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("capturedInTypeInference.kt")
|
||||
public void testCapturedInTypeInference() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/capturedInTypeInference.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("capturedType.kt")
|
||||
public void testCapturedType() throws Exception {
|
||||
|
||||
+6
@@ -17875,6 +17875,12 @@ public class LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated
|
||||
runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/capturedFlexibleIntersectionTypesWithDifferentConstructors.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("capturedInTypeInference.kt")
|
||||
public void testCapturedInTypeInference() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/capturedInTypeInference.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("capturedType.kt")
|
||||
public void testCapturedType() throws Exception {
|
||||
|
||||
+6
@@ -17869,6 +17869,12 @@ public class FirLightTreeOldFrontendDiagnosticsTestGenerated extends AbstractFir
|
||||
runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/capturedFlexibleIntersectionTypesWithDifferentConstructors.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("capturedInTypeInference.kt")
|
||||
public void testCapturedInTypeInference() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/capturedInTypeInference.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("capturedType.kt")
|
||||
public void testCapturedType() throws Exception {
|
||||
|
||||
+6
@@ -17875,6 +17875,12 @@ public class FirPsiOldFrontendDiagnosticsTestGenerated extends AbstractFirPsiDia
|
||||
runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/capturedFlexibleIntersectionTypesWithDifferentConstructors.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("capturedInTypeInference.kt")
|
||||
public void testCapturedInTypeInference() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/capturedInTypeInference.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("capturedType.kt")
|
||||
public void testCapturedType() throws Exception {
|
||||
|
||||
+4
-3
@@ -47,8 +47,9 @@ fun ConstraintStorage.buildNotFixedVariablesToNonSubtypableTypesSubstitutor(
|
||||
)
|
||||
}
|
||||
|
||||
fun TypeSystemInferenceExtensionContext.hasRecursiveTypeParametersWithGivenSelfType(selfTypeConstructor: TypeConstructorMarker) =
|
||||
selfTypeConstructor.getParameters().any { it.hasRecursiveBounds(selfTypeConstructor) }
|
||||
fun TypeSystemInferenceExtensionContext.hasRecursiveTypeParametersWithGivenSelfType(selfTypeConstructor: TypeConstructorMarker): Boolean =
|
||||
selfTypeConstructor.getParameters().any { it.hasRecursiveBounds(selfTypeConstructor) } ||
|
||||
isK2 && selfTypeConstructor is CapturedTypeConstructorMarker && selfTypeConstructor.supertypes().any { hasRecursiveTypeParametersWithGivenSelfType(it.typeConstructor()) }
|
||||
|
||||
fun TypeSystemInferenceExtensionContext.isRecursiveTypeParameter(typeConstructor: TypeConstructorMarker) =
|
||||
typeConstructor.getTypeParameterClassifier()?.hasRecursiveBounds() == true
|
||||
@@ -79,4 +80,4 @@ fun NewConstraintSystemImpl.registerTypeVariableIfNotPresent(
|
||||
if (typeVariable.freshTypeConstructor(this) !in builder.currentStorage().allTypeVariables.keys) {
|
||||
builder.registerVariable(typeVariable)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+5
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.resolve.calls.NewCommonSuperTypeCalculator
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.components.TypeVariableDirectionCalculator.ResolveDirection
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.extractTypeForGivenRecursiveTypeParameter
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.hasRecursiveTypeParametersWithGivenSelfType
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.*
|
||||
import org.jetbrains.kotlin.types.AbstractTypeApproximator
|
||||
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
||||
@@ -349,6 +350,10 @@ class ResultTypeResolver(
|
||||
if (upperConstraints.isNotEmpty()) {
|
||||
val upperType = computeUpperType(upperConstraints)
|
||||
|
||||
if (isK2 && hasRecursiveTypeParametersWithGivenSelfType(upperType.typeConstructor())) {
|
||||
return upperType
|
||||
}
|
||||
|
||||
return typeApproximator.approximateToSubType(
|
||||
upperType,
|
||||
TypeApproximatorConfiguration.InternalTypesApproximation
|
||||
|
||||
@@ -476,6 +476,15 @@ abstract class AbstractTypeApproximator(
|
||||
val argumentType = newArguments[index]?.getType() ?: argument.getType()
|
||||
|
||||
val capturedType = argumentType.lowerBoundIfFlexible().originalIfDefinitelyNotNullable().asCapturedType()
|
||||
|
||||
// When capturing recursive types with self upper bounds, their super types can contain captured types.
|
||||
// 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)) {
|
||||
continue@loop
|
||||
}
|
||||
|
||||
val capturedStarProjectionOrNull =
|
||||
capturedType?.typeConstructorProjection()?.takeIf { it.isStarProjection() }
|
||||
|
||||
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
// FIR_IDENTICAL
|
||||
class Key<T>
|
||||
class Box<T>
|
||||
|
||||
fun <T : Any> get(key: Key<in T>): T? = null
|
||||
fun <T> acceptBox(box: Box<T>) {}
|
||||
|
||||
fun <V> test(key: Key<in Box<V>>) {
|
||||
// CS of get:
|
||||
// Key<CapturedType(in Box<V>)> <: Key<in TypeVariable(T)>
|
||||
// If the type is not approximated to subtype before fixation, the type of the lambda parameter `it` becomes Any?
|
||||
get(key)?.let { acceptBox(it) }
|
||||
|
||||
val x = get(key)
|
||||
x?.let { acceptBox(it) }
|
||||
}
|
||||
+2
-2
@@ -8,6 +8,6 @@ fun <E> A<E>.bar(): A<in E> = this
|
||||
|
||||
fun baz(x: A<out CharSequence>) {
|
||||
x.bar() checkType { _<A<*>>() }
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("CapturedType(in CapturedType(out kotlin.CharSequence))")!>x.bar().foo()<!> checkType { <!UNRESOLVED_REFERENCE_WRONG_RECEIVER!>_<!><Any?>() } // See KT-10448
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("CapturedType(in CapturedType(out kotlin.CharSequence))")!>x.bar().foo()<!> checkType { _<CharSequence>() } // Inference change in K2
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("CapturedType(in CapturedType(out kotlin.CharSequence))")!>x.bar().foo()<!> checkType { _<Any?>() } // See KT-10448
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("CapturedType(in CapturedType(out kotlin.CharSequence))")!>x.bar().foo()<!> checkType { <!UNRESOLVED_REFERENCE_WRONG_RECEIVER!>_<!><CharSequence>() } // Inference change in K2
|
||||
}
|
||||
+17
-6
@@ -13,14 +13,21 @@ class Builder<B : Builder<B>> {
|
||||
fun <T : B> test(): T = TODO()
|
||||
|
||||
fun foo() {}
|
||||
fun bar(block: () -> Out<B>) {}
|
||||
}
|
||||
|
||||
class Out<out T>
|
||||
|
||||
fun testStar(builder: Builder<*>) {
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("ERROR CLASS: Cannot infer argument for type parameter T")!>builder.<!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>test<!>()<!>
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("CapturedType(*)")!>builder.test()<!>
|
||||
|
||||
builder
|
||||
.<!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>test<!>()
|
||||
.<!UNRESOLVED_REFERENCE!>foo<!>()
|
||||
.test()
|
||||
.foo()
|
||||
|
||||
builder
|
||||
.test()
|
||||
.bar { Out() }
|
||||
}
|
||||
|
||||
fun <K : Builder<K>> testTypeParam(builder: Builder<K>) {
|
||||
@@ -29,14 +36,18 @@ fun <K : Builder<K>> testTypeParam(builder: Builder<K>) {
|
||||
builder
|
||||
.test()
|
||||
.foo()
|
||||
|
||||
builder
|
||||
.test()
|
||||
.bar { Out() }
|
||||
}
|
||||
|
||||
fun testStarJava(builder: JavaBuilder<*>) {
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("ERROR CLASS: Cannot infer argument for type parameter T")!>builder.<!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>test<!>()<!>
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("CapturedType(*)!!..CapturedType(*)?!")!>builder.test()<!>
|
||||
|
||||
builder
|
||||
.<!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>test<!>()
|
||||
.<!UNRESOLVED_REFERENCE!>foo<!>()
|
||||
.test()
|
||||
.foo()
|
||||
}
|
||||
|
||||
fun <K : JavaBuilder<K>> testTypeParamJava(builder: JavaBuilder<K>) {
|
||||
|
||||
+11
@@ -13,14 +13,21 @@ class Builder<B : Builder<B>> {
|
||||
fun <T : B> test(): T = TODO()
|
||||
|
||||
fun foo() {}
|
||||
fun bar(block: () -> Out<B>) {}
|
||||
}
|
||||
|
||||
class Out<out T>
|
||||
|
||||
fun testStar(builder: Builder<*>) {
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("Builder<*>")!>builder.test()<!>
|
||||
|
||||
builder
|
||||
.test()
|
||||
.foo()
|
||||
|
||||
builder
|
||||
.test()
|
||||
.bar { Out() }
|
||||
}
|
||||
|
||||
fun <K : Builder<K>> testTypeParam(builder: Builder<K>) {
|
||||
@@ -29,6 +36,10 @@ fun <K : Builder<K>> testTypeParam(builder: Builder<K>) {
|
||||
builder
|
||||
.test()
|
||||
.foo()
|
||||
|
||||
builder
|
||||
.test()
|
||||
.bar { Out() }
|
||||
}
|
||||
|
||||
fun testStarJava(builder: JavaBuilder<*>) {
|
||||
|
||||
-25
@@ -1,25 +0,0 @@
|
||||
package
|
||||
|
||||
public fun testStar(/*0*/ builder: Builder<*>): kotlin.Unit
|
||||
public fun testStarJava(/*0*/ builder: JavaBuilder<*>): kotlin.Unit
|
||||
public fun </*0*/ K : Builder<K>> testTypeParam(/*0*/ builder: Builder<K>): kotlin.Unit
|
||||
public fun </*0*/ K : JavaBuilder<K>> testTypeParamJava(/*0*/ builder: JavaBuilder<K>): kotlin.Unit
|
||||
|
||||
public final class Builder</*0*/ B : Builder<B>> {
|
||||
public constructor Builder</*0*/ B : Builder<B>>()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public final fun foo(): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public final fun </*0*/ T : B> test(): T
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public open class JavaBuilder</*0*/ B : JavaBuilder<B!>!> {
|
||||
public constructor JavaBuilder</*0*/ B : JavaBuilder<B!>!>()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public/*package*/ open fun foo(): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public/*package*/ open fun </*0*/ T : B!> test(): T!
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
+4
-4
@@ -13,11 +13,11 @@ interface BodySpec<B, S : BodySpec<B, S>> {
|
||||
}
|
||||
|
||||
fun test(b: BodySpec<String, *>) {
|
||||
val x = b.<!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>isEqualTo<!>("")
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("ERROR CLASS: Cannot infer argument for type parameter T")!>x<!>
|
||||
val x = b.isEqualTo("")
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("BodySpec<kotlin.String, *>")!>x<!>
|
||||
}
|
||||
|
||||
fun testJava(b: JavaBodySpec<String, *>) {
|
||||
val x = b.<!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>isEqualTo<!>("")
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("ERROR CLASS: Cannot infer argument for type parameter T")!>x<!>
|
||||
val x = b.isEqualTo("")
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("JavaBodySpec<kotlin.String..kotlin.String?!, *>..JavaBodySpec<kotlin.String..kotlin.String?!, *>?!")!>x<!>
|
||||
}
|
||||
|
||||
Generated
+6
@@ -17875,6 +17875,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/capturedFlexibleIntersectionTypesWithDifferentConstructors.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("capturedInTypeInference.kt")
|
||||
public void testCapturedInTypeInference() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/capturedInTypeInference.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("capturedType.kt")
|
||||
public void testCapturedType() throws Exception {
|
||||
|
||||
Reference in New Issue
Block a user