FE/FIR: extract common code for type qualifier inheritance
This commit is contained in:
+3
-54
@@ -234,53 +234,6 @@ internal class EnhancementSignatureParts(
|
|||||||
private fun FirTypeRef?.isTypeParameterBasedType() =
|
private fun FirTypeRef?.isTypeParameterBasedType() =
|
||||||
((this as? FirJavaTypeRef)?.type as? JavaClassifierType)?.classifier is JavaTypeParameter
|
((this as? FirJavaTypeRef)?.type as? JavaClassifierType)?.classifier is JavaTypeParameter
|
||||||
|
|
||||||
private fun FirTypeRef?.computeQualifiersForOverride(
|
|
||||||
session: FirSession,
|
|
||||||
fromSupertypes: Collection<FirTypeRef>,
|
|
||||||
defaultQualifiersForType: JavaDefaultQualifiers?,
|
|
||||||
isHeadTypeConstructor: Boolean
|
|
||||||
): JavaTypeQualifiers {
|
|
||||||
val superQualifiers = fromSupertypes.map { it.extractQualifiers(session) }
|
|
||||||
val mutabilityFromSupertypes = superQualifiers.mapNotNull { it.mutability }.toSet()
|
|
||||||
val nullabilityFromSupertypes = superQualifiers.mapNotNull { it.nullability }.toSet()
|
|
||||||
val nullabilityFromSupertypesWithWarning = fromSupertypes
|
|
||||||
.mapNotNull { it.extractQualifiers(session).nullability }
|
|
||||||
.toSet()
|
|
||||||
|
|
||||||
val own = extractQualifiersFromAnnotations(isHeadTypeConstructor, defaultQualifiersForType)
|
|
||||||
val ownNullability = own.takeIf { !it.isNullabilityQualifierForWarning }?.nullability
|
|
||||||
val ownNullabilityForWarning = own.nullability
|
|
||||||
|
|
||||||
val isCovariantPosition = isCovariant && isHeadTypeConstructor
|
|
||||||
val nullability =
|
|
||||||
nullabilityFromSupertypes.select(ownNullability, isCovariantPosition)
|
|
||||||
// Vararg value parameters effectively have non-nullable type in Kotlin
|
|
||||||
// and having nullable types in Java may lead to impossibility of overriding them in Kotlin
|
|
||||||
?.takeUnless { isForVarargParameter && isHeadTypeConstructor && it == NullabilityQualifier.NULLABLE }
|
|
||||||
|
|
||||||
val mutability =
|
|
||||||
mutabilityFromSupertypes
|
|
||||||
.select(MutabilityQualifier.MUTABLE, MutabilityQualifier.READ_ONLY, own.mutability, isCovariantPosition)
|
|
||||||
|
|
||||||
val canChange = ownNullabilityForWarning != ownNullability || nullabilityFromSupertypesWithWarning != nullabilityFromSupertypes
|
|
||||||
val isAnyNonNullTypeParameter = own.isNotNullTypeParameter || superQualifiers.any { it.isNotNullTypeParameter }
|
|
||||||
if (nullability == null && canChange) {
|
|
||||||
val nullabilityWithWarning =
|
|
||||||
nullabilityFromSupertypesWithWarning.select(ownNullabilityForWarning, isCovariantPosition)
|
|
||||||
|
|
||||||
return createJavaTypeQualifiers(
|
|
||||||
nullabilityWithWarning, mutability,
|
|
||||||
forWarning = true, isAnyNonNullTypeParameter = isAnyNonNullTypeParameter
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return createJavaTypeQualifiers(
|
|
||||||
nullability, mutability,
|
|
||||||
forWarning = nullability == null,
|
|
||||||
isAnyNonNullTypeParameter = isAnyNonNullTypeParameter
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun computeIndexedQualifiersForOverride(session: FirSession): IndexedJavaTypeQualifiers {
|
private fun computeIndexedQualifiersForOverride(session: FirSession): IndexedJavaTypeQualifiers {
|
||||||
val indexedFromSupertypes = fromOverridden.map { it.toIndexed(typeQualifierResolver, context) }
|
val indexedFromSupertypes = fromOverridden.map { it.toIndexed(typeQualifierResolver, context) }
|
||||||
val indexedThisType = current.toIndexed(typeQualifierResolver, context)
|
val indexedThisType = current.toIndexed(typeQualifierResolver, context)
|
||||||
@@ -294,14 +247,10 @@ internal class EnhancementSignatureParts(
|
|||||||
|
|
||||||
val treeSize = if (onlyHeadTypeConstructor) 1 else indexedThisType.size
|
val treeSize = if (onlyHeadTypeConstructor) 1 else indexedThisType.size
|
||||||
val computedResult = Array(treeSize) { index ->
|
val computedResult = Array(treeSize) { index ->
|
||||||
val isHeadTypeConstructor = index == 0
|
|
||||||
assert(isHeadTypeConstructor || !onlyHeadTypeConstructor) { "Only head type constructors should be computed" }
|
|
||||||
|
|
||||||
val (type, defaultQualifiers) = indexedThisType[index]
|
val (type, defaultQualifiers) = indexedThisType[index]
|
||||||
val verticalSlice = indexedFromSupertypes.mapNotNull { it.getOrNull(index)?.type }
|
val qualifiers = type.extractQualifiersFromAnnotations(index == 0, defaultQualifiers)
|
||||||
|
val superQualifiers = indexedFromSupertypes.mapNotNull { it.getOrNull(index)?.type?.extractQualifiers(session) }
|
||||||
// Only the head type constructor is safely co-variant
|
qualifiers.computeQualifiersForOverride(superQualifiers, index == 0 && isCovariant, index == 0 && isForVarargParameter)
|
||||||
type.computeQualifiersForOverride(session, verticalSlice, defaultQualifiers, isHeadTypeConstructor)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return IndexedJavaTypeQualifiers(computedResult)
|
return IndexedJavaTypeQualifiers(computedResult)
|
||||||
|
|||||||
+27
-14
@@ -9,19 +9,7 @@ import org.jetbrains.kotlin.load.java.JvmAnnotationNames
|
|||||||
import org.jetbrains.kotlin.types.TypeSystemCommonBackendContext
|
import org.jetbrains.kotlin.types.TypeSystemCommonBackendContext
|
||||||
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
|
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
|
||||||
|
|
||||||
fun createJavaTypeQualifiers(
|
private fun <T : Any> Set<T>.select(low: T, high: T, own: T?, isCovariant: Boolean): T? {
|
||||||
nullability: NullabilityQualifier?,
|
|
||||||
mutability: MutabilityQualifier?,
|
|
||||||
forWarning: Boolean,
|
|
||||||
isAnyNonNullTypeParameter: Boolean
|
|
||||||
): JavaTypeQualifiers {
|
|
||||||
if (!isAnyNonNullTypeParameter || nullability != NullabilityQualifier.NOT_NULL) {
|
|
||||||
return JavaTypeQualifiers(nullability, mutability, false, forWarning)
|
|
||||||
}
|
|
||||||
return JavaTypeQualifiers(nullability, mutability, true, forWarning)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <T : Any> Set<T>.select(low: T, high: T, own: T?, isCovariant: Boolean): T? {
|
|
||||||
if (isCovariant) {
|
if (isCovariant) {
|
||||||
val supertypeQualifier = if (low in this) low else if (high in this) high else null
|
val supertypeQualifier = if (low in this) low else if (high in this) high else null
|
||||||
return if (supertypeQualifier == low && own == high) null else own ?: supertypeQualifier
|
return if (supertypeQualifier == low && own == high) null else own ?: supertypeQualifier
|
||||||
@@ -35,11 +23,36 @@ fun <T : Any> Set<T>.select(low: T, high: T, own: T?, isCovariant: Boolean): T?
|
|||||||
return effectiveSet.singleOrNull()
|
return effectiveSet.singleOrNull()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Set<NullabilityQualifier>.select(own: NullabilityQualifier?, isCovariant: Boolean) =
|
private fun Set<NullabilityQualifier>.select(own: NullabilityQualifier?, isCovariant: Boolean) =
|
||||||
if (own == NullabilityQualifier.FORCE_FLEXIBILITY)
|
if (own == NullabilityQualifier.FORCE_FLEXIBILITY)
|
||||||
NullabilityQualifier.FORCE_FLEXIBILITY
|
NullabilityQualifier.FORCE_FLEXIBILITY
|
||||||
else
|
else
|
||||||
select(NullabilityQualifier.NOT_NULL, NullabilityQualifier.NULLABLE, own, isCovariant)
|
select(NullabilityQualifier.NOT_NULL, NullabilityQualifier.NULLABLE, own, isCovariant)
|
||||||
|
|
||||||
|
private val JavaTypeQualifiers.nullabilityForErrors: NullabilityQualifier?
|
||||||
|
get() = if (isNullabilityQualifierForWarning) null else nullability
|
||||||
|
|
||||||
|
fun JavaTypeQualifiers.computeQualifiersForOverride(
|
||||||
|
superQualifiers: Collection<JavaTypeQualifiers>,
|
||||||
|
isCovariant: Boolean,
|
||||||
|
isForVarargParameter: Boolean
|
||||||
|
): JavaTypeQualifiers {
|
||||||
|
val newNullabilityForErrors = superQualifiers.mapNotNull { it.nullabilityForErrors }.toSet()
|
||||||
|
.select(nullabilityForErrors, isCovariant)
|
||||||
|
val newNullability = newNullabilityForErrors ?: superQualifiers.mapNotNull { it.nullability }.toSet()
|
||||||
|
.select(nullability, isCovariant)
|
||||||
|
val newMutability = superQualifiers.mapNotNull { it.mutability }.toSet()
|
||||||
|
.select(MutabilityQualifier.MUTABLE, MutabilityQualifier.READ_ONLY, mutability, isCovariant)
|
||||||
|
// Vararg value parameters effectively have non-nullable type in Kotlin
|
||||||
|
// and having nullable types in Java may lead to impossibility of overriding them in Kotlin
|
||||||
|
val realNullability = newNullability?.takeUnless { isForVarargParameter && it == NullabilityQualifier.NULLABLE }
|
||||||
|
return JavaTypeQualifiers(
|
||||||
|
realNullability, newMutability,
|
||||||
|
realNullability == NullabilityQualifier.NOT_NULL &&
|
||||||
|
(isNotNullTypeParameter || superQualifiers.any { it.isNotNullTypeParameter }),
|
||||||
|
realNullability != null && newNullabilityForErrors != newNullability
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fun TypeSystemCommonBackendContext.hasEnhancedNullability(type: KotlinTypeMarker): Boolean =
|
fun TypeSystemCommonBackendContext.hasEnhancedNullability(type: KotlinTypeMarker): Boolean =
|
||||||
type.hasAnnotation(JvmAnnotationNames.ENHANCED_NULLABILITY_ANNOTATION)
|
type.hasAnnotation(JvmAnnotationNames.ENHANCED_NULLABILITY_ANNOTATION)
|
||||||
|
|||||||
+20
-58
@@ -225,20 +225,24 @@ private class SignatureParts(
|
|||||||
private val KotlinType.fqNameUnsafe: FqNameUnsafe?
|
private val KotlinType.fqNameUnsafe: FqNameUnsafe?
|
||||||
get() = TypeUtils.getClassDescriptor(this)?.let { DescriptorUtils.getFqName(it) }
|
get() = TypeUtils.getClassDescriptor(this)?.let { DescriptorUtils.getFqName(it) }
|
||||||
|
|
||||||
|
private val KotlinType.nullabilityQualifier: NullabilityQualifier?
|
||||||
|
get() = when {
|
||||||
|
lowerIfFlexible().isMarkedNullable -> NullabilityQualifier.NULLABLE
|
||||||
|
!upperIfFlexible().isMarkedNullable -> NullabilityQualifier.NOT_NULL
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
|
||||||
|
private val KotlinType.mutabilityQualifier: MutabilityQualifier?
|
||||||
|
get() = when {
|
||||||
|
JavaToKotlinClassMap.isReadOnly(lowerIfFlexible().fqNameUnsafe) -> MutabilityQualifier.READ_ONLY
|
||||||
|
JavaToKotlinClassMap.isMutable(upperIfFlexible().fqNameUnsafe) -> MutabilityQualifier.MUTABLE
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
|
||||||
private fun KotlinType.extractQualifiers(): JavaTypeQualifiers {
|
private fun KotlinType.extractQualifiers(): JavaTypeQualifiers {
|
||||||
val lower = lowerIfFlexible()
|
val forErrors = nullabilityQualifier
|
||||||
val upper = upperIfFlexible()
|
val forErrorsOrWarnings = forErrors ?: unwrapEnhancement().nullabilityQualifier
|
||||||
val nullability = when {
|
return JavaTypeQualifiers(forErrorsOrWarnings, mutabilityQualifier, isNotNullTypeParameter, forErrorsOrWarnings != forErrors)
|
||||||
lower.isMarkedNullable -> NullabilityQualifier.NULLABLE
|
|
||||||
!upper.isMarkedNullable -> NullabilityQualifier.NOT_NULL
|
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
val mutability = when {
|
|
||||||
JavaToKotlinClassMap.isReadOnly(lower.fqNameUnsafe) -> MutabilityQualifier.READ_ONLY
|
|
||||||
JavaToKotlinClassMap.isMutable(upper.fqNameUnsafe) -> MutabilityQualifier.MUTABLE
|
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
return JavaTypeQualifiers(nullability, mutability, isNotNullTypeParameter)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun TypeAndDefaultQualifiers.extractQualifiersFromAnnotations(): JavaTypeQualifiers {
|
private fun TypeAndDefaultQualifiers.extractQualifiersFromAnnotations(): JavaTypeQualifiers {
|
||||||
@@ -431,8 +435,9 @@ private class SignatureParts(
|
|||||||
|
|
||||||
val treeSize = if (onlyHeadTypeConstructor) 1 else indexedThisType.size
|
val treeSize = if (onlyHeadTypeConstructor) 1 else indexedThisType.size
|
||||||
val computedResult = Array(treeSize) { index ->
|
val computedResult = Array(treeSize) { index ->
|
||||||
val verticalSlice = indexedFromSupertypes.mapNotNull { it.getOrNull(index)?.type }
|
val qualifiers = indexedThisType[index].extractQualifiersFromAnnotations()
|
||||||
indexedThisType[index].computeQualifiersForOverride(verticalSlice)
|
val superQualifiers = indexedFromSupertypes.mapNotNull { it.getOrNull(index)?.type?.extractQualifiers() }
|
||||||
|
qualifiers.computeQualifiersForOverride(superQualifiers, index == 0 && isCovariant, index == 0 && isForVarargParameter)
|
||||||
}
|
}
|
||||||
return { index -> predefined?.map?.get(index) ?: computedResult.getOrElse(index) { JavaTypeQualifiers.NONE } }
|
return { index -> predefined?.map?.get(index) ?: computedResult.getOrElse(index) { JavaTypeQualifiers.NONE } }
|
||||||
}
|
}
|
||||||
@@ -460,49 +465,6 @@ private class SignatureParts(
|
|||||||
TypeAndDefaultQualifiers(arg.type, arg.type.extractAndMergeDefaultQualifiers(it.defaultQualifiers), parameter)
|
TypeAndDefaultQualifiers(arg.type, arg.type.extractAndMergeDefaultQualifiers(it.defaultQualifiers), parameter)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun TypeAndDefaultQualifiers.computeQualifiersForOverride(fromSupertypes: Collection<KotlinType>): JavaTypeQualifiers {
|
|
||||||
val superQualifiers = fromSupertypes.map { it.extractQualifiers() }
|
|
||||||
val mutabilityFromSupertypes = superQualifiers.mapNotNull { it.mutability }.toSet()
|
|
||||||
val nullabilityFromSupertypes = superQualifiers.mapNotNull { it.nullability }.toSet()
|
|
||||||
val nullabilityFromSupertypesWithWarning = fromSupertypes
|
|
||||||
.mapNotNull { it.unwrapEnhancement().extractQualifiers().nullability }
|
|
||||||
.toSet()
|
|
||||||
|
|
||||||
val own = extractQualifiersFromAnnotations()
|
|
||||||
val ownNullability = own.takeIf { !it.isNullabilityQualifierForWarning }?.nullability
|
|
||||||
val ownNullabilityForWarning = own.nullability
|
|
||||||
|
|
||||||
val isHeadTypeConstructor = typeParameterForArgument == null
|
|
||||||
val isCovariantPosition = isCovariant && isHeadTypeConstructor
|
|
||||||
val nullability =
|
|
||||||
nullabilityFromSupertypes.select(ownNullability, isCovariantPosition)
|
|
||||||
// Vararg value parameters effectively have non-nullable type in Kotlin
|
|
||||||
// and having nullable types in Java may lead to impossibility of overriding them in Kotlin
|
|
||||||
?.takeUnless { isForVarargParameter && isHeadTypeConstructor && it == NullabilityQualifier.NULLABLE }
|
|
||||||
|
|
||||||
val mutability =
|
|
||||||
mutabilityFromSupertypes
|
|
||||||
.select(MutabilityQualifier.MUTABLE, MutabilityQualifier.READ_ONLY, own.mutability, isCovariantPosition)
|
|
||||||
|
|
||||||
val canChange = ownNullabilityForWarning != ownNullability || nullabilityFromSupertypesWithWarning != nullabilityFromSupertypes
|
|
||||||
val isAnyNonNullTypeParameter = own.isNotNullTypeParameter || superQualifiers.any { it.isNotNullTypeParameter }
|
|
||||||
if (nullability == null && canChange) {
|
|
||||||
val nullabilityWithWarning =
|
|
||||||
nullabilityFromSupertypesWithWarning.select(ownNullabilityForWarning, isCovariantPosition)
|
|
||||||
|
|
||||||
return createJavaTypeQualifiers(
|
|
||||||
nullabilityWithWarning, mutability,
|
|
||||||
forWarning = true, isAnyNonNullTypeParameter = isAnyNonNullTypeParameter
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return createJavaTypeQualifiers(
|
|
||||||
nullability, mutability,
|
|
||||||
forWarning = nullability == null,
|
|
||||||
isAnyNonNullTypeParameter = isAnyNonNullTypeParameter
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private data class TypeAndDefaultQualifiers(
|
private data class TypeAndDefaultQualifiers(
|
||||||
|
|||||||
Reference in New Issue
Block a user