[NI] Introduce DefinitelyNotNullType as type for T!! or {T & Any}
This commit is contained in:
+8
-4
@@ -74,16 +74,17 @@ interface NewTypeSubstitutor {
|
||||
if (typeConstructor is NewCapturedTypeConstructor) {
|
||||
if (!runCapturedChecks) return null
|
||||
|
||||
assert(type is NewCapturedType) { // KT-16147
|
||||
assert(type is NewCapturedType || (type is DefinitelyNotNullType && type.original is NewCapturedType)) { // KT-16147
|
||||
"Type is inconsistent -- somewhere we create type with typeConstructor = $typeConstructor " +
|
||||
"and class: ${type::class.java.canonicalName}. type.toString() = $type"
|
||||
}
|
||||
val lower = (type as NewCapturedType).lowerType?.let { substitute(it, keepAnnotation, runCapturedChecks = false) }
|
||||
val capturedType = if (type is DefinitelyNotNullType) type.original as NewCapturedType else type as NewCapturedType
|
||||
val lower = capturedType.lowerType?.let { substitute(it, keepAnnotation, runCapturedChecks = false) }
|
||||
if (lower != null) throw IllegalStateException("Illegal type substitutor: $this, " +
|
||||
"because for captured type '$type' lower type approximation should be null, but it is: '$lower'," +
|
||||
"original lower type: '${type.lowerType}")
|
||||
"original lower type: '${capturedType.lowerType}")
|
||||
|
||||
type.constructor.supertypes.forEach { supertype ->
|
||||
typeConstructor.supertypes.forEach { supertype ->
|
||||
substitute(supertype, keepAnnotation, runCapturedChecks = false)?.let {
|
||||
throw IllegalStateException("Illegal type substitutor: $this, " +
|
||||
"because for captured type '$type' supertype approximation should be null, but it is: '$supertype'," +
|
||||
@@ -111,6 +112,9 @@ interface NewTypeSubstitutor {
|
||||
if (type.isMarkedNullable) {
|
||||
replacement = replacement.makeNullableAsSpecified(true)
|
||||
}
|
||||
if (type.isDefinitelyNotNullType) {
|
||||
replacement = replacement.makeDefinitelyNotNullOrNotNull()
|
||||
}
|
||||
|
||||
return replacement
|
||||
}
|
||||
|
||||
+6
-21
@@ -139,17 +139,9 @@ abstract class TypeCheckerContextForConstraintSystem : TypeCheckerContext(errorT
|
||||
}
|
||||
|
||||
// Foo <: T! -- (Foo & Any .. Foo) <: T
|
||||
// T <: T! -- (T..T?) <: T
|
||||
// we can't use constraint (T & Any .. T) in the latter, because non-platform type with type variables is incorrect
|
||||
private fun addLowerConstraintWithSimpleSubtype(typeVariable: FlexibleType, subType: SimpleType) {
|
||||
assertFlexibleTypeVariable(typeVariable)
|
||||
|
||||
val constraintType = if (isMyTypeVariable(subType))
|
||||
KotlinTypeFactory.flexibleType(subType.makeNullableAsSpecified(false), subType.makeNullableAsSpecified(true))
|
||||
else
|
||||
KotlinTypeFactory.flexibleType(subType.definitelyNotNull(), subType)
|
||||
|
||||
addLowerConstraint(typeVariable.constructor, constraintType)
|
||||
addLowerConstraint(typeVariable.constructor, KotlinTypeFactory.flexibleType(subType.makeSimpleTypeDefinitelyNotNullOrNotNull(), subType))
|
||||
}
|
||||
|
||||
// (Foo..Bar) <: T! -- (Foo & Any .. Bar) <: T
|
||||
@@ -159,28 +151,18 @@ abstract class TypeCheckerContextForConstraintSystem : TypeCheckerContext(errorT
|
||||
val lowerBound = subType.lowerBound
|
||||
val upperBound = subType.upperBound
|
||||
|
||||
if (isMyTypeVariable(lowerBound) || isMyTypeVariable(upperBound)) {
|
||||
assertFlexibleTypeVariable(subType)
|
||||
// This means that we are trying to add constraint like T! <: A!
|
||||
addLowerConstraint(typeVariable.constructor, subType)
|
||||
return
|
||||
}
|
||||
|
||||
addLowerConstraint(typeVariable.constructor, KotlinTypeFactory.flexibleType(lowerBound.definitelyNotNull(), upperBound))
|
||||
addLowerConstraint(typeVariable.constructor, KotlinTypeFactory.flexibleType(lowerBound.makeSimpleTypeDefinitelyNotNullOrNotNull(), upperBound))
|
||||
}
|
||||
|
||||
// Foo <: T or
|
||||
// Foo <: T? -- Foo & Any <: T
|
||||
private fun addLowerConstraintForSimpleType(typeVariable: SimpleType, subType: UnwrappedType) {
|
||||
if (typeVariable.isMarkedNullable)
|
||||
addLowerConstraint(typeVariable.constructor, subType.definitelyNotNull())
|
||||
addLowerConstraint(typeVariable.constructor, subType.makeDefinitelyNotNullOrNotNull())
|
||||
else
|
||||
addLowerConstraint(typeVariable.constructor, subType)
|
||||
}
|
||||
|
||||
private fun UnwrappedType.definitelyNotNull(): UnwrappedType = intersectTypes(listOf(this, this.builtIns.anyType))
|
||||
private fun SimpleType.definitelyNotNull(): SimpleType = intersectTypes(listOf(this, this.builtIns.anyType))
|
||||
|
||||
private fun assertFlexibleTypeVariable(typeVariable: FlexibleType) {
|
||||
assert(typeVariable.lowerBound.constructor == typeVariable.upperBound.constructor) {
|
||||
"Flexible type variable ($typeVariable) should have bounds with the same type constructor, i.e. (T..T?)"
|
||||
@@ -196,6 +178,9 @@ abstract class TypeCheckerContextForConstraintSystem : TypeCheckerContext(errorT
|
||||
@Suppress("NAME_SHADOWING")
|
||||
val typeVariable = typeVariable.lowerIfFlexible()
|
||||
|
||||
@Suppress("NAME_SHADOWING")
|
||||
val superType = if (typeVariable is DefinitelyNotNullType) superType.makeNullableAsSpecified(true) else superType
|
||||
|
||||
addUpperConstraint(typeVariable.constructor, superType)
|
||||
|
||||
if (typeVariable.isMarkedNullable) {
|
||||
|
||||
@@ -39,6 +39,7 @@ open class TypeApproximatorConfiguration {
|
||||
open val dynamic get() = false // DynamicType
|
||||
open val rawType get() = false // RawTypeImpl
|
||||
open val errorType get() = false
|
||||
open val definitelyNotNullType get() = true
|
||||
open val intersection: IntersectionStrategy = TO_COMMON_SUPERTYPE
|
||||
|
||||
open val typeVariable: (TypeVariableTypeConstructor) -> Boolean = { false }
|
||||
@@ -61,6 +62,7 @@ open class TypeApproximatorConfiguration {
|
||||
object PublicDeclaration : AllFlexibleSameValue() {
|
||||
override val allFlexible get() = true
|
||||
override val errorType get() = true
|
||||
override val definitelyNotNullType get() = false
|
||||
}
|
||||
|
||||
abstract class AbstractCapturedTypesApproximation(val approximatedCapturedStatus: CaptureStatus): TypeApproximatorConfiguration.AllFlexibleSameValue() {
|
||||
@@ -262,6 +264,10 @@ class TypeApproximator {
|
||||
return approximateParametrizedType(type, conf, toSuper, depth + 1)
|
||||
}
|
||||
|
||||
if (type is DefinitelyNotNullType) {
|
||||
return approximateDefinitelyNotNullType(type, conf, toSuper, depth)
|
||||
}
|
||||
|
||||
val typeConstructor = type.constructor
|
||||
|
||||
if (typeConstructor is NewCapturedTypeConstructor) {
|
||||
@@ -283,6 +289,24 @@ class TypeApproximator {
|
||||
return null // simple classifier type
|
||||
}
|
||||
|
||||
private fun approximateDefinitelyNotNullType(
|
||||
type: DefinitelyNotNullType,
|
||||
conf: TypeApproximatorConfiguration,
|
||||
toSuper: Boolean,
|
||||
depth: Int
|
||||
): UnwrappedType? {
|
||||
val approximatedOriginalType = approximateTo(type.original, conf, toSuper, depth)
|
||||
return if (conf.definitelyNotNullType) {
|
||||
approximatedOriginalType?.makeDefinitelyNotNullOrNotNull()
|
||||
}
|
||||
else {
|
||||
if (toSuper)
|
||||
(approximatedOriginalType ?: type.original).makeNullableAsSpecified(false)
|
||||
else
|
||||
type.defaultResult(toSuper)
|
||||
}
|
||||
}
|
||||
|
||||
private fun isApproximateDirectionToSuper(effectiveVariance: Variance, toSuper: Boolean) =
|
||||
when (effectiveVariance) {
|
||||
Variance.OUT_VARIANCE -> toSuper
|
||||
@@ -364,7 +388,7 @@ class TypeApproximator {
|
||||
* Note that for case Inv<C> we will chose Inv<in Int>, because it is more informative then Inv<out Any?>.
|
||||
* May be we should do the same for deeper types, but not now.
|
||||
*/
|
||||
if (argumentType is NewCapturedType) {
|
||||
if (argumentType.constructor is NewCapturedTypeConstructor) {
|
||||
val subType = approximateToSubType(argumentType, conf, depth) ?: continue@loop
|
||||
if (!subType.isTrivialSub()) {
|
||||
newArguments[index] = TypeProjectionImpl(Variance.IN_VARIANCE, subType)
|
||||
|
||||
Reference in New Issue
Block a user