From 5c8d3180f7d44df0eb3ac67b29846db23b56e814 Mon Sep 17 00:00:00 2001 From: pyos Date: Tue, 10 Aug 2021 22:41:22 +0200 Subject: [PATCH] FE: slowly refactor extractQualifiersFromAnnotations 2 --- .../typeEnhancement/signatureEnhancement.kt | 68 ++++++++----------- 1 file changed, 28 insertions(+), 40 deletions(-) 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 ca38f34675c..a9b94d1b6f0 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 @@ -277,16 +277,17 @@ private class SignatureParts( val annotationsNullability = annotationTypeQualifierResolver.extractNullability(composedAnnotation) { (this is LazyJavaAnnotationDescriptor && (isFreshlySupportedTypeUseAnnotation || typeParameterBounds) && !areImprovementsInStrictMode) || (this is PossiblyExternalAnnotationDescriptor && isIdeExternalAnnotation) - }.takeUnless { type == null } + } - if (annotationsNullability != null) { + if (type != null && annotationsNullability != null) { return JavaTypeQualifiers( annotationsNullability.qualifier, annotationsMutability, - annotationsNullability.qualifier == NullabilityQualifier.NOT_NULL && typeOrBound.isTypeParameter(), + annotationsNullability.qualifier == NullabilityQualifier.NOT_NULL && type.isTypeParameter(), annotationsNullability.isForWarningOnly ) } + // TODO: check whether the code below works properly for star projections (when typeOrBound != type) val defaultTypeQualifier = ( if (isHeadTypeConstructor) containerContext.defaultTypeQualifiers?.get(containerApplicabilityType) @@ -299,42 +300,43 @@ private class SignatureParts( ) )?.takeIf { (it.affectsTypeParameterBasedTypes || !typeOrBound.isTypeParameter()) && (it.affectsStarProjection || type != null) } - val (nullabilityFromBoundsForTypeBasedOnTypeParameter, isTypeParameterWithNotNullableBounds) = - typeOrBound.nullabilityInfoBoundsForTypeParameterUsage() - val nullabilityInfo = computeNullabilityInfoInTheAbsenceOfExplicitAnnotation( - nullabilityFromBoundsForTypeBasedOnTypeParameter, - defaultTypeQualifier, - typeParameterForArgument - ) + val referencedParameterBoundsNullability = + (typeOrBound.constructor.declarationDescriptor as? TypeParameterDescriptor)?.boundsNullability() + // For type parameter uses, we have *three* options: + // T!! - NOT_NULL, isNotNullTypeParameter = true + // happens if T is bounded by @NotNull (technically !! is redundant) or context says unannotated + // type parameters are non-null; + // T - NOT_NULL, isNotNullTypeParameter = false + // happens if T is bounded by @Nullable or context says unannotated types in general are non-null; + // T? - NULLABLE, isNotNullTypeParameter = false + // happens if context says unannotated types in general are nullable. + // For other types, this is more straightforward (just take nullability from the context). + // TODO: clean up the representation of those cases in JavaTypeQualifiers + val defaultNullability = + referencedParameterBoundsNullability?.copy(qualifier = NullabilityQualifier.NOT_NULL) + ?: defaultTypeQualifier?.nullabilityQualifier val isNotNullTypeParameter = - isTypeParameterWithNotNullableBounds || defaultTypeQualifier?.makesTypeParameterNotNull == true + referencedParameterBoundsNullability?.qualifier == NullabilityQualifier.NOT_NULL || + (typeOrBound.isTypeParameter() && defaultTypeQualifier?.makesTypeParameterNotNull == true) + + val nullabilityInfo = computeNullabilityInfoInTheAbsenceOfExplicitAnnotation(defaultNullability, typeParameterForArgument) return JavaTypeQualifiers( nullabilityInfo?.qualifier, annotationsMutability, - isNotNullTypeParameter = isNotNullTypeParameter && typeOrBound.isTypeParameter(), - isNullabilityQualifierForWarning = nullabilityInfo?.isForWarningOnly == true + isNotNullTypeParameter, + nullabilityInfo?.isForWarningOnly == true ) } private fun computeNullabilityInfoInTheAbsenceOfExplicitAnnotation( - nullabilityFromBoundsForTypeBasedOnTypeParameter: NullabilityQualifierWithMigrationStatus?, - defaultTypeQualifier: JavaDefaultQualifiers?, + result: NullabilityQualifierWithMigrationStatus?, typeParameterForArgument: TypeParameterDescriptor? ): NullabilityQualifierWithMigrationStatus? { - val result = - nullabilityFromBoundsForTypeBasedOnTypeParameter - ?: defaultTypeQualifier?.nullabilityQualifier?.let { nullabilityQualifierWithMigrationStatus -> - NullabilityQualifierWithMigrationStatus( - nullabilityQualifierWithMigrationStatus.qualifier, - nullabilityQualifierWithMigrationStatus.isForWarningOnly - ) - } - val boundsFromTypeParameterForArgument = typeParameterForArgument?.boundsNullability() ?: return result - if (defaultTypeQualifier == null && result == null && boundsFromTypeParameterForArgument.qualifier == NullabilityQualifier.NULLABLE) { + if (result == null && boundsFromTypeParameterForArgument.qualifier == NullabilityQualifier.NULLABLE) { return NullabilityQualifierWithMigrationStatus( NullabilityQualifier.FORCE_FLEXIBILITY, boundsFromTypeParameterForArgument.isForWarningOnly @@ -350,6 +352,7 @@ private class SignatureParts( a: NullabilityQualifierWithMigrationStatus, b: NullabilityQualifierWithMigrationStatus ): NullabilityQualifierWithMigrationStatus { + // TODO: this probably behaves really weirdly when some of those are warnings. if (a.qualifier == NullabilityQualifier.FORCE_FLEXIBILITY) return b if (b.qualifier == NullabilityQualifier.FORCE_FLEXIBILITY) return a if (a.qualifier == NullabilityQualifier.NULLABLE) return b @@ -361,21 +364,6 @@ private class SignatureParts( return NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL) } - private fun KotlinType.nullabilityInfoBoundsForTypeParameterUsage(): Pair { - val typeParameterBoundsNullability = - (constructor.declarationDescriptor as? TypeParameterDescriptor)?.boundsNullability() ?: return Pair(null, false) - - // If type parameter has a nullable (non-flexible) upper bound - // We shouldn't mark its type usages as nullable: - // interface A { - // void foo(T t); // should be loaded as "fun foo(t: T)" but not as "fun foo(t: T?)" - // } - return Pair( - NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL, typeParameterBoundsNullability.isForWarningOnly), - typeParameterBoundsNullability.qualifier == NullabilityQualifier.NOT_NULL - ) - } - private fun TypeParameterDescriptor.boundsNullability(): NullabilityQualifierWithMigrationStatus? { // Do not use bounds from Kotlin-defined type parameters if (this !is LazyJavaTypeParameterDescriptor || upperBounds.all(KotlinType::isError)) return null