FIR: Refine inference constraints when type variable in flexible position
That issue might be fixed via changing TypeVariableMarker.shouldBeFlexible at ConeConstraintSystemUtilContext but this and some other tricks have been added because of incorrect handling of constraints where type variable has a flexible bound ^KT-51168 Fixed
This commit is contained in:
+6
-4
@@ -103,10 +103,12 @@ abstract class AbstractConeSubstitutor(protected val typeContext: ConeTypeContex
|
||||
}
|
||||
|
||||
private fun ConeDefinitelyNotNullType.substituteOriginal(): ConeKotlinType? {
|
||||
val substituted = substituteOrNull(original)
|
||||
?.withNullability(ConeNullability.NOT_NULL, typeContext)
|
||||
?.withAttributes(original.attributes)
|
||||
?: return null
|
||||
val substitutedOriginal = substituteOrNull(original) ?: return null
|
||||
val substituted = substitutedOriginal.withNullability(
|
||||
ConeNullability.NOT_NULL,
|
||||
typeContext,
|
||||
substitutedOriginal.attributes.add(original.attributes)
|
||||
)
|
||||
return ConeDefinitelyNotNullType.create(substituted, typeContext) ?: substituted
|
||||
}
|
||||
|
||||
|
||||
@@ -562,8 +562,7 @@ interface ConeInferenceContext : TypeSystemInferenceExtensionContext, ConeTypeCo
|
||||
return intersectionType.withAlternative(secondCandidate)
|
||||
}
|
||||
|
||||
override fun SimpleTypeMarker.createConstraintPartForLowerBoundAndFlexibleTypeVariable(): KotlinTypeMarker =
|
||||
createFlexibleType(this.makeSimpleTypeDefinitelyNotNullOrNotNull(), this.withNullability(true))
|
||||
override fun useRefinedBoundsForTypeVariableInFlexiblePosition(): Boolean = true
|
||||
|
||||
override fun createSubstitutorForSuperTypes(baseType: KotlinTypeMarker): TypeSubstitutorMarker? =
|
||||
if (baseType is ConeLookupTagBasedType) createSubstitutionForSupertype(baseType, session) else null
|
||||
|
||||
@@ -13,7 +13,10 @@ import org.jetbrains.kotlin.descriptors.ValueClassKind
|
||||
import org.jetbrains.kotlin.descriptors.valueClassLoweringKind
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.*
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.expandedConeType
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isInner
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.modality
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.superConeTypes
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
import org.jetbrains.kotlin.fir.resolve.directExpansionType
|
||||
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
||||
@@ -289,7 +292,7 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext, Ty
|
||||
else -> listOf(session.builtinTypes.anyType.type)
|
||||
}
|
||||
}
|
||||
is ConeCapturedTypeConstructor -> supertypes!!
|
||||
is ConeCapturedTypeConstructor -> supertypes.orEmpty()
|
||||
is ConeIntersectionType -> intersectedTypes
|
||||
is ConeIntegerLiteralType -> supertypes
|
||||
else -> unknownConstructorError()
|
||||
@@ -475,13 +478,13 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext, Ty
|
||||
|
||||
return when (this) {
|
||||
is ConeFlexibleType -> this.upperBound.isNullableType()
|
||||
is ConeTypeParameterType -> lookupTag.symbol.allBoundsAreNullable()
|
||||
is ConeTypeParameterType -> lookupTag.symbol.allBoundsAreNullableOrUnresolved()
|
||||
is ConeTypeVariableType -> {
|
||||
val symbol = lookupTag.toSymbol(session) ?: return false
|
||||
when (symbol) {
|
||||
is FirClassSymbol -> false
|
||||
is FirTypeAliasSymbol -> symbol.fir.expandedConeType?.isNullableType() ?: false
|
||||
is FirTypeParameterSymbol -> symbol.allBoundsAreNullable()
|
||||
is FirTypeParameterSymbol -> symbol.allBoundsAreNullableOrUnresolved()
|
||||
}
|
||||
}
|
||||
is ConeIntersectionType -> intersectedTypes.all { it.isNullableType() }
|
||||
@@ -490,8 +493,13 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext, Ty
|
||||
}
|
||||
}
|
||||
|
||||
private fun FirTypeParameterSymbol.allBoundsAreNullable(): Boolean {
|
||||
return resolvedBounds.all { it.coneType.isNullableType() }
|
||||
private fun FirTypeParameterSymbol.allBoundsAreNullableOrUnresolved(): Boolean {
|
||||
for (bound in fir.bounds) {
|
||||
if (bound !is FirResolvedTypeRef) return true
|
||||
if (!bound.type.isNullableType()) return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
private fun TypeConstructorMarker.toFirRegularClass(): FirRegularClass? {
|
||||
|
||||
@@ -60,7 +60,7 @@ fun TypeCheckerProviderContext.equalTypes(a: ConeKotlinType, b: ConeKotlinType):
|
||||
|
||||
private fun ConeTypeContext.makesSenseToBeDefinitelyNotNull(originalType: ConeKotlinType): Boolean {
|
||||
return when (val type = originalType.lowerBoundIfFlexible()) {
|
||||
is ConeTypeParameterType -> type.isNullableType()
|
||||
is ConeTypeParameterType -> !type.lookupTag.symbol.isInitializedFir || type.isNullableType()
|
||||
// Actually, this branch should work for type parameters as well, but it breaks some cases. See KT-40114.
|
||||
// Basically, if we have `T : X..X?`, then `T <: Any` but we still have `T` != `T & Any`.
|
||||
is ConeTypeVariableType, is ConeCapturedType -> {
|
||||
@@ -75,12 +75,13 @@ private fun ConeTypeContext.makesSenseToBeDefinitelyNotNull(originalType: ConeKo
|
||||
|
||||
fun ConeDefinitelyNotNullType.Companion.create(
|
||||
original: ConeKotlinType,
|
||||
typeContext: ConeTypeContext
|
||||
typeContext: ConeTypeContext,
|
||||
forceWithoutCheck: Boolean = false,
|
||||
): ConeDefinitelyNotNullType? {
|
||||
return when (original) {
|
||||
is ConeDefinitelyNotNullType -> original
|
||||
is ConeFlexibleType -> create(original.lowerBound, typeContext)
|
||||
is ConeSimpleKotlinType -> runIf(typeContext.makesSenseToBeDefinitelyNotNull(original)) {
|
||||
is ConeSimpleKotlinType -> runIf(forceWithoutCheck || typeContext.makesSenseToBeDefinitelyNotNull(original)) {
|
||||
ConeDefinitelyNotNullType(original.coneLowerBoundIfFlexible())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user