FIR: enable useCorrectedNullabilityForFlexibleTypeParameters

It's necessary for correct substitution of `T & Any` with `T = V..V?`.
This commit is contained in:
pyos
2021-09-02 10:57:50 +02:00
committed by teamcityserver
parent bbc476f44e
commit a475453a01
4 changed files with 20 additions and 72 deletions
@@ -143,8 +143,7 @@ private fun ConeKotlinType.enhanceInflexibleType(
val mergedAttributes = if (shouldAddAttribute) attributes + CompilerConeAttributes.EnhancedNullability else attributes
val enhancedType = enhancedTag.constructType(mergedArguments, enhancedNullability, mergedAttributes)
return if (effectiveQualifiers.isNotNullTypeParameter)
ConeDefinitelyNotNullType.create(enhancedType, session.typeContext, useCorrectedNullabilityForFlexibleTypeParameters = true)
?: enhancedType
ConeDefinitelyNotNullType.create(enhancedType, session.typeContext) ?: enhancedType
else
enhancedType
}
@@ -21,9 +21,7 @@ import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
import org.jetbrains.kotlin.resolve.calls.NewCommonSuperTypeCalculator
import org.jetbrains.kotlin.types.AbstractStrictEqualityTypeChecker
import org.jetbrains.kotlin.types.AbstractTypeChecker
import org.jetbrains.kotlin.types.TypeApproximatorConfiguration
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.model.*
fun ConeInferenceContext.commonSuperTypeOrNull(types: List<ConeKotlinType>): ConeKotlinType? {
@@ -47,20 +45,27 @@ fun ConeInferenceContext.intersectTypesOrNull(types: List<ConeKotlinType>): Cone
fun TypeCheckerProviderContext.equalTypes(a: ConeKotlinType, b: ConeKotlinType): Boolean =
AbstractTypeChecker.equalTypes(this, a, b)
private fun ConeTypeContext.makesSenseToBeDefinitelyNotNull(type: ConeKotlinType): Boolean = when (type) {
is ConeTypeParameterType -> 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 ->
!AbstractNullabilityChecker.isSubtypeOfAny(
newTypeCheckerState(errorTypesEqualToAnything = false, stubTypesEqualToAnything = false), type
)
// For all other types `T & Any` is the same as `T` without a question mark.
// TODO: not true for flexible types.
else -> false
}
// TODO: leave only one of `create` and `makeConeTypeDefinitelyNotNullOrNotNull`
fun ConeDefinitelyNotNullType.Companion.create(
original: ConeKotlinType,
typeContext: ConeTypeContext,
useCorrectedNullabilityForFlexibleTypeParameters: Boolean = false,
typeContext: ConeTypeContext
): ConeDefinitelyNotNullType? {
return when {
original is ConeDefinitelyNotNullType -> original
typeContext
.newTypeCheckerState(errorTypesEqualToAnything = false, stubTypesEqualToAnything = false)
.makesSenseToBeDefinitelyNotNull(original, useCorrectedNullabilityForFlexibleTypeParameters) ->
ConeDefinitelyNotNullType(
original.lowerBoundIfFlexible()
)
typeContext.makesSenseToBeDefinitelyNotNull(original) -> ConeDefinitelyNotNullType(original)
else -> null
}
}
@@ -81,10 +86,7 @@ fun <T : ConeKotlinType> T.withArguments(arguments: Array<out ConeTypeProjection
return when (this) {
is ConeClassErrorType -> this
is ConeClassLikeTypeImpl -> ConeClassLikeTypeImpl(lookupTag, arguments, nullability.isNullable) as T
is ConeDefinitelyNotNullType -> ConeDefinitelyNotNullType.create(
original.withArguments(arguments, typeSystemContext),
typeSystemContext
)!! as T
is ConeDefinitelyNotNullType -> ConeDefinitelyNotNullType(original.withArguments(arguments, typeSystemContext)) as T
else -> error("Not supported: $this: ${this.render()}")
}
}
@@ -101,10 +103,7 @@ fun <T : ConeKotlinType> T.withAttributes(attributes: ConeAttributes, typeSystem
return when (this) {
is ConeClassErrorType -> this
is ConeClassLikeTypeImpl -> ConeClassLikeTypeImpl(lookupTag, typeArguments, nullability.isNullable, attributes)
is ConeDefinitelyNotNullType -> ConeDefinitelyNotNullType.create(
original.withAttributes(attributes, typeSystemContext),
typeSystemContext
)!!
is ConeDefinitelyNotNullType -> ConeDefinitelyNotNullType(original.withAttributes(attributes, typeSystemContext))
is ConeTypeParameterTypeImpl -> ConeTypeParameterTypeImpl(lookupTag, nullability.isNullable, attributes)
is ConeFlexibleType -> ConeFlexibleType(
lowerBound.withAttributes(attributes, typeSystemContext),
@@ -14,8 +14,6 @@ import org.jetbrains.kotlin.fir.render
import org.jetbrains.kotlin.fir.types.impl.FirImplicitBuiltinTypeRef
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.StandardClassIds
import org.jetbrains.kotlin.types.AbstractNullabilityChecker
import org.jetbrains.kotlin.types.TypeCheckerState
import org.jetbrains.kotlin.types.ConstantValueKind
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.contract
@@ -151,41 +149,6 @@ fun FirTypeProjection.toConeTypeProjection(): ConeTypeProjection =
else -> error("!")
}
fun TypeCheckerState.makesSenseToBeDefinitelyNotNull(
type: ConeKotlinType,
useCorrectedNullabilityForFlexibleTypeParameters: Boolean
): Boolean {
if (!type.canHaveUndefinedNullability()) return false
// Replacing `useCorrectedNullabilityForFlexibleTypeParameters` with true for all call-sites seems to be correct
// But it seems that it should be a new feature: KT-28785 would be automatically fixed then
// (see the tests org.jetbrains.kotlin.spec.checkers.DiagnosticsTestSpecGenerated.NotLinked.Dfa.Pos.test12/13)
// So it should be a language feature, but it's hard correctly identify language version settings for all call sites
// Thus, we have non-trivial value at org.jetbrains.kotlin.load.java.typeEnhancement.JavaTypeEnhancement.notNullTypeParameter
// that run under related language-feature only
if (useCorrectedNullabilityForFlexibleTypeParameters && type is ConeTypeParameterType) {
// Effectively checks if the type is flexible or has nullable bound
return with(typeSystemContext) {
type.isNullableType()
}
}
// Actually, this code should work for type parameters as well, but it breaks some cases
// See KT-40114
return !AbstractNullabilityChecker.isSubtypeOfAny(this, type)
}
fun ConeKotlinType.canHaveUndefinedNullability(): Boolean {
return when (this) {
is ConeTypeVariableType,
is ConeCapturedType,
is ConeTypeParameterType
-> true
else -> false
}
}
private fun ConeTypeParameterType.hasNotNullUpperBound(): Boolean {
return lookupTag.typeParameterSymbol.fir.bounds.any {
val boundType = it.coneType
@@ -82,25 +82,12 @@ FILE fqName:<root> fileName:/AbstractMutableMap.kt
VALUE_PARAMETER name:p0 index:0 type:K of <root>.MyMap
VALUE_PARAMETER name:p1 index:1 type:@[EnhancedNullability] V of <root>.MyMap
VALUE_PARAMETER name:p2 index:2 type:@[EnhancedNullability] java.util.function.BiFunction<in @[EnhancedNullability] V of <root>.MyMap, in @[EnhancedNullability] V of <root>.MyMap, out V of <root>.MyMap?>
FUN FAKE_OVERRIDE name:merge visibility:public modality:OPEN <> ($this:kotlin.collections.MutableMap<K of kotlin.collections.MutableMap, V of kotlin.collections.MutableMap>, p0:@[FlexibleNullability] K of <root>.MyMap?, p1:V of <root>.MyMap, p2:@[EnhancedNullability] java.util.function.BiFunction<in V of <root>.MyMap, in V of <root>.MyMap, out V of <root>.MyMap?>) returnType:V of <root>.MyMap? [fake_override]
overridden:
public open fun merge (p0: @[FlexibleNullability] K of kotlin.collections.AbstractMutableMap?, p1: V of kotlin.collections.AbstractMutableMap, p2: @[EnhancedNullability] java.util.function.BiFunction<in V of kotlin.collections.AbstractMutableMap, in V of kotlin.collections.AbstractMutableMap, out V of kotlin.collections.AbstractMutableMap?>): V of kotlin.collections.AbstractMutableMap? [fake_override] declared in kotlin.collections.AbstractMutableMap
$this: VALUE_PARAMETER name:<this> type:kotlin.collections.MutableMap<K of kotlin.collections.MutableMap, V of kotlin.collections.MutableMap>
VALUE_PARAMETER name:p0 index:0 type:@[FlexibleNullability] K of <root>.MyMap?
VALUE_PARAMETER name:p1 index:1 type:V of <root>.MyMap
VALUE_PARAMETER name:p2 index:2 type:@[EnhancedNullability] java.util.function.BiFunction<in V of <root>.MyMap, in V of <root>.MyMap, out V of <root>.MyMap?>
FUN FAKE_OVERRIDE name:computeIfPresent visibility:public modality:OPEN <> ($this:kotlin.collections.MutableMap<K of kotlin.collections.MutableMap, V of kotlin.collections.MutableMap>, p0:K of <root>.MyMap, p1:@[EnhancedNullability] java.util.function.BiFunction<in K of <root>.MyMap, in @[EnhancedNullability] V of <root>.MyMap, out V of <root>.MyMap?>) returnType:V of <root>.MyMap? [fake_override]
overridden:
public open fun computeIfPresent (p0: K of kotlin.collections.AbstractMutableMap, p1: @[EnhancedNullability] java.util.function.BiFunction<in K of kotlin.collections.AbstractMutableMap, in @[EnhancedNullability] V of kotlin.collections.AbstractMutableMap, out V of kotlin.collections.AbstractMutableMap?>): V of kotlin.collections.AbstractMutableMap? [fake_override] declared in kotlin.collections.AbstractMutableMap
$this: VALUE_PARAMETER name:<this> type:kotlin.collections.MutableMap<K of kotlin.collections.MutableMap, V of kotlin.collections.MutableMap>
VALUE_PARAMETER name:p0 index:0 type:K of <root>.MyMap
VALUE_PARAMETER name:p1 index:1 type:@[EnhancedNullability] java.util.function.BiFunction<in K of <root>.MyMap, in @[EnhancedNullability] V of <root>.MyMap, out V of <root>.MyMap?>
FUN FAKE_OVERRIDE name:computeIfPresent visibility:public modality:OPEN <> ($this:kotlin.collections.MutableMap<K of kotlin.collections.MutableMap, V of kotlin.collections.MutableMap>, p0:@[FlexibleNullability] K of <root>.MyMap?, p1:@[EnhancedNullability] java.util.function.BiFunction<in @[FlexibleNullability] K of <root>.MyMap?, in V of <root>.MyMap, out V of <root>.MyMap?>) returnType:V of <root>.MyMap? [fake_override]
overridden:
public open fun computeIfPresent (p0: @[FlexibleNullability] K of kotlin.collections.AbstractMutableMap?, p1: @[EnhancedNullability] java.util.function.BiFunction<in @[FlexibleNullability] K of kotlin.collections.AbstractMutableMap?, in V of kotlin.collections.AbstractMutableMap, out V of kotlin.collections.AbstractMutableMap?>): V of kotlin.collections.AbstractMutableMap? [fake_override] declared in kotlin.collections.AbstractMutableMap
$this: VALUE_PARAMETER name:<this> type:kotlin.collections.MutableMap<K of kotlin.collections.MutableMap, V of kotlin.collections.MutableMap>
VALUE_PARAMETER name:p0 index:0 type:@[FlexibleNullability] K of <root>.MyMap?
VALUE_PARAMETER name:p1 index:1 type:@[EnhancedNullability] java.util.function.BiFunction<in @[FlexibleNullability] K of <root>.MyMap?, in V of <root>.MyMap, out V of <root>.MyMap?>
FUN FAKE_OVERRIDE name:putIfAbsent visibility:public modality:OPEN <> ($this:kotlin.collections.MutableMap<K of kotlin.collections.MutableMap, V of kotlin.collections.MutableMap>, p0:K of <root>.MyMap, p1:V of <root>.MyMap) returnType:V of <root>.MyMap? [fake_override]
overridden:
public open fun putIfAbsent (p0: K of kotlin.collections.AbstractMutableMap, p1: V of kotlin.collections.AbstractMutableMap): V of kotlin.collections.AbstractMutableMap? [fake_override] declared in kotlin.collections.AbstractMutableMap