From f1c68a9080c9fc5f0612313de0df8393b3d69986 Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Mon, 29 Jun 2020 16:00:29 +0300 Subject: [PATCH] Introduce JavaTypeEnhancement component It's necessary to allow using language version settings in type enancement --- .../typeEnhancement/signatureEnhancement.kt | 17 +- .../java/typeEnhancement/typeEnhancement.kt | 173 +++++++++--------- 2 files changed, 99 insertions(+), 91 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 25644e71322..b3a3d437abc 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 @@ -18,7 +18,10 @@ package org.jetbrains.kotlin.load.java.typeEnhancement import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap import org.jetbrains.kotlin.descriptors.* -import org.jetbrains.kotlin.descriptors.annotations.* +import org.jetbrains.kotlin.descriptors.annotations.Annotated +import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor +import org.jetbrains.kotlin.descriptors.annotations.Annotations +import org.jetbrains.kotlin.descriptors.annotations.composeAnnotations import org.jetbrains.kotlin.load.java.* import org.jetbrains.kotlin.load.java.descriptors.* import org.jetbrains.kotlin.load.java.lazy.LazyJavaResolverContext @@ -31,7 +34,6 @@ import org.jetbrains.kotlin.resolve.constants.EnumValue import org.jetbrains.kotlin.resolve.deprecation.DEPRECATED_FUNCTION_KEY import org.jetbrains.kotlin.resolve.descriptorUtil.firstArgument import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameOrNull -import org.jetbrains.kotlin.resolve.descriptorUtil.isSourceAnnotation import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.checker.KotlinTypeChecker import org.jetbrains.kotlin.types.typeUtil.isTypeParameter @@ -46,7 +48,8 @@ data class NullabilityQualifierWithMigrationStatus( class SignatureEnhancement( private val annotationTypeQualifierResolver: AnnotationTypeQualifierResolver, - private val jsr305State: Jsr305State + private val jsr305State: Jsr305State, + private val typeEnhancement: JavaTypeEnhancement ) { private fun AnnotationDescriptor.extractNullabilityTypeFromArgument(): NullabilityQualifierWithMigrationStatus? { @@ -241,9 +244,11 @@ class SignatureEnhancement( classifier.fqNameOrNull() == JavaToKotlinClassMap.FUNCTION_N_FQ_NAME } - return fromOverride.enhance(qualifiersWithPredefined ?: qualifiers)?.let { enhanced -> - PartEnhancementResult(enhanced, wereChanges = true, containsFunctionN = containsFunctionN) - } ?: PartEnhancementResult(fromOverride, wereChanges = false, containsFunctionN = containsFunctionN) + return with(typeEnhancement) { + fromOverride.enhance(qualifiersWithPredefined ?: qualifiers)?.let { enhanced -> + PartEnhancementResult(enhanced, wereChanges = true, containsFunctionN = containsFunctionN) + } ?: PartEnhancementResult(fromOverride, wereChanges = false, containsFunctionN = containsFunctionN) + } } private fun KotlinType.extractQualifiers(): JavaTypeQualifiers { diff --git a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/typeEnhancement/typeEnhancement.kt b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/typeEnhancement/typeEnhancement.kt index 2aba640720e..fbfd9cb173a 100644 --- a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/typeEnhancement/typeEnhancement.kt +++ b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/typeEnhancement/typeEnhancement.kt @@ -39,12 +39,6 @@ import org.jetbrains.kotlin.types.refinement.TypeRefinement import org.jetbrains.kotlin.types.typeUtil.createProjection import org.jetbrains.kotlin.types.typeUtil.isTypeParameter -// The index in the lambda is the position of the type component: -// Example: for `A>`, indices go as follows: `0 - A<...>, 1 - B, 2 - C, 3 - D, 4 - E`, -// which corresponds to the left-to-right breadth-first walk of the tree representation of the type. -// For flexible types, both bounds are indexed in the same way: `(A..C)` gives `0 - (A..C), 1 - B and D`. -fun KotlinType.enhance(qualifiers: (Int) -> JavaTypeQualifiers) = unwrap().enhancePossiblyFlexible(qualifiers, 0).typeIfChanged - fun KotlinType.hasEnhancedNullability(): Boolean = SimpleClassicTypeSystemContext.hasEnhancedNullability(this) @@ -57,96 +51,105 @@ enum class TypeComponentPosition { INFLEXIBLE } -private open class Result(open val type: KotlinType, val subtreeSize: Int, val wereChanges: Boolean) { - val typeIfChanged: KotlinType? get() = type.takeIf { wereChanges } -} +class JavaTypeEnhancement { -private class SimpleResult(override val type: SimpleType, subtreeSize: Int, wereChanges: Boolean) : Result(type, subtreeSize, wereChanges) + private open class Result(open val type: KotlinType, val subtreeSize: Int, val wereChanges: Boolean) { + val typeIfChanged: KotlinType? get() = type.takeIf { wereChanges } + } -private fun UnwrappedType.enhancePossiblyFlexible(qualifiers: (Int) -> JavaTypeQualifiers, index: Int): Result { - if (isError) return Result(this, 1, false) - return when (this) { - is FlexibleType -> { - val lowerResult = lowerBound.enhanceInflexible(qualifiers, index, TypeComponentPosition.FLEXIBLE_LOWER) - val upperResult = upperBound.enhanceInflexible(qualifiers, index, TypeComponentPosition.FLEXIBLE_UPPER) - assert(lowerResult.subtreeSize == upperResult.subtreeSize) { - "Different tree sizes of bounds: " + - "lower = ($lowerBound, ${lowerResult.subtreeSize}), " + - "upper = ($upperBound, ${upperResult.subtreeSize})" + private class SimpleResult(override val type: SimpleType, subtreeSize: Int, wereChanges: Boolean) : Result(type, subtreeSize, wereChanges) + + // The index in the lambda is the position of the type component: + // Example: for `A>`, indices go as follows: `0 - A<...>, 1 - B, 2 - C, 3 - D, 4 - E`, + // which corresponds to the left-to-right breadth-first walk of the tree representation of the type. + // For flexible types, both bounds are indexed in the same way: `(A..C)` gives `0 - (A..C), 1 - B and D`. + fun KotlinType.enhance(qualifiers: (Int) -> JavaTypeQualifiers) = unwrap().enhancePossiblyFlexible(qualifiers, 0).typeIfChanged + + private fun UnwrappedType.enhancePossiblyFlexible(qualifiers: (Int) -> JavaTypeQualifiers, index: Int): Result { + if (isError) return Result(this, 1, false) + return when (this) { + is FlexibleType -> { + val lowerResult = lowerBound.enhanceInflexible(qualifiers, index, TypeComponentPosition.FLEXIBLE_LOWER) + val upperResult = upperBound.enhanceInflexible(qualifiers, index, TypeComponentPosition.FLEXIBLE_UPPER) + assert(lowerResult.subtreeSize == upperResult.subtreeSize) { + "Different tree sizes of bounds: " + + "lower = ($lowerBound, ${lowerResult.subtreeSize}), " + + "upper = ($upperBound, ${upperResult.subtreeSize})" + } + + val wereChanges = lowerResult.wereChanges || upperResult.wereChanges + val enhancement = lowerResult.type.getEnhancement() ?: upperResult.type.getEnhancement() + val type = if (!wereChanges) this@enhancePossiblyFlexible + else when { + this is RawTypeImpl -> RawTypeImpl(lowerResult.type, upperResult.type) + else -> KotlinTypeFactory.flexibleType(lowerResult.type, upperResult.type) + }.wrapEnhancement(enhancement) + + Result( + type, + lowerResult.subtreeSize, + wereChanges + ) } - - val wereChanges = lowerResult.wereChanges || upperResult.wereChanges - val enhancement = lowerResult.type.getEnhancement() ?: upperResult.type.getEnhancement() - val type = if (!wereChanges) this@enhancePossiblyFlexible - else when { - this is RawTypeImpl -> RawTypeImpl(lowerResult.type, upperResult.type) - else -> KotlinTypeFactory.flexibleType(lowerResult.type, upperResult.type) - }.wrapEnhancement(enhancement) - - Result( - type, - lowerResult.subtreeSize, - wereChanges - ) - } - is SimpleType -> enhanceInflexible(qualifiers, index, TypeComponentPosition.INFLEXIBLE) - } -} - -private fun SimpleType.enhanceInflexible( - qualifiers: (Int) -> JavaTypeQualifiers, - index: Int, - position: TypeComponentPosition -): SimpleResult { - val shouldEnhance = position.shouldEnhance() - if (!shouldEnhance && arguments.isEmpty()) return SimpleResult(this, 1, false) - - val originalClass = constructor.declarationDescriptor - ?: return SimpleResult(this, 1, false) - - val effectiveQualifiers = qualifiers(index) - val (enhancedClassifier, enhancedMutabilityAnnotations) = originalClass.enhanceMutability(effectiveQualifiers, position) - - val typeConstructor = enhancedClassifier.typeConstructor - - var globalArgIndex = index + 1 - var wereChanges = enhancedMutabilityAnnotations != null - val enhancedArguments = arguments.mapIndexed { localArgIndex, arg -> - if (arg.isStarProjection) { - globalArgIndex++ - TypeUtils.makeStarProjection(enhancedClassifier.typeConstructor.parameters[localArgIndex]) - } else { - val enhanced = arg.type.unwrap().enhancePossiblyFlexible(qualifiers, globalArgIndex) - wereChanges = wereChanges || enhanced.wereChanges - globalArgIndex += enhanced.subtreeSize - createProjection(enhanced.type, arg.projectionKind, typeParameterDescriptor = typeConstructor.parameters[localArgIndex]) + is SimpleType -> enhanceInflexible(qualifiers, index, TypeComponentPosition.INFLEXIBLE) } } - val (enhancedNullability, enhancedNullabilityAnnotations) = this.getEnhancedNullability(effectiveQualifiers, position) - wereChanges = wereChanges || enhancedNullabilityAnnotations != null + private fun SimpleType.enhanceInflexible( + qualifiers: (Int) -> JavaTypeQualifiers, + index: Int, + position: TypeComponentPosition + ): SimpleResult { + val shouldEnhance = position.shouldEnhance() + if (!shouldEnhance && arguments.isEmpty()) return SimpleResult(this, 1, false) - val subtreeSize = globalArgIndex - index - if (!wereChanges) return SimpleResult(this, subtreeSize, wereChanges = false) + val originalClass = constructor.declarationDescriptor + ?: return SimpleResult(this, 1, false) - val newAnnotations = listOfNotNull( - annotations, - enhancedMutabilityAnnotations, - enhancedNullabilityAnnotations - ).compositeAnnotationsOrSingle() + val effectiveQualifiers = qualifiers(index) + val (enhancedClassifier, enhancedMutabilityAnnotations) = originalClass.enhanceMutability(effectiveQualifiers, position) - val enhancedType = KotlinTypeFactory.simpleType( - newAnnotations, - typeConstructor, - enhancedArguments, - enhancedNullability - ) + val typeConstructor = enhancedClassifier.typeConstructor - val enhancement = if (effectiveQualifiers.isNotNullTypeParameter) NotNullTypeParameter(enhancedType) else enhancedType - val nullabilityForWarning = enhancedNullabilityAnnotations != null && effectiveQualifiers.isNullabilityQualifierForWarning - val result = if (nullabilityForWarning) wrapEnhancement(enhancement) else enhancement + var globalArgIndex = index + 1 + var wereChanges = enhancedMutabilityAnnotations != null + val enhancedArguments = arguments.mapIndexed { localArgIndex, arg -> + if (arg.isStarProjection) { + globalArgIndex++ + TypeUtils.makeStarProjection(enhancedClassifier.typeConstructor.parameters[localArgIndex]) + } else { + val enhanced = arg.type.unwrap().enhancePossiblyFlexible(qualifiers, globalArgIndex) + wereChanges = wereChanges || enhanced.wereChanges + globalArgIndex += enhanced.subtreeSize + createProjection(enhanced.type, arg.projectionKind, typeParameterDescriptor = typeConstructor.parameters[localArgIndex]) + } + } - return SimpleResult(result as SimpleType, subtreeSize, wereChanges = true) + val (enhancedNullability, enhancedNullabilityAnnotations) = this.getEnhancedNullability(effectiveQualifiers, position) + wereChanges = wereChanges || enhancedNullabilityAnnotations != null + + val subtreeSize = globalArgIndex - index + if (!wereChanges) return SimpleResult(this, subtreeSize, wereChanges = false) + + val newAnnotations = listOfNotNull( + annotations, + enhancedMutabilityAnnotations, + enhancedNullabilityAnnotations + ).compositeAnnotationsOrSingle() + + val enhancedType = KotlinTypeFactory.simpleType( + newAnnotations, + typeConstructor, + enhancedArguments, + enhancedNullability + ) + + val enhancement = if (effectiveQualifiers.isNotNullTypeParameter) NotNullTypeParameter(enhancedType) else enhancedType + val nullabilityForWarning = enhancedNullabilityAnnotations != null && effectiveQualifiers.isNullabilityQualifierForWarning + val result = if (nullabilityForWarning) wrapEnhancement(enhancement) else enhancement + + return SimpleResult(result as SimpleType, subtreeSize, wereChanges = true) + } } private fun List.compositeAnnotationsOrSingle() = when (size) {