Support definitely not null stub types and proper subtyping on them

This commit is contained in:
Victor Petukhov
2021-05-21 14:42:29 +03:00
parent 0f317b01b4
commit 0c427555cf
10 changed files with 86 additions and 49 deletions
@@ -461,6 +461,17 @@ object AbstractTypeChecker {
return null
}
private fun TypeSystemContext.isStubTypeSubtypeOfAnother(a: SimpleTypeMarker, b: SimpleTypeMarker): Boolean {
val originalA = a.asDefinitelyNotNullType()?.original() ?: a
val originalB = b.asDefinitelyNotNullType()?.original() ?: b
if (originalA.typeConstructor() !== originalB.typeConstructor()) return false
if (!a.isDefinitelyNotNullType() && b.isDefinitelyNotNullType()) return false
if (a.isMarkedNullable() && !b.isMarkedNullable()) return false
return true // A!! == B!!, A? == B? or A == B
}
private fun checkSubtypeForSpecialCases(
context: AbstractTypeCheckerContext,
subType: SimpleTypeMarker,
@@ -478,10 +489,10 @@ object AbstractTypeChecker {
)
}
if (subType.isStubType() && superType.isStubType())
return subType.typeConstructor() === superType.typeConstructor()
if (subType.isStubTypeForBuilderInference() && superType.isStubTypeForBuilderInference())
return isStubTypeSubtypeOfAnother(subType, superType)
if (subType.isStubType() || superType.isStubType() || subType.isStubTypeForVariableInSubtyping() || superType.isStubTypeForVariableInSubtyping())
if (subType.isStubType() || superType.isStubType())
return context.isStubTypeEqualsToAnything
// superType might be a definitely notNull type (see KT-42824)
@@ -746,7 +757,7 @@ object AbstractNullabilityChecker {
if (type.isNothing()) return true
if (type.isMarkedNullable()) return false
if (context.isStubTypeEqualsToAnything && (type.isStubTypeForVariableInSubtyping() || type.isStubType())) return true
if (context.isStubTypeEqualsToAnything && type.isStubType()) return true
return areEqualTypeConstructors(type.typeConstructor(), end)
}
@@ -300,6 +300,7 @@ interface TypeSystemContext : TypeSystemOptimizationContext {
fun SimpleTypeMarker.isStubType(): Boolean
fun SimpleTypeMarker.isStubTypeForVariableInSubtyping(): Boolean
fun SimpleTypeMarker.isStubTypeForBuilderInference(): Boolean
fun KotlinTypeMarker.asTypeArgument(): TypeArgumentMarker
@@ -236,6 +236,8 @@ internal class DescriptorRendererImpl(
private fun StringBuilder.renderDefaultType(type: KotlinType) {
this.renderAnnotations(type)
val originalTypeOfDefNotNullType = (type as? DefinitelyNotNullType)?.original
when {
type.isError -> {
if (type is UnresolvedType && presentableUnresolvedTypes) {
@@ -249,7 +251,10 @@ internal class DescriptorRendererImpl(
}
append(renderTypeArguments(type.arguments))
}
type is StubTypeForBuilderInference -> append(type.originalTypeVariable.toString())
type is StubTypeForBuilderInference ->
append(type.originalTypeVariable.toString())
originalTypeOfDefNotNullType is StubTypeForBuilderInference ->
append(originalTypeOfDefNotNullType.originalTypeVariable.toString())
else -> renderTypeConstructorAndArguments(type)
}
@@ -125,6 +125,8 @@ class DefinitelyNotNullType private constructor(
): Boolean {
if (!type.canHaveUndefinedNullability()) return false
if (type is StubTypeForBuilderInference) return TypeUtils.isNullableType(type)
// 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)
@@ -142,9 +144,10 @@ class DefinitelyNotNullType private constructor(
}
private fun UnwrappedType.canHaveUndefinedNullability(): Boolean =
constructor is NewTypeVariableConstructor ||
constructor.declarationDescriptor is TypeParameterDescriptor ||
this is NewCapturedType
constructor is NewTypeVariableConstructor
|| constructor.declarationDescriptor is TypeParameterDescriptor
|| this is NewCapturedType
|| this is StubTypeForBuilderInference
}
@@ -159,13 +162,13 @@ class DefinitelyNotNullType private constructor(
delegate.constructor.declarationDescriptor is TypeParameterDescriptor
override fun substitutionResult(replacement: KotlinType): KotlinType =
replacement.unwrap().makeDefinitelyNotNullOrNotNull(useCorrectedNullabilityForTypeParameters)
replacement.unwrap().makeDefinitelyNotNullOrNotNull(useCorrectedNullabilityForTypeParameters)
override fun replaceAnnotations(newAnnotations: Annotations): DefinitelyNotNullType =
DefinitelyNotNullType(delegate.replaceAnnotations(newAnnotations), useCorrectedNullabilityForTypeParameters)
DefinitelyNotNullType(delegate.replaceAnnotations(newAnnotations), useCorrectedNullabilityForTypeParameters)
override fun makeNullableAsSpecified(newNullability: Boolean): SimpleType =
if (newNullability) delegate.makeNullableAsSpecified(newNullability) else this
if (newNullability) delegate.makeNullableAsSpecified(newNullability) else this
override fun toString(): String = "$delegate!!"
@@ -81,12 +81,20 @@ interface ClassicTypeSystemContext : TypeSystemInferenceExtensionContext, TypeSy
override fun SimpleTypeMarker.isStubType(): Boolean {
require(this is SimpleType, this::errorMessage)
return this is StubTypeForBuilderInference || this is StubTypeForProvideDelegateReceiver
return this is AbstractStubType || isDefNotNullStubType<AbstractStubType>()
}
private inline fun <reified S : AbstractStubType> SimpleTypeMarker.isDefNotNullStubType() =
this is DefinitelyNotNullType && this.original is S
override fun SimpleTypeMarker.isStubTypeForVariableInSubtyping(): Boolean {
require(this is SimpleType, this::errorMessage)
return this is StubTypeForTypeVariablesInSubtyping
return this is StubTypeForTypeVariablesInSubtyping || isDefNotNullStubType<StubTypeForTypeVariablesInSubtyping>()
}
override fun SimpleTypeMarker.isStubTypeForBuilderInference(): Boolean {
require(this is SimpleType, this::errorMessage)
return this is StubTypeForBuilderInference || isDefNotNullStubType<StubTypeForBuilderInference>()
}
override fun CapturedTypeMarker.lowerType(): KotlinTypeMarker? {
@@ -170,6 +170,8 @@ object TypeIntersector {
protected val UnwrappedType.resultNullability: ResultNullability
get() = when {
isMarkedNullable -> ACCEPT_NULL
this is DefinitelyNotNullType && this.original is StubTypeForBuilderInference -> NOT_NULL
this is StubTypeForBuilderInference -> UNKNOWN
NullabilityChecker.isSubtypeOfAny(this) -> NOT_NULL
else -> UNKNOWN
}