Support definitely not null stub types and proper subtyping on them
This commit is contained in:
@@ -387,6 +387,10 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext, Ty
|
||||
return this is ConeStubType // TODO: distinguish stub types for builder inference and for subtyping
|
||||
}
|
||||
|
||||
override fun SimpleTypeMarker.isStubTypeForBuilderInference(): Boolean {
|
||||
return this is ConeStubType // TODO: distinguish stub types for builder inference and for subtyping
|
||||
}
|
||||
|
||||
override fun intersectTypes(types: List<SimpleTypeMarker>): SimpleTypeMarker {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return ConeTypeIntersector.intersectTypes(this as ConeInferenceContext, types as List<ConeKotlinType>) as SimpleTypeMarker
|
||||
|
||||
@@ -53,6 +53,8 @@ interface IrTypeSystemContext : TypeSystemContext, TypeSystemCommonSuperTypesCon
|
||||
|
||||
override fun SimpleTypeMarker.isStubTypeForVariableInSubtyping() = false
|
||||
|
||||
override fun SimpleTypeMarker.isStubTypeForBuilderInference() = false
|
||||
|
||||
override fun FlexibleTypeMarker.asDynamicType() = this as? IrDynamicType
|
||||
|
||||
override fun FlexibleTypeMarker.asRawType(): RawTypeMarker? = null
|
||||
|
||||
+15
-14
@@ -97,6 +97,10 @@ object NewCommonSuperTypeCalculator {
|
||||
commonSuperType
|
||||
}
|
||||
|
||||
private fun TypeSystemCommonSuperTypesContext.isCapturedStubTypeForVariableInSubtyping(type: SimpleTypeMarker) =
|
||||
type.asCapturedType()?.typeConstructor()?.projection()?.takeUnless { it.isStarProjection() }
|
||||
?.getType()?.asSimpleType()?.isStubTypeForVariableInSubtyping() == true
|
||||
|
||||
private fun TypeSystemCommonSuperTypesContext.refineNullabilityForUndefinedNullability(
|
||||
types: List<SimpleTypeMarker>,
|
||||
commonSuperType: SimpleTypeMarker
|
||||
@@ -164,20 +168,27 @@ object NewCommonSuperTypeCalculator {
|
||||
): SimpleTypeMarker {
|
||||
if (types.size == 1) return types.single()
|
||||
|
||||
val nonTypeVariables = types.filter { !isTypeVariable(it) }
|
||||
val nonTypeVariables = types.filter { !it.isStubTypeForVariableInSubtyping() && !isCapturedStubTypeForVariableInSubtyping(it) }
|
||||
if (nonTypeVariables.size == 1) return nonTypeVariables.single()
|
||||
|
||||
assert(nonTypeVariables.isNotEmpty()) {
|
||||
"There should be at least one non-stub type to compute common supertype but there are: $types"
|
||||
}
|
||||
|
||||
val stubTypeVariables = types.filter { isStubTypeVariable(it) }
|
||||
val nonStubTypeVariables = types.filter { !isStubTypeVariable(it) }
|
||||
val nonStubTypeVariables = types.filter { !it.isStubType() }
|
||||
val areAllNonStubTypesNothing = nonStubTypeVariables.isNotEmpty() && nonStubTypeVariables.all { it.isNothing() }
|
||||
if (nonStubTypeVariables.size == 1 && !areAllNonStubTypesNothing) return nonStubTypeVariables.single()
|
||||
|
||||
if (nonStubTypeVariables.isEmpty() || areAllNonStubTypesNothing) {
|
||||
return uniquify(stubTypeVariables, contextStubTypesNotEqual).singleOrNull() ?: nullableAnyType()
|
||||
val stubTypeVariables = types.filter { it.isStubType() }
|
||||
val uniqueStubTypes =
|
||||
stubTypeVariables.distinctBy { it.asDefinitelyNotNullType()?.original()?.typeConstructor() ?: it.typeConstructor() }
|
||||
|
||||
if (uniqueStubTypes.size > 1) return nullableAnyType()
|
||||
|
||||
if (stubTypeVariables.none { it.isDefinitelyNotNullType() }) {
|
||||
return uniquify(stubTypeVariables.ifEmpty { types }, contextStubTypesNotEqual).singleOrNull() ?: return nullableAnyType()
|
||||
}
|
||||
}
|
||||
|
||||
val uniqueTypes = uniquify(nonTypeVariables, contextStubTypesNotEqual)
|
||||
@@ -192,16 +203,6 @@ object NewCommonSuperTypeCalculator {
|
||||
return findSuperTypeConstructorsAndIntersectResult(explicitSupertypes, depth, contextStubTypesEqualToAnything)
|
||||
}
|
||||
|
||||
private fun TypeSystemCommonSuperTypesContext.isStubTypeVariable(type: SimpleTypeMarker): Boolean {
|
||||
return type.isStubType() || isStubCapturedTypeVariable(type)
|
||||
}
|
||||
|
||||
private fun TypeSystemCommonSuperTypesContext.isStubCapturedTypeVariable(type: SimpleTypeMarker): Boolean {
|
||||
val projectedType =
|
||||
type.asCapturedType()?.typeConstructor()?.projection()?.takeUnless { it.isStarProjection() }?.getType() ?: return false
|
||||
return projectedType.asSimpleType()?.isStubType() == true
|
||||
}
|
||||
|
||||
private fun TypeSystemCommonSuperTypesContext.isTypeVariable(type: SimpleTypeMarker): Boolean {
|
||||
return type.isStubTypeForVariableInSubtyping() || isCapturedTypeVariable(type)
|
||||
}
|
||||
|
||||
+22
-22
@@ -34,16 +34,16 @@ fun <E> select4(x: E?, y: In<E>): E = x!!
|
||||
fun test() {
|
||||
val ret = build {
|
||||
emit("1")
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("TypeVariable(R1)?")!>select1(get(), getIn())<!>
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("TypeVariable(R1)?")!>select1(get(), Test.foo(getIn()))<!>
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("TypeVariable(R1)?")!>select1(Test.foo(get()), Test.foo(getIn()))<!>
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("TypeVariable(R1)?")!>select1(Test.foo(get()), getIn())<!>
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("TypeVariable(R1)")!>select4(get(), getIn())<!>
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("TypeVariable(R1)")!>select4(get(), Test.foo(getIn()))<!>
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("TypeVariable(R1)")!>select4(Test.foo(get()), Test.foo(getIn()))<!>
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("TypeVariable(R1)")!>select4(Test.foo(get()), getIn())<!>
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String?")!>select1(get(), getIn())<!>
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String?")!>select1(get(), Test.foo(getIn()))<!>
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String?")!>select1(Test.foo(get()), Test.foo(getIn()))<!>
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String?")!>select1(Test.foo(get()), getIn())<!>
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String")!>select4(get(), getIn())<!>
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String")!>select4(get(), Test.foo(getIn()))<!>
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String")!>select4(Test.foo(get()), Test.foo(getIn()))<!>
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String")!>select4(Test.foo(get()), getIn())<!>
|
||||
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("TypeVariable(R1)")!>select4(id(Test.foo(get())), getIn())<!>
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String")!>select4(id(Test.foo(get())), getIn())<!>
|
||||
|
||||
build2 {
|
||||
emit(1)
|
||||
@@ -55,30 +55,30 @@ fun test() {
|
||||
select2(get(), <!TYPE_MISMATCH("TypeVariable(R1); TypeVariable(R2)")!>Test.foo(this@build.getIn())<!>)
|
||||
select2(Test.foo(this@build.get()), <!TYPE_MISMATCH("TypeVariable(R2); TypeVariable(R1)!")!>Test.foo(getIn())<!>)
|
||||
select2(Test.foo(get()), <!TYPE_MISMATCH("TypeVariable(R1); TypeVariable(R2)!")!>this@build.getIn()<!>)
|
||||
select3(this@build.get(), <!TYPE_MISMATCH("TypeVariable(R2); TypeVariable(R1)")!>getIn()<!>)
|
||||
select3(get(), <!TYPE_MISMATCH("TypeVariable(R1); TypeVariable(R2)")!>Test.foo(this@build.getIn())<!>)
|
||||
select3(this@build.get(), <!TYPE_MISMATCH("TypeVariable(R2); TypeVariable(R1)!!")!>getIn()<!>)
|
||||
select3(get(), <!TYPE_MISMATCH("TypeVariable(R1); TypeVariable(R2)!!")!>Test.foo(this@build.getIn())<!>)
|
||||
select3(Test.foo(this@build.get()), <!TYPE_MISMATCH("TypeVariable(R2); TypeVariable(R1)")!>Test.foo(getIn())<!>)
|
||||
select3(Test.foo(get()), <!TYPE_MISMATCH("TypeVariable(R1); TypeVariable(R2)")!>this@build.getIn()<!>)
|
||||
select4(this@build.get(), <!TYPE_MISMATCH("TypeVariable(R2); TypeVariable(R1)")!>getIn()<!>)
|
||||
select4(get(), <!TYPE_MISMATCH("TypeVariable(R1); TypeVariable(R2)")!>Test.foo(this@build.getIn())<!>)
|
||||
select4(this@build.get(), <!TYPE_MISMATCH("TypeVariable(R2); TypeVariable(R1)!!")!>getIn()<!>)
|
||||
select4(get(), <!TYPE_MISMATCH("TypeVariable(R1); TypeVariable(R2)!!")!>Test.foo(this@build.getIn())<!>)
|
||||
select4(Test.foo(this@build.get()), <!TYPE_MISMATCH("TypeVariable(R2); TypeVariable(R1)")!>Test.foo(getIn())<!>)
|
||||
select4(Test.foo(get()), <!TYPE_MISMATCH("TypeVariable(R1); TypeVariable(R2)")!>this@build.getIn()<!>)
|
||||
|
||||
select4(id(Test.foo(this@build.get())), <!TYPE_MISMATCH("TypeVariable(R2); TypeVariable(R1)")!>getIn()<!>)
|
||||
select4(id(Test.foo(this@build.get())), <!TYPE_MISMATCH("TypeVariable(R2); TypeVariable(R1)!!")!>getIn()<!>)
|
||||
""
|
||||
}
|
||||
""
|
||||
}
|
||||
val ret2 = build {
|
||||
emit(if (true) "" else null)
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("TypeVariable(R1)")!>select2(get(), getIn())<!>
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("TypeVariable(R1)")!>select2(get(), Test.foo(getIn()))<!>
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("(TypeVariable(R1)..TypeVariable(R1)?)")!>select2(Test.foo(get()), Test.foo(getIn()))<!>
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("(TypeVariable(R1)..TypeVariable(R1)?)")!>select2(Test.foo(get()), getIn())<!>
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("TypeVariable(R1)")!>select3(get(), getIn())<!>
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("TypeVariable(R1)")!>select3(get(), Test.foo(getIn()))<!>
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("TypeVariable(R1)")!>select3(Test.foo(get()), Test.foo(getIn()))<!>
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("TypeVariable(R1)")!>select3(Test.foo(get()), getIn())<!>
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String?")!>select2(get(), getIn())<!>
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String?")!>select2(get(), Test.foo(getIn()))<!>
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String?")!>select2(Test.foo(get()), Test.foo(getIn()))<!>
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String?")!>select2(Test.foo(get()), getIn())<!>
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String")!>select3(get(), getIn())<!>
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String")!>select3(get(), Test.foo(getIn()))<!>
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String?")!>select3(Test.foo(get()), Test.foo(getIn()))<!>
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String?")!>select3(Test.foo(get()), getIn())<!>
|
||||
""
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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!!"
|
||||
|
||||
|
||||
+10
-2
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user