From c753e547c655fc6ff18147ead85c1d46cc6ea16d Mon Sep 17 00:00:00 2001 From: pyos Date: Mon, 9 Aug 2021 17:04:24 +0200 Subject: [PATCH] FE/FIR: extract common code for type qualifier inheritance --- .../enhancement/EnhancementSignatureParts.kt | 57 +------------- .../typeEnhancement/typeEnhancementUtils.kt | 41 ++++++---- .../typeEnhancement/signatureEnhancement.kt | 78 +++++-------------- 3 files changed, 50 insertions(+), 126 deletions(-) diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/enhancement/EnhancementSignatureParts.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/enhancement/EnhancementSignatureParts.kt index c07c48d280d..b05995bbdc1 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/enhancement/EnhancementSignatureParts.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/enhancement/EnhancementSignatureParts.kt @@ -234,53 +234,6 @@ internal class EnhancementSignatureParts( private fun FirTypeRef?.isTypeParameterBasedType() = ((this as? FirJavaTypeRef)?.type as? JavaClassifierType)?.classifier is JavaTypeParameter - private fun FirTypeRef?.computeQualifiersForOverride( - session: FirSession, - fromSupertypes: Collection, - 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 { val indexedFromSupertypes = fromOverridden.map { it.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 computedResult = Array(treeSize) { index -> - val isHeadTypeConstructor = index == 0 - assert(isHeadTypeConstructor || !onlyHeadTypeConstructor) { "Only head type constructors should be computed" } - val (type, defaultQualifiers) = indexedThisType[index] - val verticalSlice = indexedFromSupertypes.mapNotNull { it.getOrNull(index)?.type } - - // Only the head type constructor is safely co-variant - type.computeQualifiersForOverride(session, verticalSlice, defaultQualifiers, isHeadTypeConstructor) + val qualifiers = type.extractQualifiersFromAnnotations(index == 0, defaultQualifiers) + val superQualifiers = indexedFromSupertypes.mapNotNull { it.getOrNull(index)?.type?.extractQualifiers(session) } + qualifiers.computeQualifiersForOverride(superQualifiers, index == 0 && isCovariant, index == 0 && isForVarargParameter) } return IndexedJavaTypeQualifiers(computedResult) diff --git a/core/compiler.common.jvm/src/org/jetbrains/kotlin/load/java/typeEnhancement/typeEnhancementUtils.kt b/core/compiler.common.jvm/src/org/jetbrains/kotlin/load/java/typeEnhancement/typeEnhancementUtils.kt index b3629ec2e44..f47bd507bd2 100644 --- a/core/compiler.common.jvm/src/org/jetbrains/kotlin/load/java/typeEnhancement/typeEnhancementUtils.kt +++ b/core/compiler.common.jvm/src/org/jetbrains/kotlin/load/java/typeEnhancement/typeEnhancementUtils.kt @@ -9,19 +9,7 @@ import org.jetbrains.kotlin.load.java.JvmAnnotationNames import org.jetbrains.kotlin.types.TypeSystemCommonBackendContext import org.jetbrains.kotlin.types.model.KotlinTypeMarker -fun createJavaTypeQualifiers( - 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 Set.select(low: T, high: T, own: T?, isCovariant: Boolean): T? { +private fun Set.select(low: T, high: T, own: T?, isCovariant: Boolean): T? { if (isCovariant) { 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 @@ -35,11 +23,36 @@ fun Set.select(low: T, high: T, own: T?, isCovariant: Boolean): T? return effectiveSet.singleOrNull() } -fun Set.select(own: NullabilityQualifier?, isCovariant: Boolean) = +private fun Set.select(own: NullabilityQualifier?, isCovariant: Boolean) = if (own == NullabilityQualifier.FORCE_FLEXIBILITY) NullabilityQualifier.FORCE_FLEXIBILITY else select(NullabilityQualifier.NOT_NULL, NullabilityQualifier.NULLABLE, own, isCovariant) +private val JavaTypeQualifiers.nullabilityForErrors: NullabilityQualifier? + get() = if (isNullabilityQualifierForWarning) null else nullability + +fun JavaTypeQualifiers.computeQualifiersForOverride( + superQualifiers: Collection, + 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 = type.hasAnnotation(JvmAnnotationNames.ENHANCED_NULLABILITY_ANNOTATION) diff --git a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/typeEnhancement/signatureEnhancement.kt b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/typeEnhancement/signatureEnhancement.kt index 64d0398e949..f4bacd0cfbd 100644 --- a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/typeEnhancement/signatureEnhancement.kt +++ b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/typeEnhancement/signatureEnhancement.kt @@ -225,20 +225,24 @@ private class SignatureParts( private val KotlinType.fqNameUnsafe: FqNameUnsafe? 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 { - val lower = lowerIfFlexible() - val upper = upperIfFlexible() - val nullability = when { - 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) + val forErrors = nullabilityQualifier + val forErrorsOrWarnings = forErrors ?: unwrapEnhancement().nullabilityQualifier + return JavaTypeQualifiers(forErrorsOrWarnings, mutabilityQualifier, isNotNullTypeParameter, forErrorsOrWarnings != forErrors) } private fun TypeAndDefaultQualifiers.extractQualifiersFromAnnotations(): JavaTypeQualifiers { @@ -431,8 +435,9 @@ private class SignatureParts( val treeSize = if (onlyHeadTypeConstructor) 1 else indexedThisType.size val computedResult = Array(treeSize) { index -> - val verticalSlice = indexedFromSupertypes.mapNotNull { it.getOrNull(index)?.type } - indexedThisType[index].computeQualifiersForOverride(verticalSlice) + val qualifiers = indexedThisType[index].extractQualifiersFromAnnotations() + 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 } } } @@ -460,49 +465,6 @@ private class SignatureParts( TypeAndDefaultQualifiers(arg.type, arg.type.extractAndMergeDefaultQualifiers(it.defaultQualifiers), parameter) } } - - private fun TypeAndDefaultQualifiers.computeQualifiersForOverride(fromSupertypes: Collection): 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(