[FE 1.0] Build captured type's supertypes in an alternative way: use own projection type as a first supertype, then supertypes from the corresponding type parameter's upper bounds

The original case provoked forking a constraint system which isn't supported in K1 (K2 only). If the captured type is recursive, then type parameter's upper bounds may break subtyping due to substitution the current captured type again, into a recursive type parameter.

Note that we already have special logic for recursive captured types. See `isTypeVariableAgainstStarProjectionForSelfType`.

^KT-52782 Fixed
This commit is contained in:
Victor Petukhov
2022-06-17 15:01:53 +02:00
parent 37ccd85e59
commit eb19d39cbf
9 changed files with 83 additions and 14 deletions
@@ -14659,6 +14659,12 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag
runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/kt49101.kt");
}
@Test
@TestMetadata("kt52782.kt")
public void testKt52782() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/kt52782.kt");
}
@Test
@TestMetadata("memberScopeOfCaptured.kt")
public void testMemberScopeOfCaptured() throws Exception {
@@ -14659,6 +14659,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/kt49101.kt");
}
@Test
@TestMetadata("kt52782.kt")
public void testKt52782() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/kt52782.kt");
}
@Test
@TestMetadata("memberScopeOfCaptured.kt")
public void testMemberScopeOfCaptured() throws Exception {
@@ -14659,6 +14659,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/kt49101.kt");
}
@Test
@TestMetadata("kt52782.kt")
public void testKt52782() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/kt52782.kt");
}
@Test
@TestMetadata("memberScopeOfCaptured.kt")
public void testMemberScopeOfCaptured() throws Exception {
@@ -106,8 +106,8 @@ interface NewTypeSubstitutor : TypeSubstitutorMarker {
val innerType = capturedType.lowerType ?: capturedType.constructor.projection.type.unwrap()
val substitutedInnerType = substitute(innerType, keepAnnotation, runCapturedChecks = false)
val substitutedSuperTypes =
capturedType.constructor.supertypes.map { substitute(it, keepAnnotation, runCapturedChecks = false) ?: it }
val (projectionSupertype, boundSupertypes) =
capturedType.constructor.transformSupertypes { substitute(it, keepAnnotation, runCapturedChecks = false) ?: it }
if (substitutedInnerType != null) {
return if (substitutedInnerType.isCaptured()) substitutedInnerType else {
@@ -116,7 +116,7 @@ interface NewTypeSubstitutor : TypeSubstitutorMarker {
NewCapturedTypeConstructor(
TypeProjectionImpl(typeConstructor.projection.projectionKind, substitutedInnerType),
typeParameter = typeConstructor.typeParameter
).also { it.initializeSupertypes(substitutedSuperTypes) },
).also { it.initializeSupertypes(projectionSupertype, boundSupertypes) },
lowerType = if (capturedType.lowerType != null) substitutedInnerType else null
)
}
@@ -0,0 +1,13 @@
// FIR_IDENTICAL
// FILE: Foo.java
public abstract class Foo<K extends Bar<? extends Foo<K>>> {
abstract String getTest();
}
// FILE: Bar.java
public abstract class Bar<T extends Foo<? extends Bar<T>>> {}
// FILE: main.kt
fun box(foo: Foo<*>) {
foo.test // unresolved in 1.7.0, OK before
}
@@ -0,0 +1,18 @@
package
public fun box(/*0*/ foo: Foo<*>): kotlin.Unit
public abstract class Bar</*0*/ T : Foo<out Bar<T!>!>!> {
public constructor Bar</*0*/ T : Foo<out Bar<T!>!>!>()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public abstract class Foo</*0*/ K : Bar<out Foo<K!>!>!> {
public constructor Foo</*0*/ K : Bar<out Foo<K!>!>!>()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public/*package*/ abstract fun getTest(): kotlin.String!
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
+1 -1
View File
@@ -30,7 +30,7 @@ fun String.asFsdAddress(): String {
fun box(): String {
val state = Test().state
if (state is GoBuildingRunningState<*>) {
state.<!UNRESOLVED_REFERENCE_WRONG_RECEIVER!>buildingWorkingDirectory<!>.<!DEBUG_INFO_MISSING_UNRESOLVED!>asFsdAddress<!>()
<!DEBUG_INFO_SMARTCAST!>state<!>.buildingWorkingDirectory.asFsdAddress()
}
return "OK"
}
@@ -14665,6 +14665,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/kt49101.kt");
}
@Test
@TestMetadata("kt52782.kt")
public void testKt52782() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/capturedTypes/kt52782.kt");
}
@Test
@TestMetadata("memberScopeOfCaptured.kt")
public void testMemberScopeOfCaptured() throws Exception {
@@ -173,16 +173,16 @@ private fun captureArguments(type: UnwrappedType, status: CaptureStatus): List<T
val newProjection = capturedArguments[index]
if (oldProjection.projectionKind == Variance.INVARIANT) continue
val capturedTypeSupertypes = type.constructor.parameters[index].upperBounds.mapTo(mutableListOf()) {
val boundSupertypes = type.constructor.parameters[index].upperBounds.mapTo(mutableListOf()) {
KotlinTypePreparator.Default.prepareType(substitutor.safeSubstitute(it, Variance.INVARIANT).unwrap())
}
if (!oldProjection.isStarProjection && oldProjection.projectionKind == Variance.OUT_VARIANCE) {
capturedTypeSupertypes += KotlinTypePreparator.Default.prepareType(oldProjection.type.unwrap())
}
val projectionSupertype = if (!oldProjection.isStarProjection && oldProjection.projectionKind == Variance.OUT_VARIANCE) {
KotlinTypePreparator.Default.prepareType(oldProjection.type.unwrap())
} else null
val capturedType = newProjection.type as NewCapturedType
capturedType.constructor.initializeSupertypes(capturedTypeSupertypes)
capturedType.constructor.initializeSupertypes(projectionSupertype, boundSupertypes)
}
return capturedArguments
@@ -243,18 +243,32 @@ class NewCapturedTypeConstructor(
original: NewCapturedTypeConstructor? = null
) : this(projection, { supertypes }, original)
private val _supertypes by lazy(LazyThreadSafetyMode.PUBLICATION) {
// supertypes from the corresponding type parameter upper bounds
private val boundSupertypes by lazy(LazyThreadSafetyMode.PUBLICATION) {
supertypesComputation?.invoke()
}
fun initializeSupertypes(supertypes: List<UnwrappedType>) {
private var projectionSupertype: UnwrappedType? = null
fun initializeSupertypes(projectionSupertype: UnwrappedType?, boundSupertypes: List<UnwrappedType>) {
assert(this.supertypesComputation == null) {
"Already initialized! oldValue = ${this.supertypesComputation}, newValue = $supertypes"
"Already initialized! oldValue = ${this.supertypesComputation}, newValue = $boundSupertypes"
}
this.supertypesComputation = { supertypes }
this.projectionSupertype = projectionSupertype
this.supertypesComputation = { boundSupertypes }
}
override fun getSupertypes(): List<UnwrappedType> = buildList {
projectionSupertype?.let { add(it) }
boundSupertypes?.let { addAll(it) }
}
fun transformSupertypes(transformation: (UnwrappedType) -> UnwrappedType): Pair<UnwrappedType?, List<UnwrappedType>> {
val projectionSupertypeTransformed = projectionSupertype?.let(transformation)
val boundSupertypesTransformed = boundSupertypes?.map(transformation) ?: emptyList()
return projectionSupertypeTransformed to boundSupertypesTransformed
}
override fun getSupertypes() = _supertypes ?: emptyList()
override fun getParameters(): List<TypeParameterDescriptor> = emptyList()
override fun isFinal() = false