[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:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user